forked from OSchip/llvm-project
Implement substitution of a function parameter pack for its set of
instantiated function parameters, enabling instantiation of arbitrary pack expansions involving function parameter packs. At this point, we can now correctly compile a simple, variadic print() example: #include <iostream> #include <string> void print() {} template<typename Head, typename ...Tail> void print(const Head &head, const Tail &...tail) { std::cout << head; print(tail...); } int main() { std::string hello = "Hello"; print(hello, ", world!", " ", 2011, '\n'); } llvm-svn: 123000
This commit is contained in:
parent
1ec7ecce86
commit
f30101186f
|
@ -3893,7 +3893,8 @@ public:
|
|||
bool SubstParmTypes(SourceLocation Loc,
|
||||
ParmVarDecl **Params, unsigned NumParams,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
llvm::SmallVectorImpl<QualType> &ParamTypes);
|
||||
llvm::SmallVectorImpl<QualType> &ParamTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl *> *OutParams = 0);
|
||||
ExprResult SubstExpr(Expr *E,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs);
|
||||
|
||||
|
|
|
@ -166,10 +166,19 @@ namespace clang {
|
|||
/// instantiate a new function declaration, which will have its own
|
||||
/// set of parameter declarations.
|
||||
class LocalInstantiationScope {
|
||||
public:
|
||||
/// \brief A set of declarations.
|
||||
typedef llvm::SmallVector<Decl *, 4> DeclArgumentPack;
|
||||
|
||||
private:
|
||||
/// \brief Reference to the semantic analysis that is performing
|
||||
/// this template instantiation.
|
||||
Sema &SemaRef;
|
||||
|
||||
typedef llvm::DenseMap<const Decl *,
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> >
|
||||
LocalDeclsMap;
|
||||
|
||||
/// \brief A mapping from local declarations that occur
|
||||
/// within a template to their instantiations.
|
||||
///
|
||||
|
@ -184,8 +193,15 @@ namespace clang {
|
|||
/// when we instantiate add<int>, we will introduce a mapping from
|
||||
/// the ParmVarDecl for 'x' that occurs in the template to the
|
||||
/// instantiated ParmVarDecl for 'x'.
|
||||
llvm::DenseMap<const Decl *, Decl *> LocalDecls;
|
||||
///
|
||||
/// For a parameter pack, the local instantiation scope may contain a
|
||||
/// set of instantiated parameters. This is stored as a DeclArgumentPack
|
||||
/// pointer.
|
||||
LocalDeclsMap LocalDecls;
|
||||
|
||||
/// \brief The set of argument packs we've allocated.
|
||||
llvm::SmallVector<DeclArgumentPack *, 1> ArgumentPacks;
|
||||
|
||||
/// \brief The outer scope, which contains local variable
|
||||
/// definitions from some other instantiation (that may not be
|
||||
/// relevant to this particular scope).
|
||||
|
@ -219,12 +235,26 @@ namespace clang {
|
|||
if (Exited)
|
||||
return;
|
||||
|
||||
for (unsigned I = 0, N = ArgumentPacks.size(); I != N; ++I)
|
||||
delete ArgumentPacks[I];
|
||||
|
||||
SemaRef.CurrentInstantiationScope = Outer;
|
||||
Exited = true;
|
||||
}
|
||||
|
||||
Decl *getInstantiationOf(const Decl *D);
|
||||
|
||||
/// \brief Find the instantiation of the declaration D within the current
|
||||
/// instantiation scope.
|
||||
///
|
||||
/// \param D The declaration whose instantiation we are searching for.
|
||||
///
|
||||
/// \returns A pointer to the declaration or argument pack of declarations
|
||||
/// to which the declaration \c D is instantiataed, if found. Otherwise,
|
||||
/// returns NULL.
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *
|
||||
findInstantiationOf(const Decl *D);
|
||||
|
||||
VarDecl *getInstantiationOf(const VarDecl *Var) {
|
||||
return cast<VarDecl>(getInstantiationOf(cast<Decl>(Var)));
|
||||
}
|
||||
|
@ -239,6 +269,8 @@ namespace clang {
|
|||
}
|
||||
|
||||
void InstantiatedLocal(const Decl *D, Decl *Inst);
|
||||
void InstantiatedLocalPackArg(const Decl *D, Decl *Inst);
|
||||
void MakeInstantiatedLocalArgPack(const Decl *D);
|
||||
};
|
||||
|
||||
class TemplateDeclInstantiator
|
||||
|
|
|
@ -542,7 +542,6 @@ DeduceTemplateArguments(Sema &S,
|
|||
llvm::SmallVectorImpl<DeducedTemplateArgument> &Deduced,
|
||||
unsigned TDF) {
|
||||
// Fast-path check to see if we have too many/too few arguments.
|
||||
// FIXME: Variadic templates broken!
|
||||
if (NumParams != NumArgs &&
|
||||
!(NumParams && isa<PackExpansionType>(Params[NumParams - 1])) &&
|
||||
!(NumArgs && isa<PackExpansionType>(Args[NumArgs - 1])))
|
||||
|
|
|
@ -617,6 +617,10 @@ namespace {
|
|||
NumExpansions);
|
||||
}
|
||||
|
||||
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) {
|
||||
SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
|
||||
}
|
||||
|
||||
/// \brief Transform the given declaration by instantiating a reference to
|
||||
/// this declaration.
|
||||
Decl *TransformDecl(SourceLocation Loc, Decl *D);
|
||||
|
@ -1154,12 +1158,9 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
TypeSourceInfo *OldDI = OldParm->getTypeSourceInfo();
|
||||
TypeSourceInfo *NewDI = 0;
|
||||
|
||||
bool WasParameterPack = false;
|
||||
bool IsParameterPack = false;
|
||||
TypeLoc OldTL = OldDI->getTypeLoc();
|
||||
if (isa<PackExpansionTypeLoc>(OldTL)) {
|
||||
PackExpansionTypeLoc ExpansionTL = cast<PackExpansionTypeLoc>(OldTL);
|
||||
WasParameterPack = true;
|
||||
|
||||
// We have a function parameter pack. Substitute into the pattern of the
|
||||
// expansion.
|
||||
|
@ -1173,7 +1174,6 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
// our function parameter is still a function parameter pack.
|
||||
// Therefore, make its type a pack expansion type.
|
||||
NewDI = CheckPackExpansion(NewDI, ExpansionTL.getEllipsisLoc());
|
||||
IsParameterPack = true;
|
||||
}
|
||||
} else {
|
||||
NewDI = SubstType(OldDI, TemplateArgs, OldParm->getLocation(),
|
||||
|
@ -1211,8 +1211,13 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
|
||||
// FIXME: When OldParm is a parameter pack and NewParm is not a parameter
|
||||
// pack, we actually have a set of instantiated locations. Maintain this set!
|
||||
if (!WasParameterPack || IsParameterPack)
|
||||
if (OldParm->isParameterPack() && !NewParm->isParameterPack()) {
|
||||
// Add the new parameter to
|
||||
CurrentInstantiationScope->InstantiatedLocalPackArg(OldParm, NewParm);
|
||||
} else {
|
||||
// Introduce an Old -> New mapping
|
||||
CurrentInstantiationScope->InstantiatedLocal(OldParm, NewParm);
|
||||
}
|
||||
|
||||
// FIXME: OldParm may come from a FunctionProtoType, in which case CurContext
|
||||
// can be anything, is this right ?
|
||||
|
@ -1227,7 +1232,8 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
|
|||
bool Sema::SubstParmTypes(SourceLocation Loc,
|
||||
ParmVarDecl **Params, unsigned NumParams,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs,
|
||||
llvm::SmallVectorImpl<QualType> &ParamTypes) {
|
||||
llvm::SmallVectorImpl<QualType> &ParamTypes,
|
||||
llvm::SmallVectorImpl<ParmVarDecl *> *OutParams) {
|
||||
assert(!ActiveTemplateInstantiations.empty() &&
|
||||
"Cannot perform an instantiation without some context on the "
|
||||
"instantiation stack");
|
||||
|
@ -1235,7 +1241,7 @@ bool Sema::SubstParmTypes(SourceLocation Loc,
|
|||
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
|
||||
DeclarationName());
|
||||
return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, 0,
|
||||
ParamTypes, 0);
|
||||
ParamTypes, OutParams);
|
||||
}
|
||||
|
||||
/// \brief Perform substitution on the base class specifiers of the
|
||||
|
@ -1899,15 +1905,27 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs,
|
|||
}
|
||||
|
||||
Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) {
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found= findInstantiationOf(D);
|
||||
if (!Found)
|
||||
return 0;
|
||||
|
||||
if (Found->is<Decl *>())
|
||||
return Found->get<Decl *>();
|
||||
|
||||
return (*Found->get<DeclArgumentPack *>())[
|
||||
SemaRef.ArgumentPackSubstitutionIndex];
|
||||
}
|
||||
|
||||
llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> *
|
||||
LocalInstantiationScope::findInstantiationOf(const Decl *D) {
|
||||
for (LocalInstantiationScope *Current = this; Current;
|
||||
Current = Current->Outer) {
|
||||
// Check if we found something within this scope.
|
||||
const Decl *CheckD = D;
|
||||
do {
|
||||
llvm::DenseMap<const Decl *, Decl *>::iterator Found
|
||||
= Current->LocalDecls.find(CheckD);
|
||||
LocalDeclsMap::iterator Found = Current->LocalDecls.find(CheckD);
|
||||
if (Found != Current->LocalDecls.end())
|
||||
return Found->second;
|
||||
return &Found->second;
|
||||
|
||||
// If this is a tag declaration, it's possible that we need to look for
|
||||
// a previous declaration.
|
||||
|
@ -1928,7 +1946,23 @@ Decl *LocalInstantiationScope::getInstantiationOf(const Decl *D) {
|
|||
}
|
||||
|
||||
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
|
||||
Decl *&Stored = LocalDecls[D];
|
||||
assert((!Stored || Stored == Inst)&& "Already instantiated this local");
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
|
||||
assert((Stored.isNull() ||
|
||||
(Stored.get<Decl *>() == Inst)) && "Already instantiated this local");
|
||||
Stored = Inst;
|
||||
}
|
||||
|
||||
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
|
||||
Decl *Inst) {
|
||||
DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>();
|
||||
Pack->push_back(Inst);
|
||||
}
|
||||
|
||||
void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
|
||||
assert(Stored.isNull() && "Already instantiated this local");
|
||||
DeclArgumentPack *Pack = new DeclArgumentPack;
|
||||
Stored = Pack;
|
||||
ArgumentPacks.push_back(Pack);
|
||||
}
|
||||
|
||||
|
|
|
@ -1271,14 +1271,11 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
|
|||
// synthesized in the method declaration.
|
||||
if (!isa<FunctionProtoType>(T.IgnoreParens())) {
|
||||
assert(!Params.size() && "Instantiating type could not yield parameters");
|
||||
for (unsigned I = 0, N = D->getNumParams(); I != N; ++I) {
|
||||
ParmVarDecl *P = SemaRef.SubstParmVarDecl(D->getParamDecl(I),
|
||||
TemplateArgs);
|
||||
if (!P)
|
||||
return 0;
|
||||
|
||||
Params.push_back(P);
|
||||
}
|
||||
llvm::SmallVector<QualType, 4> ParamTypes;
|
||||
if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
|
||||
D->getNumParams(), TemplateArgs, ParamTypes,
|
||||
&Params))
|
||||
return 0;
|
||||
}
|
||||
|
||||
NestedNameSpecifier *Qualifier = D->getQualifier();
|
||||
|
@ -1904,12 +1901,31 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
|
|||
TypeLoc NewTL = NewTInfo->getTypeLoc().IgnoreParens();
|
||||
FunctionProtoTypeLoc *NewProtoLoc = cast<FunctionProtoTypeLoc>(&NewTL);
|
||||
assert(NewProtoLoc && "Missing prototype?");
|
||||
for (unsigned i = 0, i_end = NewProtoLoc->getNumArgs(); i != i_end; ++i) {
|
||||
// FIXME: Variadic templates will break this.
|
||||
Params.push_back(NewProtoLoc->getArg(i));
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(
|
||||
OldProtoLoc->getArg(i),
|
||||
NewProtoLoc->getArg(i));
|
||||
unsigned NewIdx = 0, NumNewParams = NewProtoLoc->getNumArgs();
|
||||
for (unsigned OldIdx = 0, NumOldParams = OldProtoLoc->getNumArgs();
|
||||
OldIdx != NumOldParams; ++OldIdx) {
|
||||
ParmVarDecl *OldParam = OldProtoLoc->getArg(OldIdx);
|
||||
if (!OldParam->isParameterPack() ||
|
||||
(NewIdx < NumNewParams &&
|
||||
NewProtoLoc->getArg(NewIdx)->isParameterPack())) {
|
||||
// Simple case: normal parameter, or a parameter pack that's
|
||||
// instantiated to a (still-dependent) parameter pack.
|
||||
ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
|
||||
Params.push_back(NewParam);
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldParam,
|
||||
NewParam);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parameter pack: make the instantiation an argument pack.
|
||||
SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(
|
||||
OldParam);
|
||||
while (NewIdx < NumNewParams) {
|
||||
ParmVarDecl *NewParam = NewProtoLoc->getArg(NewIdx++);
|
||||
Params.push_back(NewParam);
|
||||
SemaRef.CurrentInstantiationScope->InstantiatedLocalPackArg(OldParam,
|
||||
NewParam);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -2179,11 +2195,28 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
|
|||
// Introduce the instantiated function parameters into the local
|
||||
// instantiation scope, and set the parameter names to those used
|
||||
// in the template.
|
||||
unsigned FParamIdx = 0;
|
||||
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
|
||||
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(I);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
||||
if (!PatternParam->isParameterPack()) {
|
||||
// Simple case: not a parameter pack.
|
||||
assert(FParamIdx < Function->getNumParams());
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(I);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocal(PatternParam, FunctionParam);
|
||||
++FParamIdx;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Expand the parameter pack.
|
||||
Scope.MakeInstantiatedLocalArgPack(PatternParam);
|
||||
for (unsigned NumFParams = Function->getNumParams();
|
||||
FParamIdx < NumFParams;
|
||||
++FParamIdx) {
|
||||
ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
|
||||
FunctionParam->setDeclName(PatternParam->getDeclName());
|
||||
Scope.InstantiatedLocalPackArg(PatternParam, FunctionParam);
|
||||
}
|
||||
}
|
||||
|
||||
// Enter the scope of this instantiation. We don't use
|
||||
|
|
|
@ -67,13 +67,8 @@ namespace {
|
|||
/// \brief Record occurrences of (FIXME: function and) non-type template
|
||||
/// parameter packs in an expression.
|
||||
bool VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
if (NonTypeTemplateParmDecl *NTTP
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) {
|
||||
if (NTTP->isParameterPack())
|
||||
Unexpanded.push_back(std::make_pair(NTTP, E->getLocation()));
|
||||
}
|
||||
|
||||
// FIXME: Function parameter packs.
|
||||
if (E->getDecl()->isParameterPack())
|
||||
Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -440,6 +435,7 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
|
|||
unsigned Depth;
|
||||
unsigned Index;
|
||||
IdentifierInfo *Name;
|
||||
bool IsFunctionParameterPack = false;
|
||||
|
||||
if (const TemplateTypeParmType *TTP
|
||||
= Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) {
|
||||
|
@ -455,26 +451,50 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
|
|||
= dyn_cast<NonTypeTemplateParmDecl>(ND)) {
|
||||
Depth = NTTP->getDepth();
|
||||
Index = NTTP->getIndex();
|
||||
} else {
|
||||
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
|
||||
} else if (TemplateTemplateParmDecl *TTP
|
||||
= dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
||||
Depth = TTP->getDepth();
|
||||
Index = TTP->getIndex();
|
||||
} else {
|
||||
assert(cast<ParmVarDecl>(ND)->isParameterPack());
|
||||
IsFunctionParameterPack = true;
|
||||
}
|
||||
// FIXME: Variadic templates function parameter packs?
|
||||
Name = ND->getIdentifier();
|
||||
}
|
||||
|
||||
// If we don't have a template argument at this depth/index, then we
|
||||
// cannot expand the pack expansion. Make a note of this, but we still
|
||||
// want to check any parameter packs we *do* have arguments for.
|
||||
if (Depth >= TemplateArgs.getNumLevels() ||
|
||||
!TemplateArgs.hasTemplateArgument(Depth, Index)) {
|
||||
ShouldExpand = false;
|
||||
continue;
|
||||
// Determine the size of this argument pack.
|
||||
unsigned NewPackSize;
|
||||
if (IsFunctionParameterPack) {
|
||||
// Figure out whether we're instantiating to an argument pack or not.
|
||||
typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack;
|
||||
|
||||
llvm::PointerUnion<Decl *, DeclArgumentPack *> *Instantiation
|
||||
= CurrentInstantiationScope->findInstantiationOf(
|
||||
Unexpanded[I].first.get<NamedDecl *>());
|
||||
if (Instantiation &&
|
||||
Instantiation->is<DeclArgumentPack *>()) {
|
||||
// We could expand this function parameter pack.
|
||||
NewPackSize = Instantiation->get<DeclArgumentPack *>()->size();
|
||||
} else {
|
||||
// We can't expand this function parameter pack, so we can't expand
|
||||
// the pack expansion.
|
||||
ShouldExpand = false;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
// If we don't have a template argument at this depth/index, then we
|
||||
// cannot expand the pack expansion. Make a note of this, but we still
|
||||
// want to check any parameter packs we *do* have arguments for.
|
||||
if (Depth >= TemplateArgs.getNumLevels() ||
|
||||
!TemplateArgs.hasTemplateArgument(Depth, Index)) {
|
||||
ShouldExpand = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine the size of the argument pack.
|
||||
NewPackSize = TemplateArgs(Depth, Index).pack_size();
|
||||
}
|
||||
|
||||
// Determine the size of the argument pack.
|
||||
unsigned NewPackSize = TemplateArgs(Depth, Index).pack_size();
|
||||
if (!HaveFirstPack) {
|
||||
// The is the first pack we've seen for which we have an argument.
|
||||
// Record it.
|
||||
|
|
|
@ -222,6 +222,10 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Note to the derived class when a function parameter pack is
|
||||
/// being expanded.
|
||||
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
|
||||
|
||||
/// \brief Transforms the given type into another type.
|
||||
///
|
||||
/// By default, this routine transforms a type by creating a
|
||||
|
@ -3423,6 +3427,7 @@ bool TreeTransform<Derived>::
|
|||
if (ShouldExpand) {
|
||||
// Expand the function parameter pack into multiple, separate
|
||||
// parameters.
|
||||
getDerived().ExpandingFunctionParameterPack(OldParm);
|
||||
for (unsigned I = 0; I != NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
|
||||
ParmVarDecl *NewParm
|
||||
|
@ -6875,6 +6880,7 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
|
|||
llvm::SmallVector<QualType, 4> ParamTypes;
|
||||
|
||||
// Parameter substitution.
|
||||
// FIXME: Variadic templates
|
||||
const BlockDecl *BD = E->getBlockDecl();
|
||||
for (BlockDecl::param_const_iterator P = BD->param_begin(),
|
||||
EN = BD->param_end(); P != EN; ++P) {
|
||||
|
|
|
@ -13,6 +13,18 @@ template<int ...Values> struct count_ints {
|
|||
int check_types[count_types<short, int, long>::value == 3? 1 : -1];
|
||||
int check_ints[count_ints<1, 2, 3, 4, 5>::value == 5? 1 : -1];
|
||||
|
||||
// Test instantiation involving function parameter packs.
|
||||
struct any {
|
||||
template<typename T> any(T);
|
||||
};
|
||||
|
||||
template<typename ...Inits>
|
||||
void init_me(Inits ...inits) {
|
||||
any array[sizeof...(inits)] = { inits... };
|
||||
}
|
||||
|
||||
template void init_me<int, float, double*>(int, float, double*);
|
||||
|
||||
// Test parser and semantic recovery.
|
||||
template<int Value> struct count_ints_2 {
|
||||
static const unsigned value = sizeof...(Value); // expected-error{{'Value' does not refer to the name of a parameter pack}}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
|
||||
|
||||
template<class ... Types> void f(Types ... args);
|
||||
|
||||
void test() {
|
||||
f();
|
||||
f(1);
|
||||
f(2, 1.0);
|
||||
}
|
||||
|
||||
// Test simple recursive variadic function template
|
||||
template<typename Head, typename ...Tail>
|
||||
void recurse_until_fail(const Head &, const Tail &...tail) { // expected-note{{candidate function template not viable: requires at least 1 argument, but 0 were provided}}
|
||||
recurse_until_fail(tail...); // expected-error{{no matching function for call to 'recurse_until_fail'}} \
|
||||
// expected-note{{in instantiation of function template specialization 'recurse_until_fail<char [7], >' requested here}} \
|
||||
// expected-note{{in instantiation of function template specialization 'recurse_until_fail<double, char [7]>' requested here}}
|
||||
}
|
||||
|
||||
void test_recurse_until_fail() {
|
||||
recurse_until_fail(1, 3.14159, "string"); // expected-note{{in instantiation of function template specialization 'recurse_until_fail<int, double, char [7]>' requested here}}
|
||||
|
||||
}
|
|
@ -237,3 +237,30 @@ struct MemberTemplatePPNames {
|
|||
};
|
||||
};
|
||||
|
||||
// Example from working paper
|
||||
namespace WorkingPaperExample {
|
||||
template<typename...> struct Tuple {};
|
||||
template<typename T1, typename T2> struct Pair {};
|
||||
|
||||
template<class ... Args1> struct zip {
|
||||
template<class ... Args2> struct with {
|
||||
typedef Tuple<Pair<Args1, Args2> ... > type; // expected-error{{pack expansion contains parameter packs 'Args1' and 'Args2' that have different lengths (1 vs. 2)}}
|
||||
};
|
||||
};
|
||||
|
||||
typedef zip<short, int>::with<unsigned short, unsigned>::type T1; // T1 is Tuple<Pair<short, unsigned short>, Pair<int, unsigned>>
|
||||
typedef Tuple<Pair<short, unsigned short>, Pair<int, unsigned>> T1;
|
||||
|
||||
typedef zip<short>::with<unsigned short, unsigned>::type T2; // expected-note{{in instantiation of template class}}
|
||||
|
||||
template<class ... Args> void f(Args...);
|
||||
template<class ... Args> void h(Args...);
|
||||
|
||||
template<class ... Args>
|
||||
void g(Args ... args) {
|
||||
f(const_cast<const Args*>(&args)...); // OK: "Args" and "args" are expanded within f
|
||||
f(5 ...); // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
|
||||
f(args); // expected-error{{expression contains unexpanded parameter pack 'args'}}
|
||||
f(h(args ...) + args ...);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue