aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/DeclBase.h7
-rw-r--r--include/clang/AST/DeclNodes.def2
-rw-r--r--include/clang/AST/DeclTemplate.h38
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.def2
-rw-r--r--include/clang/Parse/Action.h83
-rw-r--r--include/clang/Parse/DeclSpec.h4
-rw-r--r--include/clang/Parse/Ownership.h24
-rw-r--r--include/clang/Parse/Parser.h13
-rw-r--r--lib/AST/DeclBase.cpp51
-rw-r--r--lib/AST/DeclTemplate.cpp14
-rw-r--r--lib/Parse/ParseDecl.cpp4
-rw-r--r--lib/Parse/ParseDeclCXX.cpp74
-rw-r--r--lib/Parse/ParseTemplate.cpp153
-rw-r--r--lib/Sema/Sema.h20
-rw-r--r--lib/Sema/SemaTemplate.cpp158
-rw-r--r--test/SemaTemplate/class-template-spec.cpp31
16 files changed, 555 insertions, 123 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h
index 99228d7ac9..ca4f333431 100644
--- a/include/clang/AST/DeclBase.h
+++ b/include/clang/AST/DeclBase.h
@@ -202,7 +202,7 @@ public:
bool isImplicit() const { return Implicit; }
void setImplicit(bool I = true) { Implicit = I; }
- IdentifierNamespace getIdentifierNamespace() const {
+ unsigned getIdentifierNamespace() const {
switch (DeclKind) {
default:
if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast)
@@ -245,7 +245,10 @@ public:
case FunctionTemplate:
case ClassTemplate:
case TemplateTemplateParm:
- return IdentifierNamespace(IDNS_Tag | IDNS_Ordinary);
+ return IDNS_Tag | IDNS_Ordinary;
+
+ case ClassTemplateSpecialization:
+ return 0;
}
}
diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def
index 984b21e10b..01e894c946 100644
--- a/include/clang/AST/DeclNodes.def
+++ b/include/clang/AST/DeclNodes.def
@@ -139,7 +139,7 @@ DECL_RANGE(Named, OverloadedFunction, ObjCCompatibleAlias)
DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
DECL_RANGE(Field, Field, ObjCAtDefsField)
DECL_RANGE(Type, Typedef, TemplateTypeParm)
-DECL_RANGE(Tag, Enum, CXXRecord)
+DECL_RANGE(Tag, Enum, ClassTemplateSpecialization)
DECL_RANGE(Record, Record, ClassTemplateSpecialization)
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
DECL_RANGE(Function, Function, CXXConversion)
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index d9ce70ba49..a075d74e61 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -521,6 +521,23 @@ public:
}
};
+// \brief Describes the kind of template specialization that a
+// particular template specialization declaration represents.
+enum TemplateSpecializationKind {
+ /// This template specialization was formed from a template-id but
+ /// has not yet been declared, defined, or instantiated.
+ TSK_Undeclared = 0,
+ /// This template specialization was declared or defined by an
+ /// explicit specialization (C++ [temp.expl.spec]).
+ TSK_ExplicitSpecialization,
+ /// This template specialization was implicitly instantiated from a
+ /// template. (C++ [temp.inst]).
+ TSK_ImplicitInstantiation,
+ /// This template specialization was instantiated from a template
+ /// due to an explicit instantiation request (C++ [temp.explicit]).
+ TSK_ExplicitInstantiation
+};
+
/// \brief Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///
@@ -541,8 +558,12 @@ class ClassTemplateSpecializationDecl
/// \brief The number of template arguments. The actual arguments
/// are allocated after the ClassTemplateSpecializationDecl object.
- unsigned NumTemplateArgs;
-
+ unsigned NumTemplateArgs : 16;
+
+ /// \brief The kind of specialization this declaration refers to.
+ /// Really a value of type TemplateSpecializationKind.
+ unsigned SpecializationKind : 2;
+
ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
@@ -552,7 +573,8 @@ public:
static ClassTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
- TemplateArgument *TemplateArgs, unsigned NumTemplateArgs);
+ TemplateArgument *TemplateArgs, unsigned NumTemplateArgs,
+ ClassTemplateSpecializationDecl *PrevDecl);
/// \brief Retrieve the template that this specialization specializes.
ClassTemplateDecl *getSpecializedTemplate() const {
@@ -570,6 +592,16 @@ public:
unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
+ /// \brief Determine the kind of specialization that this
+ /// declaration represents.
+ TemplateSpecializationKind getSpecializationKind() const {
+ return static_cast<TemplateSpecializationKind>(SpecializationKind);
+ }
+
+ void setSpecializationKind(TemplateSpecializationKind TSK) {
+ SpecializationKind = TSK;
+ }
+
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, template_arg_begin(), getNumTemplateArgs());
}
diff --git a/include/clang/Basic/DiagnosticParseKinds.def b/include/clang/Basic/DiagnosticParseKinds.def
index a1bfa4a72f..5134a28185 100644
--- a/include/clang/Basic/DiagnosticParseKinds.def
+++ b/include/clang/Basic/DiagnosticParseKinds.def
@@ -274,6 +274,8 @@ DIAG(err_expected_type_id_after, ERROR,
"expected type-id after '%0'")
DIAG(err_expected_class_before, ERROR,
"expected 'class' before '%0'")
+DIAG(err_template_spec_syntax_non_template, ERROR,
+ "identifier followed by '<' indicates a class template specialization but %0 %select{does not refer to a template|refers to a function template|<unused>|refers to a template template parameter}1")
// Language specific pragmas
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index 9452983550..d657780dbf 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -138,7 +138,7 @@ public:
/// isTemplateName.
enum TemplateNameKind {
/// The name does not refer to a template.
- TNK_Non_template,
+ TNK_Non_template = 0,
/// The name refers to a function template or a set of overloaded
/// functions that includes at least one function template.
TNK_Function_template,
@@ -1143,23 +1143,86 @@ public:
/// \brief Form a class template specialization from a template and
/// a list of template arguments.
///
+ /// This action merely forms the type for the template-id, possibly
+ /// checking well-formedness of the template arguments. It does not
+ /// imply the declaration of any entity.
+ ///
/// \param Template A template whose specialization results in a
/// type, e.g., a class template or template template parameter.
+ ///
+ /// \param IsSpecialization true when we are naming the class
+ /// template specialization as part of an explicit class
+ /// specialization or class template partial specialization.
+ virtual TypeResult ActOnClassTemplateId(DeclTy *Template,
+ SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgs,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ const CXXScopeSpec *SS) {
+ return 0;
+ };
+
+ /// \brief Process the declaration or definition of an explicit
+ /// class template specialization or a class template partial
+ /// specialization.
+ ///
+ /// This routine is invoked when an explicit class template
+ /// specialization or a class template partial specialization is
+ /// declared or defined, to introduce the (partial) specialization
+ /// and produce a declaration for it. In the following example,
+ /// ActOnClassTemplateSpecialization will be invoked for the
+ /// declarations at both A and B:
+ ///
+ /// \code
+ /// template<typename T> class X;
+ /// template<> class X<int> { }; // A: explicit specialization
+ /// template<typename T> class X<T*> { }; // B: partial specialization
+ /// \endcode
+ ///
+ /// Note that it is the job of semantic analysis to determine which
+ /// of the two cases actually occurred in the source code, since
+ /// they are parsed through the same path. The formulation of the
+ /// template parameter lists describes which case we are in.
+ ///
+ /// \param S the current scope
///
- /// \todo "Class template specialization" is the standard term for
- /// the types that we're forming, but the name
- /// ActOnClassTemplateSpecialization sounds like we're declaring a
- /// new class template specialization.
- virtual TypeTy *
- ActOnClassTemplateSpecialization(DeclTy *Template,
- SourceLocation TemplateLoc,
+ /// \param TagSpec whether this declares a class, struct, or union
+ /// (template)
+ ///
+ /// \param TK whether this is a declaration or a definition
+ ///
+ /// \param KWLoc the location of the 'class', 'struct', or 'union'
+ /// keyword.
+ ///
+ /// \param SS the scope specifier preceding the template-id
+ ///
+ /// \param Template the declaration of the class template that we
+ /// are specializing.
+ ///
+ /// \param Attr attributes on the specialization
+ ///
+ /// \param TemplateParameterLists the set of template parameter
+ /// lists that apply to this declaration. In a well-formed program,
+ /// the number of template parameter lists will be one more than the
+ /// number of template-ids in the scope specifier. However, it is
+ /// common for users to provide the wrong number of template
+ /// parameter lists (such as a missing \c template<> prior to a
+ /// specialization); the parser does not check this condition.
+ virtual DeclTy *
+ ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
+ SourceLocation KWLoc,
+ const CXXScopeSpec &SS,
+ DeclTy *Template,
+ SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
- const CXXScopeSpec *SS = 0) {
+ AttributeList *Attr,
+ MultiTemplateParamsArg TemplateParameterLists) {
return 0;
- };
+ }
//===----------------------- Obj-C Declarations -------------------------===//
diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h
index 008c161ac8..4879f00be7 100644
--- a/include/clang/Parse/DeclSpec.h
+++ b/include/clang/Parse/DeclSpec.h
@@ -995,7 +995,9 @@ public:
OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; }
void setInvalidType(bool flag) { InvalidType = flag; }
- bool getInvalidType() const { return InvalidType; }
+ bool getInvalidType() const {
+ return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
+ }
void setGroupingParens(bool flag) { GroupingParens = flag; }
bool hasGroupingParens() const { return GroupingParens; }
diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h
index cae8815ab0..684203d6d1 100644
--- a/include/clang/Parse/Ownership.h
+++ b/include/clang/Parse/Ownership.h
@@ -571,6 +571,20 @@ namespace clang
#endif
}
+ // FIXME: Lame, not-fully-type-safe emulation of 'move semantics'.
+ ASTTemplateArgsPtr& operator=(ASTTemplateArgsPtr &Other) {
+#if !defined(DISABLE_SMART_POINTERS)
+ Actions = Other.Actions;
+#endif
+ Args = Other.Args;
+ ArgIsType = Other.ArgIsType;
+ Count = Other.Count;
+#if !defined(DISABLE_SMART_POINTERS)
+ Other.Count = 0;
+#endif
+ return *this;
+ }
+
#if !defined(DISABLE_SMART_POINTERS)
~ASTTemplateArgsPtr() { destroy(); }
#endif
@@ -579,6 +593,16 @@ namespace clang
bool *getArgIsType() const {return ArgIsType; }
unsigned size() const { return Count; }
+ void reset(void **args, bool *argIsType, unsigned count) {
+ destroy();
+
+ Args = args;
+ ArgIsType = argIsType;
+ Count = count;
+ }
+
+ void *operator[](unsigned Arg) const { return Args[Arg]; }
+
void **release() const {
#if !defined(DISABLE_SMART_POINTERS)
Count = 0;
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index ab43c516cd..4c51e0508a 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -996,7 +996,7 @@ private:
typedef Action::TemplateNameKind TemplateNameKind;
// C++ 14.1: Template Parameters [temp.param]
- DeclTy *ParseTemplateDeclaration(unsigned Context);
+ DeclTy *ParseTemplateDeclarationOrSpecialization(unsigned Context);
bool ParseTemplateParameters(unsigned Depth,
TemplateParameterList &TemplateParams,
SourceLocation &LAngleLoc,
@@ -1011,6 +1011,17 @@ private:
typedef llvm::SmallVector<void *, 16> TemplateArgList;
typedef llvm::SmallVector<bool, 16> TemplateArgIsTypeList;
typedef llvm::SmallVector<SourceLocation, 16> TemplateArgLocationList;
+
+ bool ParseTemplateIdAfterTemplateName(DeclTy *Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec *SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations,
+ SourceLocation &RAngleLoc);
+
void AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
const CXXScopeSpec *SS = 0);
bool ParseTemplateArgumentList(TemplateArgList &TemplateArgs,
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 826b4b0ba1..db29a8e3c6 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -319,17 +319,6 @@ DeclContext *DeclContext::getPrimaryContext() {
// The original namespace is our primary context.
return static_cast<NamespaceDecl*>(this)->getOriginalNamespace();
- case Decl::Enum:
- case Decl::Record:
- case Decl::CXXRecord:
- // If this is a tag type that has a definition or is currently
- // being defined, that definition is our primary context.
- if (TagType *TagT = cast_or_null<TagType>(cast<TagDecl>(this)->TypeForDecl))
- if (TagT->isBeingDefined() ||
- (TagT->getDecl() && TagT->getDecl()->isDefinition()))
- return TagT->getDecl();
- return this;
-
case Decl::ObjCMethod:
return this;
@@ -344,6 +333,17 @@ DeclContext *DeclContext::getPrimaryContext() {
return this;
default:
+ if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) {
+ // If this is a tag type that has a definition or is currently
+ // being defined, that definition is our primary context.
+ if (TagType *TagT
+ = cast_or_null<TagType>(cast<TagDecl>(this)->TypeForDecl))
+ if (TagT->isBeingDefined() ||
+ (TagT->getDecl() && TagT->getDecl()->isDefinition()))
+ return TagT->getDecl();
+ return this;
+ }
+
assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast &&
"Unknown DeclContext kind");
return this;
@@ -352,28 +352,11 @@ DeclContext *DeclContext::getPrimaryContext() {
DeclContext *DeclContext::getNextContext() {
switch (DeclKind) {
- case Decl::TranslationUnit:
- case Decl::Enum:
- case Decl::Record:
- case Decl::CXXRecord:
- case Decl::ObjCMethod:
- case Decl::ObjCInterface:
- case Decl::ObjCCategory:
- case Decl::ObjCProtocol:
- case Decl::ObjCImplementation:
- case Decl::ObjCCategoryImpl:
- case Decl::LinkageSpec:
- case Decl::Block:
- // There is only one DeclContext for these entities.
- return 0;
-
case Decl::Namespace:
// Return the next namespace
return static_cast<NamespaceDecl*>(this)->getNextNamespace();
default:
- assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast &&
- "Unknown DeclContext kind");
return 0;
}
}
@@ -463,6 +446,12 @@ const DeclContext *DeclContext::getLookupContext() const {
}
void DeclContext::makeDeclVisibleInContext(NamedDecl *D) {
+ // FIXME: This feels like a hack. Should DeclarationName support
+ // template-ids, or is there a better way to keep specializations
+ // from being visible?
+ if (isa<ClassTemplateSpecializationDecl>(D))
+ return;
+
DeclContext *PrimaryContext = getPrimaryContext();
if (PrimaryContext != this) {
PrimaryContext->makeDeclVisibleInContext(D);
@@ -486,6 +475,12 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) {
if (!D->getDeclName())
return;
+ // FIXME: This feels like a hack. Should DeclarationName support
+ // template-ids, or is there a better way to keep specializations
+ // from being visible?
+ if (isa<ClassTemplateSpecializationDecl>(D))
+ return;
+
bool MayBeRedeclaration = true;
if (!isLookupMap()) {
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 81ef3ab70e..e10e270c7d 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -159,7 +159,7 @@ ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
// class template specializations?
SpecializedTemplate->getIdentifier()),
SpecializedTemplate(SpecializedTemplate),
- NumTemplateArgs(NumTemplateArgs) {
+ NumTemplateArgs(NumTemplateArgs), SpecializationKind(TSK_Undeclared) {
TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg)
*Arg = TemplateArgs[ArgIdx];
@@ -170,12 +170,16 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
- unsigned NumTemplateArgs) {
+ unsigned NumTemplateArgs,
+ ClassTemplateSpecializationDecl *PrevDecl) {
unsigned Size = sizeof(ClassTemplateSpecializationDecl) +
sizeof(TemplateArgument) * NumTemplateArgs;
unsigned Align = llvm::AlignOf<ClassTemplateSpecializationDecl>::Alignment;
void *Mem = Context.Allocate(Size, Align);
- return new (Mem) ClassTemplateSpecializationDecl(DC, L, SpecializedTemplate,
- TemplateArgs,
- NumTemplateArgs);
+ ClassTemplateSpecializationDecl *Result
+ = new (Mem) ClassTemplateSpecializationDecl(DC, L, SpecializedTemplate,
+ TemplateArgs, NumTemplateArgs);
+ // FIXME: Do we want a prettier type here?
+ Context.getTypeDeclType(Result, PrevDecl);
+ return Result;
}
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 5d601bc4f1..953b552562 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -228,7 +228,7 @@ Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) {
switch (Tok.getKind()) {
case tok::kw_export:
case tok::kw_template:
- return ParseTemplateDeclaration(Context);
+ return ParseTemplateDeclarationOrSpecialization(Context);
case tok::kw_namespace:
return ParseNamespace(Context);
case tok::kw_using:
@@ -2095,7 +2095,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D,
DS.AddAttributes(AttrList);
AttrList = 0; // Only apply the attributes to the first parameter.
}
- ParseDeclarationSpecifiers(DS);
+ ParseDeclarationSpecifiers(DS);
// Parse the declarator. This is "PrototypeContext", because we must
// accept either 'declarator' or 'abstract-declarator' here.
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index d6b83f3fb2..e36bc40bac 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -310,17 +310,69 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
// Parse the (optional) nested-name-specifier.
CXXScopeSpec SS;
if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) {
+ // FIXME: can we get a class template specialization or
+ // template-id token here?
if (Tok.isNot(tok::identifier))
Diag(Tok, diag::err_expected_ident);
}
- // Parse the (optional) class name.
- // FIXME: Alternatively, parse a simple-template-id.
+
+ // These variables encode the simple-template-id that we might end
+ // up parsing below. We don't translate this into a type
+ // automatically because (1) we want to create a separate
+ // declaration for each specialization, and (2) we want to retain
+ // more information about source locations that types provide.
+ DeclTy *Template = 0;
+ SourceLocation LAngleLoc, RAngleLoc;
+ TemplateArgList TemplateArgs;
+ TemplateArgIsTypeList TemplateArgIsType;
+ TemplateArgLocationList TemplateArgLocations;
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0);
+
+
+ // Parse the (optional) class name or simple-template-id.
IdentifierInfo *Name = 0;
SourceLocation NameLoc;
if (Tok.is(tok::identifier)) {
Name = Tok.getIdentifierInfo();
NameLoc = ConsumeToken();
+
+ if (Tok.is(tok::less)) {
+ // This is a simple-template-id.
+ Action::TemplateNameKind TNK
+ = Actions.isTemplateName(*Name, CurScope, Template, &SS);
+
+ bool Invalid = false;
+
+ // Parse the enclosed template argument list.
+ if (TNK != Action::TNK_Non_template)
+ Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc,
+ &SS, true, LAngleLoc,
+ TemplateArgs,
+ TemplateArgIsType,
+ TemplateArgLocations,
+ RAngleLoc);
+
+ TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0],
+ TemplateArgs.size());
+
+ if (TNK != Action::TNK_Class_template) {
+ // The template-name in the simple-template-id refers to
+ // something other than a class template. Give an appropriate
+ // error message and skip to the ';'.
+ SourceRange Range(NameLoc);
+ if (SS.isNotEmpty())
+ Range.setBegin(SS.getBeginLoc());
+ else if (!Invalid)
+
+ Diag(LAngleLoc, diag::err_template_spec_syntax_non_template)
+ << Name << static_cast<int>(TNK) << Range;
+
+ DS.SetTypeSpecError();
+ SkipUntil(tok::semi, false, true);
+ return;
+ }
+ }
}
// There are three options here. If we have 'struct foo;', then
@@ -347,7 +399,23 @@ void Parser::ParseClassSpecifier(DeclSpec &DS,
// Create the tag portion of the class or class template.
DeclTy *TagOrTempDecl;
- if (TemplateParams && TK != Action::TK_Reference)
+ if (Template && TK != Action::TK_Reference)
+ // Explicit specialization or class template partial
+ // specialization. Let semantic analysis decide.
+
+ // FIXME: we want a source range covering the simple-template-id.
+ TagOrTempDecl
+ = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK,
+ StartLoc, SS, /*Range*/
+ Template, NameLoc,
+ LAngleLoc, TemplateArgsPtr,
+ &TemplateArgLocations[0],
+ RAngleLoc, Attr,
+ Action::MultiTemplateParamsArg(Actions,
+ TemplateParams? &(*TemplateParams)[0] : 0,
+ TemplateParams? TemplateParams->size() : 0));
+
+ else if (TemplateParams && TK != Action::TK_Reference)
TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc,
SS, Name, NameLoc, Attr,
Action::MultiTemplateParamsArg(Actions,
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index 742453046b..52824f51c1 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -19,12 +19,23 @@
using namespace clang;
-/// ParseTemplateDeclaration - Parse a template declaration, which includes
-/// the template parameter list and either a function of class declaration.
+/// \brief Parse a template declaration or an explicit specialization.
+///
+/// Template declarations include one or more template parameter lists
+/// and either the function or class template declaration. Explicit
+/// specializations contain one or more 'template < >' prefixes
+/// followed by a (possibly templated) declaration. Since the
+/// syntactic form of both features is nearly identical, we parse all
+/// of the template headers together and let semantic analysis sort
+/// the declarations from the explicit specializations.
///
/// template-declaration: [C++ temp]
/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
-Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
+///
+/// explicit-specialization: [ C++ temp.expl.spec]
+/// 'template' '<' '>' declaration
+Parser::DeclTy *
+Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context) {
assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
"Token does not start a template declaration.");
@@ -40,7 +51,7 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
//
// We parse multiple levels non-recursively so that we can build a
// single data structure containing all of the template parameter
- // lists easily differentiate between the case above and:
+ // lists to easily differentiate between the case above and:
//
// template<typename T>
// class A {
@@ -370,6 +381,68 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) {
return Param;
}
+/// \brief Parses a template-id that after the template name has
+/// already been parsed.
+///
+/// This routine takes care of parsing the enclosed template argument
+/// list ('<' template-parameter-list [opt] '>') and placing the
+/// results into a form that can be transferred to semantic analysis.
+///
+/// \param Template the template declaration produced by isTemplateName
+///
+/// \param TemplateNameLoc the source location of the template name
+///
+/// \param SS if non-NULL, the nested-name-specifier preceding the
+/// template name.
+///
+/// \param ConsumeLastToken if true, then we will consume the last
+/// token that forms the template-id. Otherwise, we will leave the
+/// last token in the stream (e.g., so that it can be replaced with an
+/// annotation token).
+bool
+Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template,
+ SourceLocation TemplateNameLoc,
+ const CXXScopeSpec *SS,
+ bool ConsumeLastToken,
+ SourceLocation &LAngleLoc,
+ TemplateArgList &TemplateArgs,
+ TemplateArgIsTypeList &TemplateArgIsType,
+ TemplateArgLocationList &TemplateArgLocations,
+ SourceLocation &RAngleLoc) {
+ assert(Tok.is(tok::less) && "Must have already parsed the template-name");
+
+ // Consume the '<'.
+ LAngleLoc = ConsumeToken();
+
+ // Parse the optional template-argument-list.
+ bool Invalid = false;
+ {
+ GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
+ if (Tok.isNot(tok::greater))
+ Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
+ TemplateArgLocations);
+
+ if (Invalid) {
+ // Try to find the closing '>'.
+ SkipUntil(tok::greater, true, !ConsumeLastToken);
+
+ return true;
+ }
+ }
+
+ if (Tok.isNot(tok::greater))
+ return true;
+
+ // Determine the location of the '>'. Only consume this token if the
+ // caller asked us to.
+ RAngleLoc = Tok.getLocation();
+
+ if (ConsumeLastToken)
+ ConsumeToken();
+
+ return false;
+}
+
/// 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.
@@ -382,46 +455,44 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
// Consume the template-name.
SourceLocation TemplateNameLoc = ConsumeToken();
- // Consume the '<'.
- SourceLocation LAngleLoc = ConsumeToken();
-
- // Parse the optional template-argument-list.
+ // Parse the enclosed template argument list.
+ SourceLocation LAngleLoc, RAngleLoc;
TemplateArgList TemplateArgs;
TemplateArgIsTypeList TemplateArgIsType;
TemplateArgLocationList TemplateArgLocations;
+ bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+ SS, false, LAngleLoc,
+ TemplateArgs,
+ TemplateArgIsType,
+ TemplateArgLocations,
+ RAngleLoc);
- {
- GreaterThanIsOperatorScope G(GreaterThanIsOperator, false);
- if (Tok.isNot(tok::greater) &&
- ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType,
- TemplateArgLocations)) {
- // Try to find the closing '>'.
- SkipUntil(tok::greater, true, true);
+ ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
+ &TemplateArgIsType[0],
+ TemplateArgs.size());
- // Clean up any template arguments that we successfully parsed.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
- &TemplateArgIsType[0],
- TemplateArgs.size());
-
- return;
- }
- }
-
- if (Tok.isNot(tok::greater))
- return;
+ if (Invalid) // FIXME: How to recover from a broken template-id?
+ return;
- // Determine the location of the '>'. We won't actually consume this
- // token, because we'll be replacing it with the template-id.
- SourceLocation RAngleLoc = Tok.getLocation();
-
// Build the annotation token.
- if (TNK == Action::TNK_Function_template) {
+ if (TNK == Action::TNK_Class_template) {
+ Action::TypeResult Type
+ = Actions.ActOnClassTemplateId(Template, TemplateNameLoc,
+ LAngleLoc, TemplateArgsPtr,
+ &TemplateArgLocations[0],
+ RAngleLoc, SS);
+ if (Type.isInvalid()) // FIXME: better recovery?
+ return;
+
+ Tok.setKind(tok::annot_typename);
+ Tok.setAnnotationValue(Type.get());
+ } else {
// This is a function template. We'll be building a template-id
// annotation token.
Tok.setKind(tok::annot_template_id);
TemplateIdAnnotation *TemplateId
= (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +
- sizeof(void*) * TemplateArgs.size());
+ sizeof(void*) * TemplateArgs.size());
TemplateId->TemplateNameLoc = TemplateNameLoc;
TemplateId->Template = Template;
TemplateId->LAngleLoc = LAngleLoc;
@@ -430,24 +501,6 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK,
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.
- ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0],
- &TemplateArgIsType[0],
- TemplateArgs.size());
- TypeTy *Ty
- = Actions.ActOnClassTemplateSpecialization(Template, TemplateNameLoc,
- LAngleLoc, TemplateArgsPtr,
- &TemplateArgLocations[0],
- RAngleLoc, SS);
-
- if (!Ty) // Something went wrong; don't annotate
- return;
-
- Tok.setKind(tok::annot_typename);
- Tok.setAnnotationValue(Ty);
}
// Common fields for the annotation token
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 9b2b6e54d8..1bc469235a 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1513,14 +1513,26 @@ public:
AttributeList *Attr,