Implement support for template template parameter packs, e.g.,
template<template<class> class ...Metafunctions>
struct apply_to_each;
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122874 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 149ecbc..b452060 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -51,7 +51,7 @@
TemplateTemplateParmDecl *Parm) {
ID.AddInteger(Parm->getDepth());
ID.AddInteger(Parm->getPosition());
- // FIXME: Parameter pack
+ ID.AddBoolean(Parm->isParameterPack());
TemplateParameterList *Params = Parm->getTemplateParameters();
ID.AddInteger(Params->size());
@@ -66,7 +66,7 @@
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
ID.AddInteger(1);
- // FIXME: Parameter pack
+ ID.AddBoolean(NTTP->isParameterPack());
ID.AddPointer(NTTP->getType().getAsOpaquePtr());
continue;
}
@@ -119,7 +119,9 @@
TemplateTemplateParmDecl *CanonTTP
= TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(), TTP->getDepth(),
- TTP->getPosition(), 0,
+ TTP->getPosition(),
+ TTP->isParameterPack(),
+ 0,
TemplateParameterList::Create(*this, SourceLocation(),
SourceLocation(),
CanonParams.data(),
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index c62225e..70c8632 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -3444,6 +3444,7 @@
return TemplateTemplateParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
Loc, D->getDepth(), D->getPosition(),
+ D->isParameterPack(),
Name.getAsIdentifierInfo(),
TemplateParams);
}
diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp
index 75ea2df..7001005 100644
--- a/lib/AST/DeclBase.cpp
+++ b/lib/AST/DeclBase.cpp
@@ -111,8 +111,11 @@
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this))
return TTP->isParameterPack();
if (const NonTypeTemplateParmDecl *NTTP
- = llvm::dyn_cast<NonTypeTemplateParmDecl>(this))
+ = dyn_cast<NonTypeTemplateParmDecl>(this))
return NTTP->isParameterPack();
+ if (const TemplateTemplateParmDecl *TTP
+ = dyn_cast<TemplateTemplateParmDecl>(this))
+ return TTP->isParameterPack();
return false;
}
diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp
index 8941200..eaa117a 100644
--- a/lib/AST/DeclPrinter.cpp
+++ b/lib/AST/DeclPrinter.cpp
@@ -699,8 +699,11 @@
Out << "> ";
- if (isa<TemplateTemplateParmDecl>(D)) {
- Out << "class " << D->getName();
+ if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
+ Out << "class ";
+ if (TTP->isParameterPack())
+ Out << "...";
+ Out << D->getName();
} else {
Visit(D->getTemplatedDecl());
}
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index 0110e3b..2755a9e 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -412,9 +412,10 @@
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
- IdentifierInfo *Id,
+ bool ParameterPack, IdentifierInfo *Id,
TemplateParameterList *Params) {
- return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params);
+ return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id,
+ Params);
}
//===----------------------------------------------------------------------===//
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index ab24a69..17a9326 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -903,7 +903,7 @@
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
ID.AddInteger(NTTP->getDepth());
ID.AddInteger(NTTP->getIndex());
- ID.AddInteger(NTTP->isParameterPack());
+ ID.AddBoolean(NTTP->isParameterPack());
VisitType(NTTP->getType());
return;
}
@@ -921,6 +921,7 @@
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getIndex());
+ ID.AddBoolean(TTP->isParameterPack());
return;
}
}
diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp
index afa2cc6..8fb6b96 100644
--- a/lib/Parse/ParseTemplate.cpp
+++ b/lib/Parse/ParseTemplate.cpp
@@ -421,12 +421,14 @@
/// parameter-declaration
///
/// type-parameter: (see below)
-/// 'class' ...[opt][C++0x] identifier[opt]
+/// 'class' ...[opt] identifier[opt]
/// 'class' identifier[opt] '=' type-id
-/// 'typename' ...[opt][C++0x] identifier[opt]
+/// 'typename' ...[opt] identifier[opt]
/// 'typename' identifier[opt] '=' type-id
-/// 'template' ...[opt][C++0x] '<' template-parameter-list '>' 'class' identifier[opt]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+/// 'template' '<' template-parameter-list '>'
+/// 'class' ...[opt] identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// = id-expression
Decl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
if (isStartOfTemplateTypeParameter())
return ParseTypeParameter(Depth, Position);
@@ -502,8 +504,10 @@
/// template parameters.
///
/// type-parameter: [C++ temp.param]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
-/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
+/// 'template' '<' template-parameter-list '>' 'class'
+/// ...[opt] identifier[opt]
+/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
+/// = id-expression
Decl *
Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
@@ -529,6 +533,15 @@
}
SourceLocation ClassLoc = ConsumeToken();
+ // Parse the ellipsis, if given.
+ SourceLocation EllipsisLoc;
+ if (Tok.is(tok::ellipsis)) {
+ EllipsisLoc = ConsumeToken();
+
+ if (!getLang().CPlusPlus0x)
+ Diag(EllipsisLoc, diag::err_variadic_templates);
+ }
+
// Get the identifier, if given.
SourceLocation NameLoc;
IdentifierInfo* ParamName = 0;
@@ -569,9 +582,9 @@
}
return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc,
- ParamList, ParamName,
- NameLoc, Depth, Position,
- EqualLoc, DefaultArg);
+ ParamList, EllipsisLoc,
+ ParamName, NameLoc, Depth,
+ Position, EqualLoc, DefaultArg);
}
/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 419f59d..a0c89f0 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -522,6 +522,14 @@
IdResolver.AddDecl(Param);
}
+ // C++0x [temp.param]p9:
+ // A default template-argument may be specified for any kind of
+ // template-parameter that is not a template parameter pack.
+ if (DefaultArg && Ellipsis) {
+ Diag(EqualLoc, diag::err_template_param_pack_default_arg);
+ DefaultArg = ParsedType();
+ }
+
// Handle the default argument, if provided.
if (DefaultArg) {
TypeSourceInfo *DefaultTInfo;
@@ -529,14 +537,6 @@
assert(DefaultTInfo && "expected source information for type");
- // C++0x [temp.param]p9:
- // A default template-argument may be specified for any kind of
- // template-parameter that is not a template parameter pack.
- if (Ellipsis) {
- Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- return Param;
- }
-
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(Loc, DefaultTInfo,
UPPC_DefaultArgument))
@@ -647,16 +647,16 @@
IdResolver.AddDecl(Param);
}
+ // C++0x [temp.param]p9:
+ // A default template-argument may be specified for any kind of
+ // template-parameter that is not a template parameter pack.
+ if (Default && IsParameterPack) {
+ Diag(EqualLoc, diag::err_template_param_pack_default_arg);
+ Default = 0;
+ }
+
// Check the well-formedness of the default template argument, if provided.
if (Default) {
- // C++0x [temp.param]p9:
- // A default template-argument may be specified for any kind of
- // template-parameter that is not a template parameter pack.
- if (IsParameterPack) {
- Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- return Param;
- }
-
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(Default, UPPC_DefaultArgument))
return Param;
@@ -679,21 +679,24 @@
Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
SourceLocation TmpLoc,
TemplateParamsTy *Params,
+ SourceLocation EllipsisLoc,
IdentifierInfo *Name,
SourceLocation NameLoc,
unsigned Depth,
unsigned Position,
SourceLocation EqualLoc,
- const ParsedTemplateArgument &Default) {
+ ParsedTemplateArgument Default) {
assert(S->isTemplateParamScope() &&
"Template template parameter not in template parameter scope!");
// Construct the parameter object.
+ bool IsParameterPack = EllipsisLoc.isValid();
+ // FIXME: Pack-ness is dropped
TemplateTemplateParmDecl *Param =
TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(),
NameLoc.isInvalid()? TmpLoc : NameLoc,
- Depth, Position, Name,
- Params);
+ Depth, Position, IsParameterPack,
+ Name, Params);
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
@@ -708,6 +711,14 @@
Param->setInvalidDecl();
}
+ // C++0x [temp.param]p9:
+ // A default template-argument may be specified for any kind of
+ // template-parameter that is not a template parameter pack.
+ if (IsParameterPack && !Default.isInvalid()) {
+ Diag(EqualLoc, diag::err_template_param_pack_default_arg);
+ Default = ParsedTemplateArgument();
+ }
+
if (!Default.isInvalid()) {
// Check only that we have a template template argument. We don't want to
// try to check well-formedness now, because our template template parameter
@@ -1212,7 +1223,7 @@
// new declaration.
SawDefaultArgument = true;
// FIXME: We need to create a new kind of "default argument"
- // expression that points to a previous template template
+ // expression that points to a previous non-type template
// parameter.
NewNonTypeParm->setDefaultArgument(
OldNonTypeParm->getDefaultArgument(),
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 5d724f3..a256537 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -697,9 +697,22 @@
TTP->getPosition()))
return D;
- // FIXME: Variadic templates index substitution.
- TemplateName Template
- = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate();
+ TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition());
+
+ if (TTP->isParameterPack()) {
+ assert(Arg.getKind() == TemplateArgument::Pack &&
+ "Missing argument pack");
+
+ if (getSema().ArgumentPackSubstitutionIndex == -1) {
+ // FIXME: Variadic templates fun case.
+ getSema().Diag(Loc, diag::err_pack_expansion_mismatch_unsupported);
+ return 0;
+ }
+
+ Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
+ }
+
+ TemplateName Template = Arg.getAsTemplate();
assert(!Template.isNull() && Template.getAsTemplateDecl() &&
"Wrong kind of template template argument");
return Template.getAsTemplateDecl();
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 60a942a..92521ae 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1542,8 +1542,8 @@
TemplateTemplateParmDecl *Param
= TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(), D->getIdentifier(),
- InstParams);
+ D->getPosition(), D->isParameterPack(),
+ D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
// Introduce this template parameter's instantiation into the instantiation
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 4e01ec2..acb7314 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -78,7 +78,16 @@
return true;
}
- // FIXME: Record occurrences of template template parameter packs.
+ /// \brief Record occurrences of template template parameter packs.
+ bool TraverseTemplateName(TemplateName Template) {
+ if (TemplateTemplateParmDecl *TTP
+ = dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Template.getAsTemplateDecl()))
+ if (TTP->isParameterPack())
+ Unexpanded.push_back(std::make_pair(TTP, SourceLocation()));
+
+ return inherited::TraverseTemplateName(Template);
+ }
//------------------------------------------------------------------------
// Pruning the search for unexpanded parameter packs.
@@ -556,7 +565,6 @@
SourceLocation RParenLoc) {
// C++0x [expr.sizeof]p5:
// The identifier in a sizeof... expression shall name a parameter pack.
-
LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName);
LookupName(R, S);
diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp
index 40f3ab7..239abbe 100644
--- a/lib/Serialization/ASTReaderDecl.cpp
+++ b/lib/Serialization/ASTReaderDecl.cpp
@@ -1173,6 +1173,7 @@
TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
bool IsInherited = Record[Idx++];
D->setDefaultArgument(Arg, IsInherited);
+ D->ParameterPack = Record[Idx++];
}
void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) {
@@ -1433,7 +1434,8 @@
QualType(), false, 0);
break;
case DECL_TEMPLATE_TEMPLATE_PARM:
- D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(),0,0,0,0);
+ D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0,
+ false, 0, 0);
break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0);
diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp
index add6cd3..ff1f4bf 100644
--- a/lib/Serialization/ASTWriterDecl.cpp
+++ b/lib/Serialization/ASTWriterDecl.cpp
@@ -1011,6 +1011,7 @@
// Rest of TemplateTemplateParmDecl.
Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
Record.push_back(D->defaultArgumentWasInherited());
+ Record.push_back(D->isParameterPack());
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}