aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2008-12-24 02:52:09 +0000
committerDouglas Gregor <dgregor@apple.com>2008-12-24 02:52:09 +0000
commitc4b4e7b8f6ca9b036824e048af49cd2a52b57cdf (patch)
tree9f49436d6c7742234922d2fe5d16f29ade8c0edb
parent07603aa9e57dc13889dd330cd29159003f1c45c3 (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
-rw-r--r--Driver/PrintParserCallbacks.cpp3
-rw-r--r--include/clang/AST/DeclCXX.h28
-rw-r--r--include/clang/Basic/DiagnosticKinds.def2
-rw-r--r--include/clang/Parse/Action.h61
-rw-r--r--include/clang/Parse/Ownership.h2
-rw-r--r--include/clang/Parse/Parser.h33
-rw-r--r--lib/AST/DeclCXX.cpp15
-rw-r--r--lib/Parse/ParseDecl.cpp13
-rw-r--r--lib/Parse/ParseDeclCXX.cpp12
-rw-r--r--lib/Parse/ParseTemplate.cpp145
-rw-r--r--lib/Parse/Parser.cpp10
-rw-r--r--lib/Sema/Sema.h19
-rw-r--r--lib/Sema/SemaDecl.cpp3
-rw-r--r--lib/Sema/SemaTemplate.cpp22
-rw-r--r--test/Parser/cxx-template-decl.cpp3
15 files changed, 284 insertions, 87 deletions
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<Decl **>(this + 1); }
+ const_iterator begin() const {
+ return reinterpret_cast<Decl * const *>(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<int Size>
/// 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<typename T, T Size>
+ /// @endcode
+ ///
+ /// Depth is the number of enclosing template parameter lists. This
+ /// value does not include templates from outer scopes. For example:
+ ///
+ /// @code
+ /// template<typename T> // depth = 0
+ /// class A {
+ /// template<typename U> // depth = 0
+ /// class B;
+ /// };
+ ///
+ /// template<typename T> // depth = 0
+ /// template<typename U> // depth = 1
+ /// class A<T>::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<TemplateParamsTy *, 4> 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<DeclTy *, 4> 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<TemplateArgTy*, 8> 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<TemplateParameterList>::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<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
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<int Size>
/// 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..5