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).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163369 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d6ad8eb..1e81f0d 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1205,11 +1205,17 @@
/// 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 @@
} 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*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 @@
// 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 @@
// 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 @@
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 @@
++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 @@
/// 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 @@
<< Template;
}
+ TemplateParameterList *Params = Param->getTemplateParameters();
+ if (Param->isExpandedParameterPack())
+ Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
+
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
- Param->getTemplateParameters(),
+ Params,
true,
TPL_TemplateTemplateArgumentMatch,
Arg.getLocation());
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b8f0bca..b236f28 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -573,7 +573,7 @@
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;
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 28e4116..55462ff 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1657,7 +1657,7 @@
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 @@
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);