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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 213a210..c7f92cf 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -419,7 +419,8 @@
/// [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 @@
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 @@
/// [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 @@
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 @@
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 eaada1c..1b0b811 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -202,7 +202,8 @@
/// 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 @@
}
// 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 5d0c4b5..bd937d4 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -27,59 +27,94 @@
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)) {
- 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 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;
+ }
+
+ // 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 @@
/// 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 @@
/// '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 @@
/// '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 @@
}
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 @@
/// 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 @@
/// 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 @@
}
// 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 48b0d5f..e5b40d9 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -373,7 +373,9 @@
/// 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 @@
/// [!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] ';'