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
clang
include/clang
lib
AST
Sema
Serialization
test
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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>{});
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Reference in New Issue