forked from OSchip/llvm-project
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:
parent
97158ca5c2
commit
1fde8ece37
|
@ -50,7 +50,11 @@ class TemplateParameterList {
|
||||||
|
|
||||||
/// The number of template parameters in this template
|
/// The number of template parameters in this template
|
||||||
/// parameter list.
|
/// parameter list.
|
||||||
unsigned NumParams;
|
unsigned NumParams : 31;
|
||||||
|
|
||||||
|
/// Whether this template parameter list contains an unexpanded parameter
|
||||||
|
/// pack.
|
||||||
|
unsigned ContainsUnexpandedParameterPack : 1;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
|
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
|
||||||
|
@ -104,6 +108,12 @@ public:
|
||||||
/// the second template parameter list will have depth 1, etc.
|
/// the second template parameter list will have depth 1, etc.
|
||||||
unsigned getDepth() const;
|
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 getTemplateLoc() const { return TemplateLoc; }
|
||||||
SourceLocation getLAngleLoc() const { return LAngleLoc; }
|
SourceLocation getLAngleLoc() const { return LAngleLoc; }
|
||||||
SourceLocation getRAngleLoc() const { return RAngleLoc; }
|
SourceLocation getRAngleLoc() const { return RAngleLoc; }
|
||||||
|
@ -1090,8 +1100,17 @@ public:
|
||||||
/// \endcode
|
/// \endcode
|
||||||
bool isParameterPack() const { return ParameterPack; }
|
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
|
/// \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
|
/// A parameter pack is an expanded parameter pack when the original
|
||||||
/// parameter pack's type was itself a pack expansion, and that expansion
|
/// 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.
|
/// \brief Whether this parameter is a parameter pack.
|
||||||
bool ParameterPack;
|
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,
|
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
|
||||||
unsigned D, unsigned P, bool ParameterPack,
|
unsigned D, unsigned P, bool ParameterPack,
|
||||||
IdentifierInfo *Id, TemplateParameterList *Params)
|
IdentifierInfo *Id, TemplateParameterList *Params)
|
||||||
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
|
||||||
TemplateParmPosition(D, P), DefaultArgument(),
|
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:
|
public:
|
||||||
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation L, unsigned D,
|
SourceLocation L, unsigned D,
|
||||||
unsigned P, bool ParameterPack,
|
unsigned P, bool ParameterPack,
|
||||||
IdentifierInfo *Id,
|
IdentifierInfo *Id,
|
||||||
TemplateParameterList *Params);
|
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);
|
unsigned ID);
|
||||||
|
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
|
||||||
|
unsigned ID,
|
||||||
|
unsigned NumExpansions);
|
||||||
|
|
||||||
using TemplateParmPosition::getDepth;
|
using TemplateParmPosition::getDepth;
|
||||||
using TemplateParmPosition::getPosition;
|
using TemplateParmPosition::getPosition;
|
||||||
|
@ -1195,6 +1238,49 @@ public:
|
||||||
/// \endcode
|
/// \endcode
|
||||||
bool isParameterPack() const { return ParameterPack; }
|
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
|
/// \brief Determine whether this template parameter has a default
|
||||||
/// argument.
|
/// argument.
|
||||||
bool hasDefaultArgument() const {
|
bool hasDefaultArgument() const {
|
||||||
|
|
|
@ -4832,7 +4832,8 @@ public:
|
||||||
TemplateArgument &Converted,
|
TemplateArgument &Converted,
|
||||||
CheckTemplateArgumentKind CTAK = CTAK_Specified);
|
CheckTemplateArgumentKind CTAK = CTAK_Specified);
|
||||||
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||||
const TemplateArgumentLoc &Arg);
|
const TemplateArgumentLoc &Arg,
|
||||||
|
unsigned ArgumentPackIndex);
|
||||||
|
|
||||||
ExprResult
|
ExprResult
|
||||||
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
|
BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg,
|
||||||
|
|
|
@ -945,6 +945,9 @@ namespace clang {
|
||||||
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
|
/// \brief A NonTypeTemplateParmDecl record that stores an expanded
|
||||||
/// non-type template parameter pack.
|
/// non-type template parameter pack.
|
||||||
DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_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
|
/// \brief A ClassScopeFunctionSpecializationDecl record a class scope
|
||||||
/// function specialization. (Microsoft extension).
|
/// function specialization. (Microsoft extension).
|
||||||
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
|
DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION,
|
||||||
|
|
|
@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
|
||||||
NamedDecl **Params, unsigned NumParams,
|
NamedDecl **Params, unsigned NumParams,
|
||||||
SourceLocation RAngleLoc)
|
SourceLocation RAngleLoc)
|
||||||
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
|
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
|
||||||
NumParams(NumParams) {
|
NumParams(NumParams), ContainsUnexpandedParameterPack(false) {
|
||||||
for (unsigned Idx = 0; Idx < NumParams; ++Idx)
|
assert(this->NumParams == NumParams && "Too many template parameters");
|
||||||
begin()[Idx] = Params[Idx];
|
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 *
|
TemplateParameterList *
|
||||||
|
@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const {
|
||||||
|
|
||||||
void TemplateTemplateParmDecl::anchor() { }
|
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 *
|
||||||
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
|
TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
|
||||||
SourceLocation L, unsigned D, unsigned P,
|
SourceLocation L, unsigned D, unsigned P,
|
||||||
|
@ -586,6 +615,19 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC,
|
||||||
Params);
|
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 *
|
||||||
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||||
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
|
void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl));
|
||||||
|
@ -593,6 +635,16 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) {
|
||||||
0, 0);
|
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
|
// TemplateArgumentList Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -1205,11 +1205,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S,
|
||||||
/// of a template template parameter, recursively.
|
/// of a template template parameter, recursively.
|
||||||
static bool DiagnoseUnexpandedParameterPacks(Sema &S,
|
static bool DiagnoseUnexpandedParameterPacks(Sema &S,
|
||||||
TemplateTemplateParmDecl *TTP) {
|
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();
|
TemplateParameterList *Params = TTP->getTemplateParameters();
|
||||||
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
|
for (unsigned I = 0, N = Params->size(); I != N; ++I) {
|
||||||
NamedDecl *P = Params->getParam(I);
|
NamedDecl *P = Params->getParam(I);
|
||||||
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
|
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) {
|
||||||
if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
|
if (!NTTP->isParameterPack() &&
|
||||||
|
S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(),
|
||||||
NTTP->getTypeSourceInfo(),
|
NTTP->getTypeSourceInfo(),
|
||||||
Sema::UPPC_NonTypeTemplateParameterType))
|
Sema::UPPC_NonTypeTemplateParameterType))
|
||||||
return true;
|
return true;
|
||||||
|
@ -1322,7 +1328,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
|
} else if (NonTypeTemplateParmDecl *NewNonTypeParm
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
|
= dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) {
|
||||||
// Check for unexpanded parameter packs.
|
// Check for unexpanded parameter packs.
|
||||||
if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
|
if (!NewNonTypeParm->isParameterPack() &&
|
||||||
|
DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(),
|
||||||
NewNonTypeParm->getTypeSourceInfo(),
|
NewNonTypeParm->getTypeSourceInfo(),
|
||||||
UPPC_NonTypeTemplateParameterType)) {
|
UPPC_NonTypeTemplateParameterType)) {
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
@ -1343,7 +1350,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
if (NewNonTypeParm->isParameterPack()) {
|
if (NewNonTypeParm->isParameterPack()) {
|
||||||
assert(!NewNonTypeParm->hasDefaultArgument() &&
|
assert(!NewNonTypeParm->hasDefaultArgument() &&
|
||||||
"Parameter packs can't have a default argument!");
|
"Parameter packs can't have a default argument!");
|
||||||
SawParameterPack = true;
|
if (!NewNonTypeParm->isPackExpansion())
|
||||||
|
SawParameterPack = true;
|
||||||
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
|
} else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() &&
|
||||||
NewNonTypeParm->hasDefaultArgument()) {
|
NewNonTypeParm->hasDefaultArgument()) {
|
||||||
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
|
OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc();
|
||||||
|
@ -1390,7 +1398,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
if (NewTemplateParm->isParameterPack()) {
|
if (NewTemplateParm->isParameterPack()) {
|
||||||
assert(!NewTemplateParm->hasDefaultArgument() &&
|
assert(!NewTemplateParm->hasDefaultArgument() &&
|
||||||
"Parameter packs can't have a default argument!");
|
"Parameter packs can't have a default argument!");
|
||||||
SawParameterPack = true;
|
if (!NewTemplateParm->isPackExpansion())
|
||||||
|
SawParameterPack = true;
|
||||||
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
|
} else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() &&
|
||||||
NewTemplateParm->hasDefaultArgument()) {
|
NewTemplateParm->hasDefaultArgument()) {
|
||||||
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
|
OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation();
|
||||||
|
@ -1417,7 +1426,7 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
MissingDefaultArg = true;
|
MissingDefaultArg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// C++0x [temp.param]p11:
|
// C++11 [temp.param]p11:
|
||||||
// If a template parameter of a primary class template or alias template
|
// If a template parameter of a primary class template or alias template
|
||||||
// is a template parameter pack, it shall be the last template parameter.
|
// is a template parameter pack, it shall be the last template parameter.
|
||||||
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
|
if (SawParameterPack && (NewParam + 1) != NewParamEnd &&
|
||||||
|
@ -2950,7 +2959,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
|
||||||
|
|
||||||
case TemplateArgument::Template:
|
case TemplateArgument::Template:
|
||||||
case TemplateArgument::TemplateExpansion:
|
case TemplateArgument::TemplateExpansion:
|
||||||
if (CheckTemplateArgument(TempParm, Arg))
|
if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Converted.push_back(Arg.getArgument());
|
Converted.push_back(Arg.getArgument());
|
||||||
|
@ -2999,6 +3008,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
|
||||||
return true;
|
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
|
/// \brief Check that the given template argument list is well-formed
|
||||||
/// for specializing the given template.
|
/// for specializing the given template.
|
||||||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
|
@ -3011,15 +3047,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
*ExpansionIntoFixedList = false;
|
*ExpansionIntoFixedList = false;
|
||||||
|
|
||||||
TemplateParameterList *Params = Template->getTemplateParameters();
|
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||||
unsigned NumParams = Params->size();
|
|
||||||
unsigned NumArgs = TemplateArgs.size();
|
|
||||||
bool Invalid = false;
|
|
||||||
|
|
||||||
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
|
SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc();
|
||||||
|
|
||||||
bool HasParameterPack =
|
|
||||||
NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack();
|
|
||||||
|
|
||||||
// C++ [temp.arg]p1:
|
// C++ [temp.arg]p1:
|
||||||
// [...] The type and form of each template-argument specified in
|
// [...] The type and form of each template-argument specified in
|
||||||
// a template-id shall match the type and form specified for the
|
// a template-id shall match the type and form specified for the
|
||||||
|
@ -3027,38 +3057,53 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
// template-parameter-list.
|
// template-parameter-list.
|
||||||
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
|
bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template);
|
||||||
SmallVector<TemplateArgument, 2> ArgumentPack;
|
SmallVector<TemplateArgument, 2> ArgumentPack;
|
||||||
TemplateParameterList::iterator Param = Params->begin(),
|
unsigned ArgIdx = 0, NumArgs = TemplateArgs.size();
|
||||||
ParamEnd = Params->end();
|
|
||||||
unsigned ArgIdx = 0;
|
|
||||||
LocalInstantiationScope InstScope(*this, true);
|
LocalInstantiationScope InstScope(*this, true);
|
||||||
bool SawPackExpansion = false;
|
for (TemplateParameterList::iterator Param = Params->begin(),
|
||||||
while (Param != ParamEnd) {
|
ParamEnd = Params->end();
|
||||||
if (ArgIdx < NumArgs) {
|
Param != ParamEnd; /* increment in loop */) {
|
||||||
// If we have an expanded parameter pack, make sure we don't have too
|
// If we have an expanded parameter pack, make sure we don't have too
|
||||||
// many arguments.
|
// many arguments.
|
||||||
// FIXME: This really should fall out from the normal arity checking.
|
if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) {
|
||||||
if (NonTypeTemplateParmDecl *NTTP
|
if (*Expansions == ArgumentPack.size()) {
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
// We're done with this parameter pack. Pack up its arguments and add
|
||||||
if (NTTP->isExpandedParameterPack() &&
|
// them to the list.
|
||||||
ArgumentPack.size() >= NTTP->getNumExpansionTypes()) {
|
if (ArgumentPack.empty())
|
||||||
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
|
Converted.push_back(TemplateArgument(0, 0));
|
||||||
<< true
|
else {
|
||||||
<< (isa<ClassTemplateDecl>(Template)? 0 :
|
Converted.push_back(
|
||||||
isa<FunctionTemplateDecl>(Template)? 1 :
|
TemplateArgument::CreatePackCopy(Context,
|
||||||
isa<TemplateTemplateParmDecl>(Template)? 2 : 3)
|
ArgumentPack.data(),
|
||||||
<< Template;
|
ArgumentPack.size()));
|
||||||
Diag(Template->getLocation(), diag::note_template_decl_here)
|
ArgumentPack.clear();
|
||||||
<< Params->getSourceRange();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
// 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.
|
// Check the template argument we were given.
|
||||||
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
|
if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template,
|
||||||
TemplateLoc, RAngleLoc,
|
TemplateLoc, RAngleLoc,
|
||||||
ArgumentPack.size(), Converted))
|
ArgumentPack.size(), Converted))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
// We're now done with this argument.
|
||||||
|
++ArgIdx;
|
||||||
|
|
||||||
if ((*Param)->isTemplateParameterPack()) {
|
if ((*Param)->isTemplateParameterPack()) {
|
||||||
// The template parameter was a template parameter pack, so take the
|
// The template parameter was a template parameter pack, so take the
|
||||||
// deduced argument and place it on the argument pack. Note that we
|
// deduced argument and place it on the argument pack. Note that we
|
||||||
|
@ -3071,15 +3116,50 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
++Param;
|
++Param;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this template argument is a pack expansion, record that fact
|
// If we just saw a pack expansion, then directly convert the remaining
|
||||||
// and break out; we can't actually check any more.
|
// arguments, because we don't know what parameters they'll match up
|
||||||
if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) {
|
// with.
|
||||||
SawPackExpansion = true;
|
if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) {
|
||||||
++ArgIdx;
|
bool InFinalParameterPack = Param != ParamEnd &&
|
||||||
break;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3090,13 +3170,33 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
ArgumentPack.data(),
|
ArgumentPack.data(),
|
||||||
ArgumentPack.size()));
|
ArgumentPack.size()));
|
||||||
|
|
||||||
return Invalid;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a template parameter pack with no more corresponding
|
// 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.
|
// arguments, just break out now and we'll fill in the argument pack below.
|
||||||
if ((*Param)->isTemplateParameterPack())
|
if ((*Param)->isTemplateParameterPack()) {
|
||||||
break;
|
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.
|
// Check whether we have a default argument.
|
||||||
TemplateArgumentLoc Arg;
|
TemplateArgumentLoc Arg;
|
||||||
|
@ -3184,86 +3284,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
++ArgIdx;
|
++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.
|
// If we have any leftover arguments, then there were too many arguments.
|
||||||
// Complain and fail.
|
// Complain and fail.
|
||||||
if (ArgIdx < NumArgs)
|
if (ArgIdx < NumArgs)
|
||||||
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
|
return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs);
|
||||||
|
|
||||||
// If we have an expanded parameter pack, make sure we don't have too
|
return false;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -4420,7 +4446,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
/// This routine implements the semantics of C++ [temp.arg.template].
|
/// This routine implements the semantics of C++ [temp.arg.template].
|
||||||
/// It returns true if an error occurred, and false otherwise.
|
/// It returns true if an error occurred, and false otherwise.
|
||||||
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||||
const TemplateArgumentLoc &Arg) {
|
const TemplateArgumentLoc &Arg,
|
||||||
|
unsigned ArgumentPackIndex) {
|
||||||
TemplateName Name = Arg.getArgument().getAsTemplate();
|
TemplateName Name = Arg.getArgument().getAsTemplate();
|
||||||
TemplateDecl *Template = Name.getAsTemplateDecl();
|
TemplateDecl *Template = Name.getAsTemplateDecl();
|
||||||
if (!Template) {
|
if (!Template) {
|
||||||
|
@ -4451,8 +4478,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
|
||||||
<< Template;
|
<< Template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TemplateParameterList *Params = Param->getTemplateParameters();
|
||||||
|
if (Param->isExpandedParameterPack())
|
||||||
|
Params = Param->getExpansionTemplateParameters(ArgumentPackIndex);
|
||||||
|
|
||||||
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
|
return !TemplateParameterListsAreEqual(Template->getTemplateParameters(),
|
||||||
Param->getTemplateParameters(),
|
Params,
|
||||||
true,
|
true,
|
||||||
TPL_TemplateTemplateArgumentMatch,
|
TPL_TemplateTemplateArgumentMatch,
|
||||||
Arg.getLocation());
|
Arg.getLocation());
|
||||||
|
|
|
@ -573,7 +573,7 @@ static void PrepareArgumentPackDeduction(Sema &S,
|
||||||
if (!S.CurrentInstantiationScope)
|
if (!S.CurrentInstantiationScope)
|
||||||
continue;
|
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.
|
// the set of deduced arguments.
|
||||||
const TemplateArgument *ExplicitArgs;
|
const TemplateArgument *ExplicitArgs;
|
||||||
unsigned NumExplicitArgs;
|
unsigned NumExplicitArgs;
|
||||||
|
|
|
@ -1657,7 +1657,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
||||||
IsExpandedParameterPack = true;
|
IsExpandedParameterPack = true;
|
||||||
DI = D->getTypeSourceInfo();
|
DI = D->getTypeSourceInfo();
|
||||||
T = DI->getType();
|
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.
|
// 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
|
// Determine whether we need to expand this parameter pack into separate
|
||||||
// types.
|
// types.
|
||||||
|
@ -1771,27 +1771,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
|
||||||
return Param;
|
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 *
|
Decl *
|
||||||
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
|
TemplateDeclInstantiator::VisitTemplateTemplateParmDecl(
|
||||||
TemplateTemplateParmDecl *D) {
|
TemplateTemplateParmDecl *D) {
|
||||||
// Instantiate the template parameter list of the template template parameter.
|
// Instantiate the template parameter list of the template template parameter.
|
||||||
TemplateParameterList *TempParams = D->getTemplateParameters();
|
TemplateParameterList *TempParams = D->getTemplateParameters();
|
||||||
TemplateParameterList *InstParams;
|
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,
|
// Perform the actual substitution of template parameters within a new,
|
||||||
// local instantiation scope.
|
// local instantiation scope.
|
||||||
LocalInstantiationScope Scope(SemaRef);
|
LocalInstantiationScope Scope(SemaRef);
|
||||||
InstParams = SubstTemplateParams(TempParams);
|
InstParams = SubstTemplateParams(TempParams);
|
||||||
if (!InstParams)
|
if (!InstParams)
|
||||||
return NULL;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build the template template parameter.
|
// Build the template template parameter.
|
||||||
TemplateTemplateParmDecl *Param
|
TemplateTemplateParmDecl *Param;
|
||||||
= TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(),
|
if (IsExpandedParameterPack)
|
||||||
|
Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner,
|
||||||
|
D->getLocation(),
|
||||||
D->getDepth() - TemplateArgs.getNumLevels(),
|
D->getDepth() - TemplateArgs.getNumLevels(),
|
||||||
D->getPosition(), D->isParameterPack(),
|
D->getPosition(),
|
||||||
D->getIdentifier(), InstParams);
|
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->setDefaultArgument(D->getDefaultArgument(), false);
|
||||||
Param->setAccess(AS_public);
|
Param->setAccess(AS_public);
|
||||||
|
|
||||||
|
|
|
@ -1486,11 +1486,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
|
||||||
// TemplateParmPosition.
|
// TemplateParmPosition.
|
||||||
D->setDepth(Record[Idx++]);
|
D->setDepth(Record[Idx++]);
|
||||||
D->setPosition(Record[Idx++]);
|
D->setPosition(Record[Idx++]);
|
||||||
// Rest of TemplateTemplateParmDecl.
|
if (D->isExpandedParameterPack()) {
|
||||||
TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx);
|
void **Data = reinterpret_cast<void **>(D + 1);
|
||||||
bool IsInherited = Record[Idx++];
|
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
|
||||||
D->setDefaultArgument(Arg, IsInherited);
|
I != N; ++I)
|
||||||
D->ParameterPack = Record[Idx++];
|
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) {
|
void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
|
||||||
|
@ -2004,6 +2011,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
|
||||||
case DECL_TEMPLATE_TEMPLATE_PARM:
|
case DECL_TEMPLATE_TEMPLATE_PARM:
|
||||||
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
|
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID);
|
||||||
break;
|
break;
|
||||||
|
case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK:
|
||||||
|
D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID,
|
||||||
|
Record[Idx++]);
|
||||||
|
break;
|
||||||
case DECL_TYPE_ALIAS_TEMPLATE:
|
case DECL_TYPE_ALIAS_TEMPLATE:
|
||||||
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
|
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1172,7 +1172,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) {
|
||||||
|
|
||||||
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
||||||
// For an expanded parameter pack, record the number of expansion types here
|
// 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())
|
if (D->isExpandedParameterPack())
|
||||||
Record.push_back(D->getNumExpansionTypes());
|
Record.push_back(D->getNumExpansionTypes());
|
||||||
|
|
||||||
|
@ -1201,15 +1202,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *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);
|
VisitTemplateDecl(D);
|
||||||
// TemplateParmPosition.
|
// TemplateParmPosition.
|
||||||
Record.push_back(D->getDepth());
|
Record.push_back(D->getDepth());
|
||||||
Record.push_back(D->getPosition());
|
Record.push_back(D->getPosition());
|
||||||
// Rest of TemplateTemplateParmDecl.
|
|
||||||
Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record);
|
if (D->isExpandedParameterPack()) {
|
||||||
Record.push_back(D->defaultArgumentWasInherited());
|
for (unsigned I = 0, N = D->getNumExpansionTemplateParameters();
|
||||||
Record.push_back(D->isParameterPack());
|
I != N; ++I)
|
||||||
Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM;
|
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) {
|
void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) {
|
||||||
|
|
|
@ -22,3 +22,153 @@ void f(const X<int> x) {
|
||||||
|
|
||||||
template<typename T = void> struct X1 { };
|
template<typename T = void> struct X1 { };
|
||||||
X1<X1<>> x1a;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -9,3 +9,7 @@
|
||||||
|
|
||||||
// CHECK: allocate_shared
|
// CHECK: allocate_shared
|
||||||
shared_ptr<int> spi = shared_ptr<int>::allocate_shared(1, 2);
|
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>{});
|
||||||
|
|
|
@ -16,3 +16,10 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args)
|
||||||
shared_ptr<_Tp> __r;
|
shared_ptr<_Tp> __r;
|
||||||
return __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>;
|
||||||
|
|
Loading…
Reference in New Issue