aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaTemplateInstantiate.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-01-07 16:43:16 +0000
committerDouglas Gregor <dgregor@apple.com>2011-01-07 16:43:16 +0000
commit12c9c00024a01819e3a70ef6d951d32efaeb9312 (patch)
tree0c6499b83aab17269756d4e65041d29374506256 /lib/Sema/SemaTemplateInstantiate.cpp
parent170464b7c0a2c0c86f2821f14a46f0d540cb5e94 (diff)
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'); } git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123000 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiate.cpp')
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp58
1 files changed, 46 insertions, 12 deletions
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index c4f91f9ff6..71ccb06212 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -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);
+}
+