PR9023: A template template parameter whose template parameter list contains an

unexpanded parameter pack is a pack expansion. Thus, as with a non-type template
parameter which is a pack expansion, it needs to be expanded early into a fixed
list of template parameters.

Since the expanded list of template parameters is not itself a parameter pack,
it is permitted to appear before the end of the template parameter list, so also
remove that restriction (for both template template parameter pack expansions and
non-type template parameter pack expansions).

llvm-svn: 163369
This commit is contained in:
Richard Smith 2012-09-07 02:06:42 +00:00
parent 97158ca5c2
commit 1fde8ece37
12 changed files with 607 additions and 152 deletions

View File

@ -50,7 +50,11 @@ class TemplateParameterList {
/// The number of template parameters in this template
/// parameter list.
unsigned NumParams;
unsigned NumParams : 31;
/// Whether this template parameter list contains an unexpanded parameter
/// pack.
unsigned ContainsUnexpandedParameterPack : 1;
protected:
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
@ -104,6 +108,12 @@ public:
/// the second template parameter list will have depth 1, etc.
unsigned getDepth() const;
/// \brief Determine whether this template parameter list contains an
/// unexpanded parameter pack.
bool containsUnexpandedParameterPack() const {
return ContainsUnexpandedParameterPack;
}
SourceLocation getTemplateLoc() const { return TemplateLoc; }
SourceLocation getLAngleLoc() const { return LAngleLoc; }
SourceLocation getRAngleLoc() const { return RAngleLoc; }
@ -1090,8 +1100,17 @@ public:
/// \endcode
bool isParameterPack() const { return ParameterPack; }
/// \brief Whether this parameter pack is a pack expansion.
///
/// A non-type template parameter pack is a pack expansion if its type
/// contains an unexpanded parameter pack. In this case, we will have
/// built a PackExpansionType wrapping the type.
bool isPackExpansion() const {
return ParameterPack && getType()->getAs<PackExpansionType>();
}
/// \brief Whether this parameter is a non-type template parameter pack
/// that has different types at different positions.
/// that has a known list of different types at different positions.
///
/// A parameter pack is an expanded parameter pack when the original
/// parameter pack's type was itself a pack expansion, and that expansion
@ -1165,23 +1184,47 @@ class TemplateTemplateParmDecl : public TemplateDecl,
/// \brief Whether this parameter is a parameter pack.
bool ParameterPack;
/// \brief Whether this template template parameter is an "expanded"
/// parameter pack, meaning that it is a pack expansion and we
/// already know the set of template parameters that expansion expands to.
bool ExpandedParameterPack;
/// \brief The number of parameters in an expanded parameter pack.
unsigned NumExpandedParams;
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P, bool ParameterPack,
IdentifierInfo *Id, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), DefaultArgument(),
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack)
DefaultArgumentWasInherited(false), ParameterPack(ParameterPack),
ExpandedParameterPack(false), NumExpandedParams(0)
{ }
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params,
unsigned NumExpansions,
TemplateParameterList * const *Expansions);
public:
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, bool ParameterPack,
IdentifierInfo *Id,
TemplateParameterList *Params);
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
llvm::ArrayRef<TemplateParameterList*> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID,
unsigned NumExpansions);
using TemplateParmPosition::getDepth;
using TemplateParmPosition::getPosition;
@ -1195,6 +1238,49 @@ public:
/// \endcode
bool isParameterPack() const { return ParameterPack; }
/// \brief Whether this parameter pack is a pack expansion.
///
/// A template template parameter pack is a pack expansion if its template
/// parameter list contains an unexpanded parameter pack.
bool isPackExpansion() const {
return ParameterPack &&
getTemplateParameters()->containsUnexpandedParameterPack();
}
/// \brief Whether this parameter is a template template parameter pack that
/// has a known list of different template parameter lists at different
/// positions.
///
/// A parameter pack is an expanded parameter pack when the original parameter
/// pack's template parameter list was itself a pack expansion, and that
/// expansion has already been expanded. For exampe, given:
///
/// \code
/// template<typename...Types> struct Outer {
/// template<template<Types> class...Templates> struct Inner;
/// };
/// \endcode
///
/// The parameter pack \c Templates is a pack expansion, which expands the
/// pack \c Types. When \c Types is supplied with template arguments by
/// instantiating \c Outer, the instantiation of \c Templates is an expanded
/// parameter pack.
bool isExpandedParameterPack() const { return ExpandedParameterPack; }
/// \brief Retrieves the number of expansion template parameters in
/// an expanded parameter pack.
unsigned getNumExpansionTemplateParameters() const {
assert(ExpandedParameterPack && "Not an expansion parameter pack");
return NumExpandedParams;
}
/// \brief Retrieve a particular expansion type within an expanded parameter
/// pack.
TemplateParameterList *getExpansionTemplateParameters(unsigned I) const {
assert(I < NumExpandedParams && "Out-of-range expansion type index");
return reinterpret_cast<TemplateParameterList *const *>(this + 1)[I];
}
/// \brief Determine whether this template parameter has a default
/// argument.
bool hasDefaultArgument() const {

View File

@ -4832,7 +4832,8 @@ public:
TemplateArgument &Converted,
CheckTemplateArgumentKind CTAK = CTAK_Specified);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg);
const TemplateArgumentLoc &Arg,
unsigned ArgumentPackIndex);
ExprResult
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,

View File

@ -945,6 +945,9 @@ namespace clang {
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
/// non-type template parameter pack.
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
/// \brief A TemplateTemplateParmDecl record that stores an expanded
/// template template parameter pack.
DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK,
/// \brief A ClassScopeFunctionSpecializationDecl record a class scope
/// function specialization. (Microsoft extension).
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,

View File

@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(NumParams) {
for (unsigned Idx = 0; Idx < NumParams; ++Idx)
begin()[Idx] = Params[Idx];
NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
assert(this->NumParams == NumParams && "Too many template parameters");
for (unsigned Idx = 0; Idx < NumParams; ++Idx) {
NamedDecl *P = Params[Idx];
begin()[Idx] = P;
if (!P->isTemplateParameterPack()) {
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P))
if (NTTP->getType()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P))
if (TTP->getTemplateParameters()->containsUnexpandedParameterPack())
ContainsUnexpandedParameterPack = true;
// FIXME: If a default argument contains an unexpanded parameter pack, the
// template parameter list does too.
}
}
}
TemplateParameterList *
@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
void TemplateTemplateParmDecl::anchor() { }
TemplateTemplateParmDecl::TemplateTemplateParmDecl(
DeclContext *DC, SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id, TemplateParameterList *Params,
unsigned NumExpansions, TemplateParameterList * const *Expansions)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
TemplateParmPosition(D, P), DefaultArgument(),
DefaultArgumentWasInherited(false), ParameterPack(true),
ExpandedParameterPack(true), NumExpandedParams(NumExpansions) {
if (Expansions)
std::memcpy(reinterpret_cast<void*>(this + 1), Expansions,
sizeof(TemplateParameterList*) * NumExpandedParams);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
@ -586,6 +615,19 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
Params);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D, unsigned P,
IdentifierInfo *Id,
TemplateParameterList *Params,
llvm::ArrayRef<TemplateParameterList*> Expansions) {
void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) +
sizeof(TemplateParameterList*) * Expansions.size());
return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params,
Expansions.size(),
Expansions.data());
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
@ -593,6 +635,16 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
0, 0);
}
TemplateTemplateParmDecl *
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID,
unsigned NumExpansions) {
unsigned Size = sizeof(TemplateTemplateParmDecl) +
sizeof(TemplateParameterList*) * NumExpansions;
void *Mem = AllocateDeserializedDecl(C, ID, Size);
return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0,
NumExpansions, 0);
}
//===----------------------------------------------------------------------===//
// TemplateArgumentList Implementation
//===----------------------------------------------------------------------===//

View File

@ -1205,11 +1205,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
/// of a template template parameter, recursively.
static bool DiagnoseUnexpandedParameterPacks(Sema &S,
TemplateTemplateParmDecl *TTP) {
// A template template parameter which is a parameter pack is also a pack
// expansion.
if (TTP->isParameterPack())
return false;
TemplateParameterList *Params = TTP->getTemplateParameters();
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
NamedDecl *P = Params->getParam(I);
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
if (!NTTP->isParameterPack() &&
S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
NTTP->getTypeSourceInfo(),
Sema::UPPC_NonTypeTemplateParameterType))
return true;
@ -1322,7 +1328,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
// Check for unexpanded parameter packs.
if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
if (!NewNonTypeParm->isParameterPack() &&
DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
NewNonTypeParm->getTypeSourceInfo(),
UPPC_NonTypeTemplateParameterType)) {
Invalid = true;
@ -1343,7 +1350,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewNonTypeParm->isParameterPack()) {
assert(!NewNonTypeParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
if (!NewNonTypeParm->isPackExpansion())
SawParameterPack = true;
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
NewNonTypeParm->hasDefaultArgument()) {
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
@ -1390,7 +1398,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
if (NewTemplateParm->isParameterPack()) {
assert(!NewTemplateParm->hasDefaultArgument() &&
"Parameter packs can't have a default argument!");
SawParameterPack = true;
if (!NewTemplateParm->isPackExpansion())
SawParameterPack = true;
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
NewTemplateParm->hasDefaultArgument()) {
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
@ -1417,10 +1426,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
MissingDefaultArg = true;
}
// C++0x [temp.param]p11:
// C++11 [temp.param]p11:
// If a template parameter of a primary class template or alias template
// is a template parameter pack, it shall be the last template parameter.
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
(TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) {
Diag((*NewParam)->getLocation(),
diag::err_template_param_pack_must_be_last_template_parameter);
@ -2950,7 +2959,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (CheckTemplateArgument(TempParm, Arg))
if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex))
return true;
Converted.push_back(Arg.getArgument());
@ -2999,6 +3008,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
return true;
}
/// \brief Check whether the template parameter is a pack expansion, and if so,
/// determine the number of parameters produced by that expansion. For instance:
///
/// \code
/// template<typename ...Ts> struct A {
/// template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B;
/// };
/// \endcode
///
/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us
/// is not a pack expansion, so returns an empty Optional.
static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Param)) {
if (NTTP->isExpandedParameterPack())
return NTTP->getNumExpansionTypes();
}
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(Param)) {
if (TTP->isExpandedParameterPack())
return TTP->getNumExpansionTemplateParameters();
}
return llvm::Optional<unsigned>();
}
/// \brief Check that the given template argument list is well-formed
/// for specializing the given template.
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
@ -3011,15 +3047,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
*ExpansionIntoFixedList = false;
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
unsigned NumArgs = TemplateArgs.size();
bool Invalid = false;
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
bool HasParameterPack =
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
// C++ [temp.arg]p1:
// [...] The type and form of each template-argument specified in
// a template-id shall match the type and form specified for the
@ -3027,38 +3057,53 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// template-parameter-list.
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
SmallVector<TemplateArgument, 2> ArgumentPack;
TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
unsigned ArgIdx = 0;
unsigned ArgIdx = 0, NumArgs = TemplateArgs.size();
LocalInstantiationScope InstScope(*this, true);
bool SawPackExpansion = false;
while (Param != ParamEnd) {
if (ArgIdx < NumArgs) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
// FIXME: This really should fall out from the normal arity checking.
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (NTTP->isExpandedParameterPack() &&
ArgumentPack.size() >= NTTP->getNumExpansionTypes()) {
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< true
<< (isa<ClassTemplateDecl>(Template)? 0 :
isa<FunctionTemplateDecl>(Template)? 1 :
isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
<< Template;
Diag(Template->getLocation(), diag::note_template_decl_here)
<< Params->getSourceRange();
return true;
for (TemplateParameterList::iterator Param = Params->begin(),
ParamEnd = Params->end();
Param != ParamEnd; /* increment in loop */) {
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
if (*Expansions == ArgumentPack.size()) {
// We're done with this parameter pack. Pack up its arguments and add
// them to the list.
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(
TemplateArgument::CreatePackCopy(Context,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
}
// This argument is assigned to the next parameter.
++Param;
continue;
} else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
// Not enough arguments for this parameter pack.
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< false
<< (isa<ClassTemplateDecl>(Template)? 0 :
isa<FunctionTemplateDecl>(Template)? 1 :
isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
<< Template;
Diag(Template->getLocation(), diag::note_template_decl_here)
<< Params->getSourceRange();
return true;
}
}
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
TemplateLoc, RAngleLoc,
ArgumentPack.size(), Converted))
return true;
// We're now done with this argument.
++ArgIdx;
if ((*Param)->isTemplateParameterPack()) {
// The template parameter was a template parameter pack, so take the
// deduced argument and place it on the argument pack. Note that we
@ -3070,16 +3115,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// Move to the next template parameter.
++Param;
}
// If this template argument is a pack expansion, record that fact
// and break out; we can't actually check any more.
if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
SawPackExpansion = true;
++ArgIdx;
break;
// If we just saw a pack expansion, then directly convert the remaining
// arguments, because we don't know what parameters they'll match up
// with.
if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) {
bool InFinalParameterPack = Param != ParamEnd &&
Param + 1 == ParamEnd &&
(*Param)->isTemplateParameterPack() &&
!getExpandedPackSize(*Param);
if (!InFinalParameterPack && !ArgumentPack.empty()) {
// If we were part way through filling in an expanded parameter pack,
// fall back to just producing individual arguments.
Converted.insert(Converted.end(),
ArgumentPack.begin(), ArgumentPack.end());
ArgumentPack.clear();
}
while (ArgIdx < NumArgs) {
if (InFinalParameterPack)
ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
else
Converted.push_back(TemplateArgs[ArgIdx].getArgument());
++ArgIdx;
}
// Push the argument pack onto the list of converted arguments.
if (InFinalParameterPack) {
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(
TemplateArgument::CreatePackCopy(Context,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
}
} else if (ExpansionIntoFixedList) {
// We have expanded a pack into a fixed list.
*ExpansionIntoFixedList = true;
}
return false;
}
++ArgIdx;
continue;
}
@ -3090,14 +3170,34 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
ArgumentPack.data(),
ArgumentPack.size()));
return Invalid;
return false;
}
// If we have a template parameter pack with no more corresponding
// arguments, just break out now and we'll fill in the argument pack below.
if ((*Param)->isTemplateParameterPack())
break;
if ((*Param)->isTemplateParameterPack()) {
assert(!getExpandedPackSize(*Param) &&
"Should have dealt with this already");
// A non-expanded parameter pack before the end of the parameter list
// only occurs for an ill-formed template parameter list, unless we've
// got a partial argument list for a function template, so just bail out.
if (Param + 1 != ParamEnd)
return true;
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(TemplateArgument::CreatePackCopy(Context,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
}
++Param;
continue;
}
// Check whether we have a default argument.
TemplateArgumentLoc Arg;
@ -3184,86 +3284,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
++ArgIdx;
}
// If we saw a pack expansion, then directly convert the remaining arguments,
// because we don't know what parameters they'll match up with.
if (SawPackExpansion) {
bool AddToArgumentPack
= Param != ParamEnd && (*Param)->isTemplateParameterPack();
while (ArgIdx < NumArgs) {
if (AddToArgumentPack)
ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument());
else
Converted.push_back(TemplateArgs[ArgIdx].getArgument());
++ArgIdx;
}
// Push the argument pack onto the list of converted arguments.
if (AddToArgumentPack) {
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(
TemplateArgument::CreatePackCopy(Context,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
}
} else if (ExpansionIntoFixedList) {
// We have expanded a pack into a fixed list.
*ExpansionIntoFixedList = true;
}
return Invalid;
}
// If we have any leftover arguments, then there were too many arguments.
// Complain and fail.
if (ArgIdx < NumArgs)
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
// If we have an expanded parameter pack, make sure we don't have too
// many arguments.
// FIXME: This really should fall out from the normal arity checking.
if (Param != ParamEnd) {
if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (NTTP->isExpandedParameterPack() &&
ArgumentPack.size() < NTTP->getNumExpansionTypes()) {
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
<< false
<< (isa<ClassTemplateDecl>(Template)? 0 :
isa<FunctionTemplateDecl>(Template)? 1 :
isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
<< Template;
Diag(Template->getLocation(), diag::note_template_decl_here)
<< Params->getSourceRange();
return true;
}
}
}
// Form argument packs for each of the parameter packs remaining.
while (Param != ParamEnd) {
// If we're checking a partial list of template arguments, don't fill
// in arguments for non-template parameter packs.
if ((*Param)->isTemplateParameterPack()) {
if (!HasParameterPack)
return true;
if (ArgumentPack.empty())
Converted.push_back(TemplateArgument(0, 0));
else {
Converted.push_back(TemplateArgument::CreatePackCopy(Context,
ArgumentPack.data(),
ArgumentPack.size()));
ArgumentPack.clear();
}
} else if (!PartialTemplateArgs)
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
++Param;
}
return Invalid;
return false;
}
namespace {
@ -4420,7 +4446,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
/// This routine implements the semantics of C++ [temp.arg.template].
/// It returns true if an error occurred, and false otherwise.
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
const TemplateArgumentLoc &Arg) {
const TemplateArgumentLoc &Arg,
unsigned ArgumentPackIndex) {
TemplateName Name = Arg.getArgument().getAsTemplate();
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template) {
@ -4451,8 +4478,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
<< Template;
}
TemplateParameterList *Params = Param->getTemplateParameters();
if (Param->isExpandedParameterPack())
Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
Param->getTemplateParameters(),
Params,
true,
TPL_TemplateTemplateArgumentMatch,
Arg.getLocation());

View File

@ -573,7 +573,7 @@ static void PrepareArgumentPackDeduction(Sema &S,
if (!S.CurrentInstantiationScope)
continue;
// If the template arugment pack was explicitly specified, add that to
// If the template argument pack was explicitly specified, add that to
// the set of deduced arguments.
const TemplateArgument *ExplicitArgs;
unsigned NumExplicitArgs;

View File

@ -1657,7 +1657,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
IsExpandedParameterPack = true;
DI = D->getTypeSourceInfo();
T = DI->getType();
} else if (isa<PackExpansionTypeLoc>(TL)) {
} else if (D->isPackExpansion()) {
// The non-type template parameter pack's type is a pack expansion of types.
// Determine whether we need to expand this parameter pack into separate
// types.
@ -1771,27 +1771,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
return Param;
}
static void collectUnexpandedParameterPacks(
Sema &S,
TemplateParameterList *Params,
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) {
for (TemplateParameterList::const_iterator I = Params->begin(),
E = Params->end(); I != E; ++I) {
if ((*I)->isTemplateParameterPack())
continue;
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I))
S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(),
Unexpanded);
if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I))
collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(),
Unexpanded);
}
}
Decl *
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
TemplateTemplateParmDecl *D) {
// Instantiate the template parameter list of the template template parameter.
TemplateParameterList *TempParams = D->getTemplateParameters();
TemplateParameterList *InstParams;
{
SmallVector<TemplateParameterList*, 8> ExpandedParams;
bool IsExpandedParameterPack = false;
if (D->isExpandedParameterPack()) {
// The template template parameter pack is an already-expanded pack
// expansion of template parameters. Substitute into each of the expanded
// parameters.
ExpandedParams.reserve(D->getNumExpansionTemplateParameters());
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I) {
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *Expansion =
SubstTemplateParams(D->getExpansionTemplateParameters(I));
if (!Expansion)
return 0;
ExpandedParams.push_back(Expansion);
}
IsExpandedParameterPack = true;
InstParams = TempParams;
} else if (D->isPackExpansion()) {
// The template template parameter pack expands to a pack of template
// template parameters. Determine whether we need to expand this parameter
// pack into separate parameters.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(),
Unexpanded);
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(),
TempParams->getSourceRange(),
Unexpanded,
TemplateArgs,
Expand, RetainExpansion,
NumExpansions))
return 0;
if (Expand) {
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I);
LocalInstantiationScope Scope(SemaRef);
TemplateParameterList *Expansion = SubstTemplateParams(TempParams);
if (!Expansion)
return 0;
ExpandedParams.push_back(Expansion);
}
// Note that we have an expanded parameter pack. The "type" of this
// expanded parameter pack is the original expansion type, but callers
// will end up using the expanded parameter pack types for type-checking.
IsExpandedParameterPack = true;
InstParams = TempParams;
} else {
// We cannot fully expand the pack expansion now, so just substitute
// into the pattern.
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1);
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return 0;
}
} else {
// Perform the actual substitution of template parameters within a new,
// local instantiation scope.
LocalInstantiationScope Scope(SemaRef);
InstParams = SubstTemplateParams(TempParams);
if (!InstParams)
return NULL;
return 0;
}
// Build the template template parameter.
TemplateTemplateParmDecl *Param
= TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
TemplateTemplateParmDecl *Param;
if (IsExpandedParameterPack)
Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
D->getPosition(), D->isParameterPack(),
D->getIdentifier(), InstParams);
D->getPosition(),
D->getIdentifier(), InstParams,
ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
D->getLocation(),
D->getDepth() - TemplateArgs.getNumLevels(),
D->getPosition(),
D->isParameterPack(),
D->getIdentifier(), InstParams);
Param->setDefaultArgument(D->getDefaultArgument(), false);
Param->setAccess(AS_public);

View File

@ -1486,11 +1486,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// TemplateParmPosition.
D->setDepth(Record[Idx++]);
D->setPosition(Record[Idx++]);
// Rest of TemplateTemplateParmDecl.
TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
bool IsInherited = Record[Idx++];
D->setDefaultArgument(Arg, IsInherited);
D->ParameterPack = Record[Idx++];
if (D->isExpandedParameterPack()) {
void **Data = reinterpret_cast<void **>(D + 1);
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I)
Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx);
} else {
// Rest of TemplateTemplateParmDecl.
TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
bool IsInherited = Record[Idx++];
D->setDefaultArgument(Arg, IsInherited);
D->ParameterPack = Record[Idx++];
}
}
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
@ -2004,6 +2011,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
case DECL_TEMPLATE_TEMPLATE_PARM:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
break;
case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
Record[Idx++]);
break;
case DECL_TYPE_ALIAS_TEMPLATE:
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;

View File

@ -1172,7 +1172,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
// so that it's easier for
// so that it's easier for deserialization to allocate the right amount of
// memory.
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTypes());
@ -1201,15 +1202,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
}
void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
// For an expanded parameter pack, record the number of expansion types here
// so that it's easier for deserialization to allocate the right amount of
// memory.
if (D->isExpandedParameterPack())
Record.push_back(D->getNumExpansionTemplateParameters());
VisitTemplateDecl(D);
// TemplateParmPosition.
Record.push_back(D->getDepth());
Record.push_back(D->getPosition());
// Rest of TemplateTemplateParmDecl.
Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
Record.push_back(D->defaultArgumentWasInherited());
Record.push_back(D->isParameterPack());
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
if (D->isExpandedParameterPack()) {
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
I != N; ++I)
Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I),
Record);
Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK;
} else {
// Rest of TemplateTemplateParmDecl.
Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
Record.push_back(D->defaultArgumentWasInherited());
Record.push_back(D->isParameterPack());
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
}
}
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {

View File

@ -22,3 +22,153 @@ void f(const X<int> x) {
template<typename T = void> struct X1 { };
X1<X1<>> x1a;
namespace ParameterPackExpansions {
// A template parameter pack that [contains an unexpanded parameter pack] is a
// pack expansion.
template<typename...Ts> struct Outer {
// From [temp.variadic]p4:
// In a template parameter pack that is a pack expansion, the pattern is
// [...the template-parameter...] without the ellipsis.
// Therefore the resulting sequence of parameters is not a parameter pack,
// so is not required to be the last template parameter.
template<Ts ...As, template<Ts> class ...Bs, typename ...Cs> struct Inner {
struct Check : Bs<As>... {
Check(Cs...);
};
};
};
template<int> struct TemplateInt {};
template<char> struct TemplateChar {};
template<int*> struct TemplateIntPtr {};
int x;
Outer<int, char, int*>::
Inner<12345, 'x', &x,
TemplateInt, TemplateChar, TemplateIntPtr,
int*>::
Check check(&x);
template<typename...Ts> struct types;
enum place { _ };
template<place...> struct places {};
template<typename P1, typename P2> struct append_places;
template<place...X1, place...X2>
struct append_places<places<X1...>, places<X2...>> {
typedef places<X1...,X2...> type;
};
template<unsigned N>
struct make_places : append_places<typename make_places<N/2>::type,
typename make_places<N-N/2>::type> {};
template<> struct make_places<0> { typedef places<> type; };
template<> struct make_places<1> { typedef places<_> type; };
template<typename T> struct wrap {
template<place> struct inner { typedef T type; };
};
template<typename T> struct takedrop_impl;
template<place...X> struct takedrop_impl<places<X...>> {
template<template<decltype(X)> class ...Take,
template<place > class ...Drop>
struct inner { // expected-note 2{{declared}}
typedef types<typename Take<_>::type...> take;
typedef types<typename Drop<_>::type...> drop;
};
};
template<unsigned N, typename...Ts> struct take {
using type = typename takedrop_impl<typename make_places<N>::type>::
template inner<wrap<Ts>::template inner...>::take; // expected-error {{too few template arguments}}
};
template<unsigned N, typename...Ts> struct drop {
using type = typename takedrop_impl<typename make_places<N>::type>::
template inner<wrap<Ts>::template inner...>::drop; // expected-error {{too few template arguments}}
};
using T1 = take<3, int, char, double, long>::type; // expected-note {{previous}}
using T1 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<int, char, double, (no argument)>'}}
using D1 = drop<3, int, char, double, long>::type;
using D1 = types<long>;
using T2 = take<4, int, char, double, long>::type; // expected-note {{previous}}
using T2 = types<int, char, double, long>;
using T2 = types<void, void, void, void>; // expected-error {{'types<void, void, void, void>' vs 'types<int, char, double, long>'}}
using D2 = drop<4, int, char, double, long>::type;
using D2 = types<>;
using T3 = take<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
using D3 = drop<5, int, char, double, long>::type; // expected-note {{in instantiation of}}
// FIXME: We should accept this code. A parameter pack within a default argument
// in a template template parameter pack is expanded, because the pack is
// implicitly a pack expansion.
template<typename ...Default> struct DefArg {
template<template<typename T = Default> class ...Classes> struct Inner { // expected-error {{default argument contains unexpanded parameter pack}} expected-note {{here}}
Inner(Classes<>...); // expected-error {{too few}}
};
};
template<typename T> struct vector {};
template<typename T> struct list {};
vector<int> vi;
list<char> lc;
DefArg<int, char>::Inner<vector, list> defarg(vi, lc);
// FIXME:
// A template parameter pack that is a pack expansion shall not expand a
// parameter pack declared in the same template-parameter-list.
template<typename...Ts, Ts...Vs> void error(); // desired-error
// This case should not produce an error, because in A's instantiation, Cs is
// not a parameter pack.
template<typename...Ts> void consume(Ts...);
template<typename...Ts> struct A {
template<template<typename, Ts = 0> class ...Cs, Cs<Ts> ...Vs> struct B { // ok
B() {
consume([]{
int arr[Vs]; // expected-error {{negative size}}
}...);
}
};
};
template<typename, int> using Int = int;
template<typename, short> using Char = char;
A<int, short>::B<Int, Char, -1, 'x'> b; // expected-note {{here}}
}
namespace PR9023 {
template<typename ...T> struct A {
template<template<T> class ...> struct B {
};
};
template<int> struct C { };
template<long> struct D { };
int main() {
A<int, long>::B<C, D> e;
}
}
namespace std_examples {
template <class... Types> class Tuple;
template <class T, int... Dims> struct multi_array;
template <class... T> struct value_holder {
template<T... Values> struct apply { };
};
template <class... T, T... Values> struct static_array; // expected-error {{must be the last}}
int n;
value_holder<int, char, int*>::apply<12345, 'x', &n> test;
}

View File

@ -9,3 +9,7 @@
// CHECK: allocate_shared
shared_ptr<int> spi = shared_ptr<int>::allocate_shared(1, 2);
template<int> struct A {};
template<int> struct B {};
outer<int, int>::inner<1, 2, A, B> i(A<1>{}, B<2>{});

View File

@ -16,3 +16,10 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args)
shared_ptr<_Tp> __r;
return __r;
}
template<typename...Ts> struct outer {
template<Ts...Vs, template<Ts> class ...Cs> struct inner {
inner(Cs<Vs>...);
};
};
template struct outer<int, int>;