diff options
-rw-r--r-- | include/clang/AST/DeclBase.h | 7 | ||||
-rw-r--r-- | include/clang/AST/DeclNodes.def | 2 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 38 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticParseKinds.def | 2 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 83 | ||||
-rw-r--r-- | include/clang/Parse/DeclSpec.h | 4 | ||||
-rw-r--r-- | include/clang/Parse/Ownership.h | 24 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 13 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 51 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 14 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 74 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 153 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 20 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 158 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-spec.cpp | 31 |
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, |