From: Douglas Gregor Date: Wed, 24 Dec 2008 02:52:09 +0000 (+0000) Subject: Keep track of template arguments when we parse them. Right now, we don't actually... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c4b4e7b8f6ca9b036824e048af49cd2a52b57cdf;p=clang Keep track of template arguments when we parse them. Right now, we don't actually do anything with the template arguments, but they'll be used to create template declarations git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61413 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index c97e95a51a..291ee393c1 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/Driver/PrintParserCallbacks.cpp @@ -189,7 +189,8 @@ namespace { virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr) { + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists) { // TagType is an instance of DeclSpec::TST, indicating what kind of tag this // is (struct/union/enum/class). llvm::cout << __FUNCTION__ << "\n"; diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index f5089785b9..d66e1a241e 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -945,6 +945,34 @@ protected: void ReadInRec(llvm::Deserializer& D, ASTContext& C); }; +/// TemplateParameterList - Stores a list of template parameters. +class TemplateParameterList { + /// NumParams - The number of template parameters in this template + /// parameter list. + unsigned NumParams; + + TemplateParameterList(Decl **Params, unsigned NumParams); + +public: + static TemplateParameterList *Create(ASTContext &C, Decl **Params, + unsigned NumParams); + + /// iterator - Iterates through the template parameters in this list. + typedef Decl** iterator; + + /// const_iterator - Iterates through the template parameters in this list. + typedef Decl* const* const_iterator; + + iterator begin() { return reinterpret_cast(this + 1); } + const_iterator begin() const { + return reinterpret_cast(this + 1); + } + iterator end() { return begin() + NumParams; } + const_iterator end() const { return begin() + NumParams; } + + unsigned size() const { return NumParams; } +}; + } // end namespace clang #endif diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 321b2c69c5..5c72e8de39 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -976,6 +976,8 @@ DIAG(err_template_param_shadow, ERROR, "declaration of %0 shadows template parameter") DIAG(note_template_param_here, NOTE, "template parameter is declared here") +DIAG(note_template_export_unsupported, NOTE, + "exported templates are unsupported") DIAG(err_unexpected_typedef, ERROR, "unexpected type name %0: expected expression") diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 13b3c8a2b7..335b97224c 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -63,6 +63,7 @@ public: typedef void BaseTy; typedef void MemInitTy; typedef void CXXScopeTy; + typedef void TemplateParamsTy; typedef void TemplateArgTy; /// Expr/Stmt/Type/BaseResult - Provide a unique type to wrap @@ -90,6 +91,7 @@ public: /// Multiple expressions or statements as arguments. typedef ASTMultiPtr<&ActionBase::DeleteExpr> MultiExprArg; typedef ASTMultiPtr<&ActionBase::DeleteStmt> MultiStmtArg; + typedef ASTMultiPtr<&ActionBase::DeleteTemplateParams> MultiTemplateParamsArg; typedef ASTMultiPtr<&ActionBase::DeleteTemplateArg> MultiTemplateArgArg; // Utilities for Action implementations to return smart results. @@ -303,7 +305,8 @@ public: virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr) { + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists) { // TagType is an instance of DeclSpec::TST, indicating what kind of tag this // is (struct/union/enum/class). return 0; @@ -944,11 +947,15 @@ public: /// parameter (NULL indicates an unnamed template parameter) and /// ParamName is the location of the parameter name (if any). /// If the type parameter has a default argument, it will be added - /// later via ActOnTypeParameterDefault. + /// later via ActOnTypeParameterDefault. Depth and Position provide + /// the number of enclosing templates (see + /// ActOnTemplateParameterList) and the number of previous + /// parameters within this template parameter list. virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation KeyLoc, IdentifierInfo *ParamName, - SourceLocation ParamNameLoc) { + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position) { return 0; } @@ -960,12 +967,54 @@ public: /// ActOnNonTypeTemplateParameter - Called when a C++ non-type /// template parameter (e.g., "int Size" in "template /// class Array") has been parsed. S is the current scope and D is - /// the parsed declarator. - virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) { + /// the parsed declarator. Depth and Position provide + /// the number of enclosing templates (see + /// ActOnTemplateParameterList) and the number of previous + /// parameters within this template parameter list. + virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position) { return 0; } - + /// ActOnTemplateParameterList - Called when a complete template + /// parameter list has been parsed, e.g., + /// + /// @code + /// export template + /// @endcode + /// + /// Depth is the number of enclosing template parameter lists. This + /// value does not include templates from outer scopes. For example: + /// + /// @code + /// template // depth = 0 + /// class A { + /// template // depth = 0 + /// class B; + /// }; + /// + /// template // depth = 0 + /// template // depth = 1 + /// class A::B { ... }; + /// @endcode + /// + /// ExportLoc, if valid, is the position of the "export" + /// keyword. Otherwise, "export" was not specified. + /// TemplateLoc is the position of the template keyword, LAngleLoc + /// is the position of the left angle bracket, and RAngleLoc is the + /// position of the corresponding right angle bracket. + /// Params/NumParams provides the template parameters that were + /// parsed as part of the template-parameter-list. + virtual TemplateParamsTy * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclTy **Params, unsigned NumParams, + SourceLocation RAngleLoc) { + return 0; + } //===----------------------- Obj-C Declarations -------------------------===// diff --git a/include/clang/Parse/Ownership.h b/include/clang/Parse/Ownership.h index 2e2a57d79f..a7d805d38e 100644 --- a/include/clang/Parse/Ownership.h +++ b/include/clang/Parse/Ownership.h @@ -118,6 +118,7 @@ namespace clang // what types are required to be identical for the actions. typedef void ExprTy; typedef void StmtTy; + typedef void TemplateParamsTy; typedef void TemplateArgTy; /// ActionResult - This structure is used while parsing/acting on @@ -146,6 +147,7 @@ namespace clang /// pointers need access to them. virtual void DeleteExpr(ExprTy *E) {} virtual void DeleteStmt(StmtTy *E) {} + virtual void DeleteTemplateParams(TemplateParamsTy *E) {} virtual void DeleteTemplateArg(TemplateArgTy *E) {} }; diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index fb1ebcf36e..df6f895e49 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -78,8 +78,11 @@ public: typedef Action::BaseTy BaseTy; typedef Action::MemInitTy MemInitTy; typedef Action::CXXScopeTy CXXScopeTy; + typedef Action::TemplateParamsTy TemplateParamsTy; typedef Action::TemplateArgTy TemplateArgTy; + typedef llvm::SmallVector TemplateParameterLists; + typedef Action::ExprResult ExprResult; typedef Action::StmtResult StmtResult; typedef Action::BaseResult BaseResult; @@ -500,7 +503,8 @@ private: //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. DeclTy *ParseExternalDeclaration(); - DeclTy *ParseDeclarationOrFunctionDefinition(); + DeclTy *ParseDeclarationOrFunctionDefinition( + TemplateParameterLists *TemplateParams = 0); DeclTy *ParseFunctionDefinition(Declarator &D); void ParseKNRParamDeclarations(Declarator &D); OwningExprResult ParseSimpleAsm(); @@ -751,9 +755,11 @@ private: DeclTy *ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); DeclTy *ParseFunctionStatementBody(DeclTy *Decl, SourceLocation L, SourceLocation R); - void ParseDeclarationSpecifiers(DeclSpec &DS); + void ParseDeclarationSpecifiers(DeclSpec &DS, + TemplateParameterLists *TemplateParams = 0); bool MaybeParseTypeSpecifier(DeclSpec &DS, int &isInvalid, - const char *&PrevSpec); + const char *&PrevSpec, + TemplateParameterLists *TemplateParams = 0); void ParseSpecifierQualifierList(DeclSpec &DS); void ParseObjCTypeQualifierList(ObjCDeclSpec &DS); @@ -928,7 +934,8 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. TypeTy *ParseClassName(const CXXScopeSpec *SS = 0); - void ParseClassSpecifier(DeclSpec &DS); + void ParseClassSpecifier(DeclSpec &DS, + TemplateParameterLists *TemplateParams = 0); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclTy *TagDecl); DeclTy *ParseCXXClassMemberDeclaration(AccessSpecifier AS); @@ -948,14 +955,20 @@ private: //===--------------------------------------------------------------------===// // C++ 14: Templates [temp] + typedef llvm::SmallVector TemplateParameterList; + // C++ 14.1: Template Parameters [temp.param] DeclTy *ParseTemplateDeclaration(unsigned Context); - bool ParseTemplateParameters(DeclTy* TempDecl); - bool ParseTemplateParameterList(DeclTy *TmpDecl); - DeclTy *ParseTemplateParameter(); - DeclTy *ParseTypeParameter(); - DeclTy *ParseTemplateTemplateParameter(); - DeclTy *ParseNonTypeTemplateParameter(); + bool ParseTemplateParameters(unsigned Depth, + TemplateParameterList &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc); + bool ParseTemplateParameterList(unsigned Depth, + TemplateParameterList &TemplateParams); + DeclTy *ParseTemplateParameter(unsigned Depth, unsigned Position); + DeclTy *ParseTypeParameter(unsigned Depth, unsigned Position); + DeclTy *ParseTemplateTemplateParameter(unsigned Depth, unsigned Position); + DeclTy *ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position); // C++ 14.3: Template arguments [temp.arg] typedef llvm::SmallVector TemplateArgList; void AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS = 0); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index d213385d91..27065a75ba 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -37,6 +37,21 @@ NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, return new (Mem) NonTypeTemplateParmDecl(DC, L, Id, T, TypeSpecStartLoc); } +TemplateParameterList::TemplateParameterList(Decl **Params, unsigned NumParams) + : NumParams(NumParams) { + for (unsigned Idx = 0; Idx < NumParams; ++Idx) + begin()[Idx] = Params[Idx]; +} + +TemplateParameterList * +TemplateParameterList::Create(ASTContext &C, Decl **Params, + unsigned NumParams) { + unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams; + unsigned Align = llvm::AlignOf::Alignment; + void *Mem = C.getAllocator().Allocate(Size, Align); + return new (Mem) TemplateParameterList(Params, NumParams); +} + CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id) : RecordDecl(CXXRecord, TK, DC, L, Id), diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 213a210b9e..c7f92cf014 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -419,7 +419,8 @@ void Parser::ParseSpecifierQualifierList(DeclSpec &DS) { /// [C++] 'virtual' /// [C++] 'explicit' /// -void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) +void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, + TemplateParameterLists *TemplateParams) { DS.SetRangeStart(Tok.getLocation()); while (1) { @@ -436,7 +437,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) default: // Try to parse a type-specifier; if we found one, continue. If it's not // a type, this falls through. - if (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) { + if (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec, TemplateParams)) { continue; } @@ -661,7 +662,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS) /// [OBJC] class-name objc-protocol-refs[opt] [TODO] /// [OBJC] typedef-name objc-protocol-refs[opt] [TODO] bool Parser::MaybeParseTypeSpecifier(DeclSpec &DS, int& isInvalid, - const char *&PrevSpec) { + const char *&PrevSpec, + TemplateParameterLists *TemplateParams) { // Annotate typenames and C++ scope specifiers. TryAnnotateTypeOrScopeToken(); @@ -748,7 +750,7 @@ bool Parser::MaybeParseTypeSpecifier(DeclSpec &DS, int& isInvalid, case tok::kw_class: case tok::kw_struct: case tok::kw_union: - ParseClassSpecifier(DS); + ParseClassSpecifier(DS, TemplateParams); return true; // enum-specifier: @@ -1036,7 +1038,8 @@ void Parser::ParseEnumSpecifier(DeclSpec &DS) { else TK = Action::TK_Reference; DeclTy *TagDecl = Actions.ActOnTag(CurScope, DeclSpec::TST_enum, TK, StartLoc, - SS, Name, NameLoc, Attr); + SS, Name, NameLoc, Attr, + Action::MultiTemplateParamsArg(Actions)); if (Tok.is(tok::l_brace)) ParseEnumBody(StartLoc, TagDecl); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index eaada1c26c..1b0b811c88 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -202,7 +202,8 @@ Parser::TypeTy *Parser::ParseClassName(const CXXScopeSpec *SS) { /// struct-or-union: /// 'struct' /// 'union' -void Parser::ParseClassSpecifier(DeclSpec &DS) { +void Parser::ParseClassSpecifier(DeclSpec &DS, + TemplateParameterLists *TemplateParams) { assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_struct) || Tok.is(tok::kw_union)) && @@ -258,8 +259,13 @@ void Parser::ParseClassSpecifier(DeclSpec &DS) { } // Parse the tag portion of this. - DeclTy *TagDecl = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, - NameLoc, Attr); + DeclTy *TagDecl + = Actions.ActOnTag(CurScope, TagType, TK, StartLoc, SS, Name, + NameLoc, Attr, + Action::MultiTemplateParamsArg( + Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); // Parse the optional base clause (C++ only). if (getLang().CPlusPlus && Tok.is(tok::colon)) { diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 5d0c4b5350..bd937d447a 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -27,59 +27,94 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) { assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Token does not start a template declaration."); - // Consume the optional export token, if it exists, followed by the - // namespace token. - bool isExported = false; - if(Tok.is(tok::kw_export)) { - SourceLocation ExportLoc = ConsumeToken(); - if(!Tok.is(tok::kw_template)) { + // Enter template-parameter scope. + ParseScope TemplateParmScope(this, Scope::TemplateParamScope); + + // Parse multiple levels of template headers within this template + // parameter scope, e.g., + // + // template + // template + // class A::B { ... }; + // + // We parse multiple levels non-recursively so that we can build a + // single data structure containing all of the template parameter + // lists, and easily differentiate between the case above and: + // + // template + // class A { + // template class B; + // }; + // + // In the first case, the action for declaring A::B receives + // both template parameter lists. In the second case, the action for + // defining A::B receives just the inner template parameter list + // (and retrieves the outer template parameter list from its + // context). + TemplateParameterLists ParamLists; + do { + // Consume the 'export', if any. + SourceLocation ExportLoc; + if (Tok.is(tok::kw_export)) { + ExportLoc = ConsumeToken(); + } + + // Consume the 'template', which should be here. + SourceLocation TemplateLoc; + if (Tok.is(tok::kw_template)) { + TemplateLoc = ConsumeToken(); + } else { Diag(Tok.getLocation(), diag::err_expected_template); return 0; } - isExported = true; - } - SourceLocation TemplateLoc = ConsumeToken(); - // Enter template-parameter scope. - ParseScope TemplateParmScope(this, Scope::TemplateParamScope); - - // Try to parse the template parameters, and the declaration if - // successful. - DeclTy *TemplateDecl = 0; - if (Tok.is(tok::less) && NextToken().is(tok::greater)) { - // This is a template specialization. Just consume the angle - // brackets and parse the declaration or function definition that - // follows. - // FIXME: Record somehow that we're in an explicit specialization. - ConsumeToken(); - ConsumeToken(); - TemplateParmScope.Exit(); - TemplateDecl = ParseDeclarationOrFunctionDefinition(); - } else { - if(ParseTemplateParameters(0)) - TemplateDecl = ParseDeclarationOrFunctionDefinition(); - } + // Parse the '<' template-parameter-list '>' + SourceLocation LAngleLoc, RAngleLoc; + TemplateParameterList TemplateParams; + ParseTemplateParameters(ParamLists.size(), TemplateParams, LAngleLoc, + RAngleLoc); + + ParamLists.push_back( + Actions.ActOnTemplateParameterList(ParamLists.size(), ExportLoc, + TemplateLoc, LAngleLoc, + &TemplateParams[0], + TemplateParams.size(), RAngleLoc)); + } while (Tok.is(tok::kw_export) || Tok.is(tok::kw_template)); + + // Parse the actual template declaration. + DeclTy *TemplateDecl = ParseDeclarationOrFunctionDefinition(&ParamLists); return TemplateDecl; } /// ParseTemplateParameters - Parses a template-parameter-list enclosed in -/// angle brackets. -bool Parser::ParseTemplateParameters(DeclTy* TmpDecl) { +/// angle brackets. Depth is the depth of this +/// template-parameter-list, which is the number of template headers +/// directly enclosing this template header. TemplateParams is the +/// current list of template parameters we're building. The template +/// parameter we parse will be added to this list. LAngleLoc and +/// RAngleLoc will receive the positions of the '<' and '>', +/// respectively, that enclose this template parameter list. +bool Parser::ParseTemplateParameters(unsigned Depth, + TemplateParameterList &TemplateParams, + SourceLocation &LAngleLoc, + SourceLocation &RAngleLoc) { // Get the template parameter list. if(!Tok.is(tok::less)) { Diag(Tok.getLocation(), diag::err_expected_less_after) << "template"; return false; } - ConsumeToken(); + LAngleLoc = ConsumeToken(); // Try to parse the template parameter list. - if(ParseTemplateParameterList(0)) { + if (Tok.is(tok::greater)) + RAngleLoc = ConsumeToken(); + else if(ParseTemplateParameterList(Depth, TemplateParams)) { if(!Tok.is(tok::greater)) { Diag(Tok.getLocation(), diag::err_expected_greater); return false; } - ConsumeToken(); + RAngleLoc = ConsumeToken(); } return true; } @@ -92,13 +127,14 @@ bool Parser::ParseTemplateParameters(DeclTy* TmpDecl) { /// template-parameter-list: [C++ temp] /// template-parameter /// template-parameter-list ',' template-parameter -bool Parser::ParseTemplateParameterList(DeclTy* TmpDecl) { - // FIXME: For now, this is just going to consume the template parameters. - // Eventually, we should pass the template decl AST node as a parameter and - // apply template parameters as we find them. +bool +Parser::ParseTemplateParameterList(unsigned Depth, + TemplateParameterList &TemplateParams) { while(1) { - DeclTy* TmpParam = ParseTemplateParameter(); - if(!TmpParam) { + if (DeclTy* TmpParam + = ParseTemplateParameter(Depth, TemplateParams.size())) { + TemplateParams.push_back(TmpParam); + } else { // If we failed to parse a template parameter, skip until we find // a comma or closing brace. SkipUntil(tok::comma, tok::greater, true, true); @@ -137,20 +173,21 @@ bool Parser::ParseTemplateParameterList(DeclTy* TmpDecl) { /// 'typename' identifier[opt] '=' type-id /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression -Parser::DeclTy *Parser::ParseTemplateParameter() { +Parser::DeclTy * +Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { TryAnnotateCXXScopeToken(); if(Tok.is(tok::kw_class) || (Tok.is(tok::kw_typename) && NextToken().isNot(tok::annot_qualtypename))) { - return ParseTypeParameter(); + return ParseTypeParameter(Depth, Position); } else if(Tok.is(tok::kw_template)) { - return ParseTemplateTemplateParameter(); + return ParseTemplateTemplateParameter(Depth, Position); } else { // If it's none of the above, then it must be a parameter declaration. // NOTE: This will pick up errors in the closure of the template parameter // list (e.g., template < ; Check here to implement >> style closures. - return ParseNonTypeTemplateParameter(); + return ParseNonTypeTemplateParameter(Depth, Position); } return 0; } @@ -164,7 +201,7 @@ Parser::DeclTy *Parser::ParseTemplateParameter() { /// 'class' identifier[opt] '=' type-id /// 'typename' identifier[opt] /// 'typename' identifier[opt] '=' type-id -Parser::DeclTy *Parser::ParseTypeParameter() { +Parser::DeclTy *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) && "A type-parameter starts with 'class' or 'typename'"); @@ -188,13 +225,13 @@ Parser::DeclTy *Parser::ParseTypeParameter() { } DeclTy *TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword, - KeyLoc, ParamName, NameLoc); + KeyLoc, ParamName, NameLoc, + Depth, Position); // Grab a default type id (if given). if(Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); - TypeTy *DefaultType = ParseTypeName(); - if(DefaultType) + if (TypeTy *DefaultType = ParseTypeName()) Actions.ActOnTypeParameterDefault(TypeParam, DefaultType); } @@ -207,12 +244,16 @@ Parser::DeclTy *Parser::ParseTypeParameter() { /// type-parameter: [C++ temp.param] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] /// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression -Parser::DeclTy* Parser::ParseTemplateTemplateParameter() { +Parser::DeclTy * +Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); - if(!ParseTemplateParameters(0)) { + TemplateParameterList TemplateParams; + SourceLocation LParenLoc, RParenLoc; + if(!ParseTemplateParameters(Depth+1, TemplateParams, LParenLoc, + RParenLoc)) { return 0; } @@ -265,7 +306,8 @@ Parser::DeclTy* Parser::ParseTemplateTemplateParameter() { /// parameters. /// FIXME: We need to make a ParseParameterDeclaration that works for /// non-type template parameters and normal function parameters. -Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() { +Parser::DeclTy * +Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { SourceLocation StartLoc = Tok.getLocation(); // Parse the declaration-specifiers (i.e., the type). @@ -288,7 +330,8 @@ Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() { } // Create the parameter. - DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl); + DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl, + Depth, Position); // Is there a default value? Parsing this can be fairly annoying because // we have to stop on the first non-nested (paren'd) '>' as the closure diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 48b0d5f422..e5b40d9a44 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -373,7 +373,9 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { /// ParseDeclarationOrFunctionDefinition - Parse either a function-definition or /// a declaration. We can't tell which we have until we read up to the -/// compound-statement in function-definition. +/// compound-statement in function-definition. TemplateParams, if +/// non-NULL, provides the template parameters when we're parsing a +/// C++ template-declaration. /// /// function-definition: [C99 6.9.1] /// decl-specs declarator declaration-list[opt] compound-statement @@ -385,10 +387,12 @@ Parser::DeclTy *Parser::ParseExternalDeclaration() { /// [!C99] init-declarator-list ';' [TODO: warn in c99 mode] /// [OMP] threadprivate-directive [TODO] /// -Parser::DeclTy *Parser::ParseDeclarationOrFunctionDefinition() { +Parser::DeclTy * +Parser::ParseDeclarationOrFunctionDefinition( + TemplateParameterLists *TemplateParams) { // Parse the common declaration-specifiers piece. DeclSpec DS; - ParseDeclarationSpecifiers(DS); + ParseDeclarationSpecifiers(DS, TemplateParams); // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 843e732e87..3225628a9d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -307,7 +307,8 @@ public: virtual DeclTy *ActOnTag(Scope *S, unsigned TagType, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr); + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists); virtual void ActOnDefs(Scope *S, DeclTy *TagD, SourceLocation DeclStart, IdentifierInfo *ClassName, @@ -1034,9 +1035,19 @@ public: virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename, SourceLocation KeyLoc, IdentifierInfo *ParamName, - SourceLocation ParamNameLoc); - virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D); - + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position); + virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position); + virtual TemplateParamsTy * + ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclTy **Params, unsigned NumParams, + SourceLocation RAngleLoc); + // Objective-C declarations. virtual DeclTy *ActOnStartClassInterface(SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c668959176..902101d617 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2527,7 +2527,8 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, IdentifierInfo *Name, SourceLocation NameLoc, - AttributeList *Attr) { + AttributeList *Attr, + MultiTemplateParamsArg TemplateParameterLists) { // If this is not a definition, it must have a name. assert((Name != 0 || TK == TK_Definition) && "Nameless record must be a definition!"); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d300f283b6..f448664615 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -86,7 +86,8 @@ bool Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename, SourceLocation KeyLoc, IdentifierInfo *ParamName, - SourceLocation ParamNameLoc) { + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool Invalid = false; @@ -117,7 +118,9 @@ Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename, /// template parameter (e.g., "int Size" in "template /// class Array") has been parsed. S is the current scope and D is /// the parsed declarator. -Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) { +Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, + unsigned Depth, + unsigned Position) { QualType T = GetTypeForDeclarator(D, S); assert(S->isTemplateParamScope() && @@ -145,3 +148,18 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D) { } return Param; } + +/// ActOnTemplateParameterList - Builds a TemplateParameterList that +/// contains the template parameters in Params/NumParams. +Sema::TemplateParamsTy * +Sema::ActOnTemplateParameterList(unsigned Depth, + SourceLocation ExportLoc, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + DeclTy **Params, unsigned NumParams, + SourceLocation RAngleLoc) { + if (ExportLoc.isValid()) + Diag(ExportLoc, diag::note_template_export_unsupported); + + return TemplateParameterList::Create(Context, (Decl**)Params, NumParams); +} diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index bcf05fcefc..53813776e7 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -3,7 +3,8 @@ // Errors export class foo { }; // expected-error {{expected template}} template x; // expected-error {{expected '<' after 'template'}} -export template x; // expected-error {{expected '<' after 'template'}} +export template x; // expected-error {{expected '<' after 'template'}} \ + // expected-note {{exported templates are unsupported}} template < ; // expected-error {{parse error}} template