diff options
author | Douglas Gregor <dgregor@apple.com> | 2008-12-24 02:52:09 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2008-12-24 02:52:09 +0000 |
commit | c4b4e7b8f6ca9b036824e048af49cd2a52b57cdf (patch) | |
tree | 9f49436d6c7742234922d2fe5d16f29ade8c0edb /lib/Parse/ParseTemplate.cpp | |
parent | 07603aa9e57dc13889dd330cd29159003f1c45c3 (diff) |
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
Diffstat (limited to 'lib/Parse/ParseTemplate.cpp')
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 145 |
1 files changed, 94 insertions, 51 deletions
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<typename T> + // template<typename U> + // class A<T>::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<typename T> + // class A { + // template<typename U> class B; + // }; + // + // In the first case, the action for declaring A<T>::B receives + // both template parameter lists. In the second case, the action for + // defining A<T>::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 |