Implement support for template template parameter packs, e.g.,

template<template<class> class ...Metafunctions>
    struct apply_to_each;

llvm-svn: 122874
This commit is contained in:
Douglas Gregor
2011-01-05 15:48:55 +00:00
parent c7d65b42fc
commit f550077ef5
19 changed files with 152 additions and 51 deletions

View File

@@ -1084,18 +1084,22 @@ class TemplateTemplateParmDecl
/// Whether or not the default argument was inherited.
bool DefaultArgumentWasInherited;
/// \brief Whether this parameter is a parameter pack.
bool ParameterPack;
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), DefaultArgument(),
DefaultArgumentWasInherited(false)
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
{ }
public:
static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, IdentifierInfo *Id,
unsigned P, bool ParameterPack,
IdentifierInfo *Id,
TemplateParameterList *Params);
using TemplateParmPosition::getDepth;
@@ -1108,7 +1112,7 @@ public:
/// \code
/// template<template <class T> ...MetaFunctions> struct Apply;
/// \endcode
bool isParameterPack() const { return /*FIXME: variadic templates*/false; }
bool isParameterPack() const { return ParameterPack; }
/// \brief Determine whether this template parameter has a default
/// argument.

View File

@@ -2845,12 +2845,13 @@ public:
Decl *ActOnTemplateTemplateParameter(Scope *S,
SourceLocation TmpLoc,
TemplateParamsTy *Params,
SourceLocation EllipsisLoc,
IdentifierInfo *ParamName,
SourceLocation ParamNameLoc,
unsigned Depth,
unsigned Position,
SourceLocation EqualLoc,
const ParsedTemplateArgument &DefaultArg);
ParsedTemplateArgument DefaultArg);
TemplateParamsTy *
ActOnTemplateParameterList(unsigned Depth,

View File

@@ -51,7 +51,7 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
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 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID,
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 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *CanonTTP
= TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(),
SourceLocation(), TTP->getDepth(),
TTP->getPosition(), 0,
TTP->getPosition(),
TTP->isParameterPack(),
0,
TemplateParameterList::Create(*this, SourceLocation(),
SourceLocation(),
CanonParams.data(),

View File

@@ -3444,6 +3444,7 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
return TemplateTemplateParmDecl::Create(Importer.getToContext(),
Importer.getToContext().getTranslationUnitDecl(),
Loc, D->getDepth(), D->getPosition(),
D->isParameterPack(),
Name.getAsIdentifierInfo(),
TemplateParams);
}

View File

@@ -111,8 +111,11 @@ bool Decl::isTemplateParameterPack() const {
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;
}

View File

@@ -699,8 +699,11 @@ void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) {
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());
}

View File

@@ -412,9 +412,10 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
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);
}
//===----------------------------------------------------------------------===//

View File

@@ -903,7 +903,7 @@ void StmtProfiler::VisitDecl(Decl *D) {
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 @@ void StmtProfiler::VisitDecl(Decl *D) {
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) {
ID.AddInteger(TTP->getDepth());
ID.AddInteger(TTP->getIndex());
ID.AddBoolean(TTP->isParameterPack());
return;
}
}

View File

@@ -421,12 +421,14 @@ bool Parser::isStartOfTemplateTypeParameter() {
/// 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 @@ Decl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) {
/// 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 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
}
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 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) {
}
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

View File

@@ -522,6 +522,14 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
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 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, bool Ellipsis,
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 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
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::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
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 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
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 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
// 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(),

View File

@@ -697,9 +697,22 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
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();

View File

@@ -1542,8 +1542,8 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
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

View File

@@ -78,7 +78,16 @@ namespace {
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 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
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);

View File

@@ -1173,6 +1173,7 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
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 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) {
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);

View File

@@ -1011,6 +1011,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// Rest of TemplateTemplateParmDecl.
Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
Record.push_back(D->defaultArgumentWasInherited());
Record.push_back(D->isParameterPack());
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}

View File

@@ -138,3 +138,29 @@ namespace Indices {
int check0[is_same<build_indices<5>::type,
int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1];
}
namespace TemplateTemplateApply {
template<typename T, template<class> class ...Meta>
struct apply_each {
typedef tuple<typename Meta<T>::type...> type;
};
template<typename T>
struct add_reference {
typedef T& type;
};
template<typename T>
struct add_pointer {
typedef T* type;
};
template<typename T>
struct add_const {
typedef const T type;
};
int check0[is_same<apply_each<int,
add_reference, add_pointer, add_const>::type,
tuple<int&, int*, int const>>::value? 1 : -1];
}

View File

@@ -154,6 +154,11 @@ void TestPPNameFunc(int i) {
f(static_cast<Types>(i)); // expected-error{{expression contains unexpanded parameter pack 'Types'}}
}
template<typename T, template<class> class ...Meta>
struct TestUnexpandedTTP {
typedef tuple<typename Meta<T>::type> type; // expected-error{{declaration type contains unexpanded parameter pack 'Meta'}}
};
// Test for unexpanded parameter packs in declarations.
// FIXME: Attributes?
template<typename T, typename... Types>

View File

@@ -19,3 +19,5 @@ template<template<typename T> class> struct X1tt; // expected-error{{template ty
template<template<typename T> class> struct X2tt; // expected-note{{previous template type parameter declared here}}
template<template<typename ...T> class> struct X2tt; // expected-error{{template type parameter pack conflicts with previous template type parameter}}
// FIXME: Add checks for non-type template parameter packs, template parameter packs

View File

@@ -8,3 +8,7 @@ struct X0;
template<int ...Values = 0> // expected-error{{template parameter pack cannot have a default argument}}
struct X1;
template<typename T> struct vector;
template<template<class> class ...Templates = vector> // expected-error{{template parameter pack cannot have a default argument}}
struct X2;