Start processing template-ids as types when the template-name refers
to a class template. For example, the template-id 'vector<int>' now
has a nice, sugary type in the type system. What we can do now:
- Parse template-ids like 'vector<int>' (where 'vector' names a
class template) and form proper types for them in the type system.
- Parse icky template-ids like 'A<5>' and 'A<(5 > 0)>' properly,
using (sadly) a bool in the parser to tell it whether '>' should
be treated as an operator or not.
This is a baby-step, with major problems and limitations:
- There are currently two ways that we handle template arguments
(whether they are types or expressions). These will be merged, and,
most likely, TemplateArg will disappear.
- We don't have any notion of the declaration of class template
specializations or of template instantiations, so all template-ids
are fancy names for 'int' :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64153 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a87a902..72aef42 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1220,6 +1220,34 @@
return QualType(TypeParm, 0);
}
+QualType
+ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
+ unsigned NumArgs,
+ uintptr_t *Args, bool *ArgIsType,
+ QualType Canon) {
+ llvm::FoldingSetNodeID ID;
+ ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args,
+ ArgIsType);
+ void *InsertPos = 0;
+ ClassTemplateSpecializationType *Spec
+ = ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (Spec)
+ return QualType(Spec, 0);
+
+ void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) +
+ (sizeof(uintptr_t) *
+ (ClassTemplateSpecializationType::
+ getNumPackedWords(NumArgs) +
+ NumArgs)), 8);
+ Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args,
+ ArgIsType, Canon);
+ Types.push_back(Spec);
+ ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
+
+ return QualType(Spec, 0);
+}
+
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index d005ca3..ab5a3bc 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
@@ -43,6 +44,11 @@
NumParams, RAngleLoc);
}
+void TemplateArg::Destroy(ASTContext &C) {
+ if (Kind == ExprArg)
+ getAsExpr()->Destroy(C);
+}
+
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 106d0eb..6ec5062 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -489,6 +489,14 @@
return dyn_cast<TemplateTypeParmType>(CanonicalType);
}
+const ClassTemplateSpecializationType *
+Type::getClassTemplateSpecializationType() const {
+ // There is no sugar for class template specialization types, so
+ // just return the canonical type pointer if it is the right class.
+ return dyn_cast<ClassTemplateSpecializationType>(CanonicalType);
+}
+
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
@@ -882,6 +890,54 @@
return isa<EnumDecl>(TT->getDecl());
}
+void
+ClassTemplateSpecializationType::
+packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
+ const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+
+ for (unsigned PW = 0, NumPackedWords = getNumPackedWords(NumArgs), Arg = 0;
+ PW != NumPackedWords; ++PW) {
+ uintptr_t Word = 0;
+ for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) {
+ Word <<= 1;
+ Word |= Values[Arg];
+ }
+ Words[PW] = Word;
+ }
+}
+
+ClassTemplateSpecializationType::
+ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
+ uintptr_t *Args, bool *ArgIsType,
+ QualType Canon)
+ : Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false),
+ Template(T), NumArgs(NumArgs)
+{
+ uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
+
+ // Pack the argument-is-type values into the words just after the
+ // class template specialization type.
+ packBooleanValues(NumArgs, ArgIsType, Data);
+
+ // Copy the template arguments after the packed words.
+ Data += getNumPackedWords(NumArgs);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ Data[Arg] = Args[Arg];
+}
+
+uintptr_t
+ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
+ const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+ Data += getNumPackedWords(NumArgs);
+ return Data[Arg];
+}
+
+bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
+ const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+ const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+ Data += Arg / BitsPerWord;
+ return (*Data >> (Arg % BitsPerWord)) & 0x01;
+}
//===----------------------------------------------------------------------===//
// Type Printing
@@ -1146,6 +1202,47 @@
InnerString = Name->getName() + InnerString;
}
+void
+ClassTemplateSpecializationType::
+getAsStringInternal(std::string &InnerString) const {
+ std::string SpecString = Template->getNameAsString();
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ if (isArgType(Arg))
+ getArgAsType(Arg).getAsStringInternal(ArgString);
+ else {
+ llvm::raw_string_ostream s(ArgString);
+ getArgAsExpr(Arg)->printPretty(s);
+ }
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ if (InnerString.empty())
+ InnerString.swap(SpecString);
+ else
+ InnerString = SpecString + ' ' + InnerString;
+}
+
void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const {
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
InnerString = ' ' + InnerString;
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 57598d3..90bc67a 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Bitcode/Serialize.h"
@@ -377,6 +378,48 @@
}
//===----------------------------------------------------------------------===//
+// ClassTemplateSpecializationType
+//===----------------------------------------------------------------------===//
+
+void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const {
+ S.Emit(getCanonicalTypeInternal());
+ S.EmitPtr(Template);
+ S.EmitInt(NumArgs);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ S.EmitBool(isArgType(Arg));
+ if (isArgType(Arg))
+ S.Emit(getArgAsType(Arg));
+ else
+ S.EmitOwnedPtr(getArgAsExpr(Arg));
+ }
+}
+
+Type*
+ClassTemplateSpecializationType::
+CreateImpl(ASTContext& Context, Deserializer& D) {
+ llvm::SmallVector<uintptr_t, 16> Args;
+ llvm::SmallVector<bool, 16> ArgIsType;
+
+ QualType Canon = QualType::ReadVal(D);
+ TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
+ unsigned NumArgs = D.ReadInt();
+
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ bool IsType = D.ReadBool();
+ ArgIsType.push_back(IsType);
+ if (IsType)
+ Args.push_back(
+ reinterpret_cast<uintptr_t>(QualType::ReadVal(D).getAsOpaquePtr()));
+ else
+ Args.push_back(reinterpret_cast<uintptr_t>(D.ReadOwnedPtr<Expr>(Context)));
+ }
+
+ return Context.getClassTemplateSpecializationType(Template, NumArgs,
+ &Args[0], &ArgIsType[0],
+ Canon).getTypePtr();
+}
+
+//===----------------------------------------------------------------------===//
// VariableArrayType
//===----------------------------------------------------------------------===//
diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp
index 0b74e1e..37b7c5f 100644
--- a/lib/CodeGen/CodeGenTypes.cpp
+++ b/lib/CodeGen/CodeGenTypes.cpp
@@ -176,6 +176,7 @@
switch (Ty.getTypeClass()) {
case Type::TypeName: // typedef isn't canonical.
case Type::TemplateTypeParm:// template type parameters never generated
+ case Type::ClassTemplateSpecialization: // these types are always sugar
case Type::DependentSizedArray: // dependent types are never generated
case Type::TypeOfExp: // typeof isn't canonical.
case Type::TypeOfTyp: // typeof isn't canonical.
diff --git a/lib/Parse/MinimalAction.cpp b/lib/Parse/MinimalAction.cpp
index 2d6c9a6..ce15cf9 100644
--- a/lib/Parse/MinimalAction.cpp
+++ b/lib/Parse/MinimalAction.cpp
@@ -95,14 +95,11 @@
return false;
}
- /// isTemplateName - Determines whether the identifier II is a
- /// template name in the current scope, and returns the template
- /// declaration if II names a template. An optional CXXScope can be
- /// passed to indicate the C++ scope in which the identifier will be
- /// found.
-Action::DeclTy *MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
- const CXXScopeSpec *SS ) {
- return 0;
+Action::TemplateNameKind
+MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S,
+ DeclTy *&TemplateDecl,
+ const CXXScopeSpec *SS) {
+ return TNK_Non_template;
}
/// ActOnDeclarator - If this is a typedef declarator, we modify the
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 73a09ee..5d601bc 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -499,6 +499,7 @@
Token Next = NextToken();
TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(),
Next.getLocation(), CurScope, &SS);
+
if (TypeRep == 0)
goto DoneWithDeclSpec;
@@ -553,9 +554,23 @@
// It has to be available as a typedef too!
TypeTy *TypeRep = Actions.getTypeName(*Tok.getIdentifierInfo(),
Tok.getLocation(), CurScope);
+
+ if (TypeRep == 0 && getLang().CPlusPlus && NextToken().is(tok::less)) {
+ // If we have a template name, annotate the token and try again.
+ DeclTy *Template = 0;
+ if (TemplateNameKind TNK =
+ Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope,
+ Template)) {
+ AnnotateTemplateIdToken(Template, TNK, 0);
+ continue;
+ }
+ }
+
if (TypeRep == 0)
goto DoneWithDeclSpec;
+
+
// C++: If the identifier is actually the name of the class type
// being defined and the next token is a '(', then this is a
// constructor declaration. We're done with the decl-specifiers
@@ -1752,11 +1767,12 @@
// If this identifier is followed by a '<', we may have a template-id.
DeclTy *Template;
+ Action::TemplateNameKind TNK;
if (getLang().CPlusPlus && NextToken().is(tok::less) &&
- (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(),
- CurScope))) {
+ (TNK = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template))) {
IdentifierInfo *II = Tok.getIdentifierInfo();
- AnnotateTemplateIdToken(Template, 0);
+ AnnotateTemplateIdToken(Template, TNK, 0);
// FIXME: Set the declarator to a template-id. How? I don't
// know... for now, just use the identifier.
D.SetIdentifier(II, Tok.getLocation());
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 332ad77..0f04d13 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -55,8 +55,17 @@
/// getBinOpPrecedence - Return the precedence of the specified binary operator
/// token. This returns:
///
-static prec::Level getBinOpPrecedence(tok::TokenKind Kind) {
+static prec::Level getBinOpPrecedence(tok::TokenKind Kind,
+ bool GreaterThanIsOperator) {
switch (Kind) {
+ case tok::greater:
+ // The '>' token can act as either an operator or as the ending
+ // token for a template argument list.
+ // FIXME: '>>' is similar, for error recovery and C++0x.
+ if (GreaterThanIsOperator)
+ return prec::Relational;
+ return prec::Unknown;
+
default: return prec::Unknown;
case tok::comma: return prec::Comma;
case tok::equal:
@@ -80,8 +89,7 @@
case tok::equalequal: return prec::Equality;
case tok::lessequal:
case tok::less:
- case tok::greaterequal:
- case tok::greater: return prec::Relational;
+ case tok::greaterequal: return prec::Relational;
case tok::lessless:
case tok::greatergreater: return prec::Shift;
case tok::plus:
@@ -266,7 +274,7 @@
/// LHS and has a precedence of at least MinPrec.
Parser::OwningExprResult
Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
- unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
+ unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
SourceLocation ColonLoc;
while (1) {
@@ -316,7 +324,7 @@
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
unsigned ThisPrec = NextTokPrec;
- NextTokPrec = getBinOpPrecedence(Tok.getKind());
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
// Assignment and conditional expressions are right-associative.
bool isRightAssoc = ThisPrec == prec::Conditional ||
@@ -335,7 +343,7 @@
if (RHS.isInvalid())
return move(RHS);
- NextTokPrec = getBinOpPrecedence(Tok.getKind());
+ NextTokPrec = getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator);
}
assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
@@ -1104,6 +1112,7 @@
Parser::ParseParenExpression(ParenParseOption &ExprType,
TypeTy *&CastTy, SourceLocation &RParenLoc) {
assert(Tok.is(tok::l_paren) && "Not a paren expr!");
+ MakeGreaterThanAnOperator G(GreaterThanIsOperator);
SourceLocation OpenLoc = ConsumeParen();
OwningExprResult Result(Actions, true);
CastTy = 0;
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 8836106..2e2cf53 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -15,6 +15,7 @@
#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
+#include "AstGuard.h"
using namespace clang;
@@ -354,7 +355,8 @@
/// AnnotateTemplateIdToken - The current token is an identifier that
/// refers to the template declaration Template, and is followed by a
/// '<'. Turn this template-id into a template-id annotation token.
-void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) {
+void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
+ const CXXScopeSpec *SS) {
assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
"Parser isn't at the beginning of a template-id");
@@ -366,13 +368,16 @@
SourceLocation LAngleLoc = ConsumeToken();
// Parse the optional template-argument-list.
- TemplateArgList TemplateArgs;
- if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) {
- // Try to find the closing '>'.
- SkipUntil(tok::greater, true, true);
-
- // FIXME: What's our recovery strategy for failed template-argument-lists?
- return;
+ ASTVector<&ActionBase::DeleteTemplateArg, 8> TemplateArgs(Actions);
+ {
+ MakeGreaterThanTemplateArgumentListTerminator G(GreaterThanIsOperator);
+ if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, true);
+
+ // FIXME: What's our recovery strategy for failed template-argument-lists?
+ return;
+ }
}
if (Tok.isNot(tok::greater))
@@ -382,24 +387,41 @@
// token, because we'll be replacing it with the template-id.
SourceLocation RAngleLoc = Tok.getLocation();
- Tok.setKind(tok::annot_template_id);
+ // Build the annotation token.
+ if (TNK == Action::TNK_Function_template) {
+ // This is a function template. We'll be building a template-id
+ // annotation token.
+ TemplateArgs.take(); // Annotation token takes ownership
+ Tok.setKind(tok::annot_template_id);
+ TemplateIdAnnotation *TemplateId
+ = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
+ sizeof(TemplateArgTy*) * TemplateArgs.size());
+ TemplateId->TemplateNameLoc = TemplateNameLoc;
+ TemplateId->Template = Template;
+ TemplateId->LAngleLoc = LAngleLoc;
+ TemplateId->NumArgs = TemplateArgs.size();
+ TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1);
+ for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
+ Args[Arg] = TemplateArgs[Arg];
+ Tok.setAnnotationValue(TemplateId);
+ } else {
+ // This is a type template, e.g., a class template, template
+ // template parameter, or template alias. We'll be building a
+ // "typename" annotation token.
+ TypeTy *Ty
+ = Actions.ActOnClassTemplateSpecialization(Template,LAngleLoc,
+ move_arg(TemplateArgs),
+ RAngleLoc, SS);
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Ty);
+ }
+
+ // Common fields for the annotation token
Tok.setAnnotationEndLoc(RAngleLoc);
Tok.setLocation(TemplateNameLoc);
if (SS && SS->isNotEmpty())
Tok.setLocation(SS->getBeginLoc());
- TemplateIdAnnotation *TemplateId
- = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
- sizeof(TemplateArgTy*) * TemplateArgs.size());
- TemplateId->TemplateNameLoc = TemplateNameLoc;
- TemplateId->Template = Template;
- TemplateId->LAngleLoc = LAngleLoc;
- TemplateId->NumArgs = TemplateArgs.size();
- TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1);
- for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg)
- Args[Arg] = TemplateArgs[Arg];
- Tok.setAnnotationValue(TemplateId);
-
// In case the tokens were cached, have Preprocessor replace them with the
// annotation token.
PP.AnnotateCachedTokens(Tok);
@@ -412,8 +434,22 @@
/// type-id
/// id-expression
Parser::OwningTemplateArgResult Parser::ParseTemplateArgument() {
- // FIXME: Implement this!
- return TemplateArgError();
+ // C++ [temp.arg]p2:
+ // In a template-argument, an ambiguity between a type-id and an
+ // expression is resolved to a type-id, regardless of the form of
+ // the corresponding template-parameter.
+ //
+ // Therefore, we initially try to parse a type-id.
+ if (isTypeIdInParens()) {
+ TypeTy *TypeArg = ParseTypeName();
+ return Actions.ActOnTypeTemplateArgument(TypeArg);
+ }
+
+ OwningExprResult ExprArg = ParseExpression();
+ if (ExprArg.isInvalid())
+ return TemplateArgError();
+
+ return Actions.ActOnExprTemplateArgument(move(ExprArg));
}
/// ParseTemplateArgumentList - Parse a C++ template-argument-list
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index f28767a..7b09d21 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -20,7 +20,8 @@
using namespace clang;
Parser::Parser(Preprocessor &pp, Action &actions)
- : PP(pp), Actions(actions), Diags(PP.getDiagnostics()) {
+ : PP(pp), Actions(actions), Diags(PP.getDiagnostics()),
+ GreaterThanIsOperator(true) {
Tok.setKind(tok::eof);
CurScope = 0;
NumCachedScopes = 0;
@@ -785,10 +786,15 @@
}
// If this is a template-id, annotate the template-id token.
- if (NextToken().is(tok::less))
- if (DeclTy *Template =
- Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope, &SS))
- AnnotateTemplateIdToken(Template, &SS);
+ if (NextToken().is(tok::less)) {
+ DeclTy *Template;
+ if (TemplateNameKind TNK
+ = Actions.isTemplateName(*Tok.getIdentifierInfo(),
+ CurScope, Template, &SS)) {
+ AnnotateTemplateIdToken(Template, TNK, &SS);
+ return true;
+ }
+ }
// We either have an identifier that is not a type name or we have
// just created a template-id that might be a type name. Both
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index f0544eb..bba99fd 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -62,6 +62,7 @@
class TypedefDecl;
class TemplateDecl;
class TemplateParameterList;
+ class TemplateArg;
class ObjCInterfaceDecl;
class ObjCCompatibleAliasDecl;
class ObjCProtocolDecl;
@@ -258,6 +259,9 @@
return OwningExprResult(*this, R.get());
}
OwningStmtResult Owned(Stmt* S) { return OwningStmtResult(*this, S); }
+ OwningTemplateArgResult Owned(TemplateArg *Arg) {
+ return OwningTemplateArgResult(*this, Arg);
+ }
virtual void ActOnEndOfTranslationUnit();
@@ -1478,8 +1482,9 @@
//===--------------------------------------------------------------------===//
// C++ Templates [C++ 14]
//
- virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S,
- const CXXScopeSpec *SS = 0);
+ virtual TemplateNameKind isTemplateName(IdentifierInfo &II, Scope *S,
+ DeclTy *&TemplateDecl,
+ const CXXScopeSpec *SS = 0);
bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
TemplateDecl *AdjustDeclIfTemplate(DeclTy *&Decl);
@@ -1506,6 +1511,10 @@
DeclTy **Params, unsigned NumParams,
SourceLocation RAngleLoc);
+ virtual OwningTemplateArgResult ActOnTypeTemplateArgument(TypeTy *Type);
+
+ virtual OwningTemplateArgResult ActOnExprTemplateArgument(ExprArg Value);
+
virtual DeclTy *
ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -1513,6 +1522,13 @@
AttributeList *Attr,
MultiTemplateParamsArg TemplateParameterLists);
+ virtual TypeTy *
+ ActOnClassTemplateSpecialization(DeclTy *Template,
+ SourceLocation LAngleLoc,
+ MultiTemplateArgsArg TemplateArgs,
+ SourceLocation RAngleLoc,
+ const CXXScopeSpec *SS = 0);
+
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,
bool Complain,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 6c5f90a..6b6a501 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -25,38 +25,43 @@
/// declaration if II names a template. An optional CXXScope can be
/// passed to indicate the C++ scope in which the identifier will be
/// found.
-Sema::DeclTy *Sema::isTemplateName(IdentifierInfo &II, Scope *S,
- const CXXScopeSpec *SS) {
- DeclContext *DC = 0;
-
- if (SS) {
- if (SS->isInvalid())
- return 0;
- DC = static_cast<DeclContext*>(SS->getScopeRep());
- }
+Sema::TemplateNameKind Sema::isTemplateName(IdentifierInfo &II, Scope *S,
+ DeclTy *&Template,
+ const CXXScopeSpec *SS) {
NamedDecl *IIDecl = LookupParsedName(S, SS, &II, LookupOrdinaryName);
if (IIDecl) {
- // FIXME: We need to represent templates via some kind of
- // TemplateDecl, because what follows is a hack that only works in
- // one specific case.
- if (isa<TemplateDecl>(IIDecl))
- return IIDecl;
+ if (isa<TemplateDecl>(IIDecl)) {
+ Template = IIDecl;
+ if (isa<FunctionTemplateDecl>(IIDecl))
+ return TNK_Function_template;
+ else if (isa<ClassTemplateDecl>(IIDecl))
+ return TNK_Class_template;
+ else if (isa<TemplateTemplateParmDecl>(IIDecl))
+ return TNK_Template_template_parm;
+ else
+ assert(false && "Unknown TemplateDecl");
+ }
+ // FIXME: What follows is a gross hack.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) {
- if (FD->getType()->isDependentType())
- return FD;
+ if (FD->getType()->isDependentType()) {
+ Template = FD;
+ return TNK_Function_template;
+ }
} else if (OverloadedFunctionDecl *Ovl
= dyn_cast<OverloadedFunctionDecl>(IIDecl)) {
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
- if ((*F)->getType()->isDependentType())
- return Ovl;
+ if ((*F)->getType()->isDependentType()) {
+ Template = Ovl;
+ return TNK_Function_template;
+ }
}
}
}
- return 0;
+ return TNK_Non_template;
}
/// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining
@@ -226,6 +231,15 @@
(Decl**)Params, NumParams, RAngleLoc);
}
+Sema::OwningTemplateArgResult Sema::ActOnTypeTemplateArgument(TypeTy *Type) {
+ return Owned(new (Context) TemplateArg(QualType::getFromOpaquePtr(Type)));
+}
+
+Sema::OwningTemplateArgResult
+Sema::ActOnExprTemplateArgument(ExprArg Value) {
+ return Owned(new (Context) TemplateArg(static_cast<Expr *>(Value.release())));
+}
+
Sema::DeclTy *
Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc, const CXXScopeSpec &SS,
@@ -351,6 +365,42 @@
return NewTemplate;
}
+Action::TypeTy *
+Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
+ SourceLocation LAngleLoc,
+ MultiTemplateArgsArg TemplateArgsIn,
+ SourceLocation RAngleLoc,
+ const CXXScopeSpec *SS) {
+ TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
+
+ // FIXME: Not happy about this. We should teach the parser to pass
+ // us opaque pointers + bools for template argument lists.
+ // FIXME: Also not happy about the fact that we leak these
+ // TemplateArg structures. Fixing the above will fix this, too.
+ llvm::SmallVector<uintptr_t, 16> Args;
+ llvm::SmallVector<bool, 16> ArgIsType;
+ unsigned NumArgs = TemplateArgsIn.size();
+ TemplateArg **TemplateArgs
+ = reinterpret_cast<TemplateArg **>(TemplateArgsIn.release());
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Expr *ExprArg = TemplateArgs[Arg]->getAsExpr()) {
+ Args.push_back(reinterpret_cast<uintptr_t>(ExprArg));
+ ArgIsType.push_back(false);
+ } else {
+ QualType T = TemplateArgs[Arg]->getAsType();
+ Args.push_back(reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()));
+ ArgIsType.push_back(true);
+ }
+ }
+
+ // Yes, all class template specializations are just silly sugar for
+ // 'int'. Gotta problem wit dat?
+ return Context.getClassTemplateSpecializationType(Template, NumArgs,
+ &Args[0], &ArgIsType[0],
+ Context.IntTy)
+ .getAsOpaquePtr();
+}
+
/// \brief Determine whether the given template parameter lists are
/// equivalent.
///