Work-in-progress implementation of C++0x [temp.arg.explicit]p9, which
allows an argument pack determines via explicit specification of
function template arguments to be extended by further, deduced
arguments. For example:
template<class ... Types> void f(Types ... values);
void g() {
f<int*, float*>(0, 0, 0); // Types is deduced to the sequence int*, float*, int
}
There are a number of FIXMEs in here that indicate places where we
need to implement + test retained expansions, plus a number of other
places in deduction where we need to correctly cope with the
explicitly-specified arguments when deducing an argument
pack. Furthermore, it appears that the RecursiveASTVisitor needs to be
auditied; it's missing some traversals (especially w.r.t. template
arguments) that cause it not to find unexpanded parameter packs when
it should.
The good news, however, is that the tr1::tuple implementation now
works fully, and the tr1::bind example (both from N2080) is actually
working now.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@123163 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 2c9a430..f540c7b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2550,10 +2550,13 @@
// 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()) {
- // The parameter pack takes the contents of the current argument pack,
- // which we built up earlier.
- if (ArgumentPack.empty()) {
+ if (PartialTemplateArgs && ArgumentPack.empty()) {
+ Converted.push_back(TemplateArgument());
+ } else if (ArgumentPack.empty()) {
Converted.push_back(TemplateArgument(0, 0));
} else {
TemplateArgument *PackedArgs
@@ -3600,7 +3603,7 @@
Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg,
SourceLocation Loc) {
assert(Arg.getKind() == TemplateArgument::Integral &&
- "Operation is only value for integral template arguments");
+ "Operation is only valid for integral template arguments");
QualType T = Arg.getIntegralType();
if (T->isCharType() || T->isWideCharType())
return Owned(new (Context) CharacterLiteral(
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 8832447..ff084c3 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -478,14 +478,9 @@
}
}
-/// \brief Retrieve the depth and index of an unexpanded parameter pack.
+/// \brief Retrieve the depth and index of a template parameter.
static std::pair<unsigned, unsigned>
-getDepthAndIndex(UnexpandedParameterPack UPP) {
- if (const TemplateTypeParmType *TTP
- = UPP.first.dyn_cast<const TemplateTypeParmType *>())
- return std::make_pair(TTP->getDepth(), TTP->getIndex());
-
- NamedDecl *ND = UPP.first.get<NamedDecl *>();
+getDepthAndIndex(NamedDecl *ND) {
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
return std::make_pair(TTP->getDepth(), TTP->getIndex());
@@ -496,6 +491,16 @@
return std::make_pair(TTP->getDepth(), TTP->getIndex());
}
+/// \brief Retrieve the depth and index of an unexpanded parameter pack.
+static std::pair<unsigned, unsigned>
+getDepthAndIndex(UnexpandedParameterPack UPP) {
+ if (const TemplateTypeParmType *TTP
+ = UPP.first.dyn_cast<const TemplateTypeParmType *>())
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+
+ return getDepthAndIndex(UPP.first.get<NamedDecl *>());
+}
+
/// \brief Helper function to build a TemplateParameter when we don't
/// know its type statically.
static TemplateParameter makeTemplateParameter(Decl *D) {
@@ -602,6 +607,12 @@
}
assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
+ // Keep track of the deduced template arguments for each parameter pack
+ // expanded by this pack expansion (the outer index) and for each
+ // template argument (the inner SmallVectors).
+ llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
+ NewlyDeducedPacks(PackIndices.size());
+
// Save the deduced template arguments for each parameter pack expanded
// by this pack expansion, then clear out the deduction.
llvm::SmallVector<DeducedTemplateArgument, 2>
@@ -609,13 +620,21 @@
for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
SavedPacks[I] = Deduced[PackIndices[I]];
Deduced[PackIndices[I]] = DeducedTemplateArgument();
+
+ // If the template arugment pack was explicitly specified, add that to
+ // the set of deduced arguments.
+ const TemplateArgument *ExplicitArgs;
+ unsigned NumExplicitArgs;
+ if (NamedDecl *PartiallySubstitutedPack
+ = S.CurrentInstantiationScope->getPartiallySubstitutedPack(
+ &ExplicitArgs,
+ &NumExplicitArgs)) {
+ if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
+ NewlyDeducedPacks[I].append(ExplicitArgs,
+ ExplicitArgs + NumExplicitArgs);
+ }
}
- // Keep track of the deduced template arguments for each parameter pack
- // expanded by this pack expansion (the outer index) and for each
- // template argument (the inner SmallVectors).
- llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacks(PackIndices.size());
bool HasAnyArguments = false;
for (; ArgIdx < NumArgs; ++ArgIdx) {
HasAnyArguments = true;
@@ -1879,13 +1898,30 @@
TemplateArgumentList *ExplicitArgumentList
= TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size());
Info.reset(ExplicitArgumentList);
-
+
// Template argument deduction and the final substitution should be
// done in the context of the templated declaration. Explicit
// argument substitution, on the other hand, needs to happen in the
// calling context.
ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl());
+ // If we deduced template arguments for a template parameter pack,
+ // note that the template argument pack is partially substituted and record
+ // the explicit template arguments. They'll be used as part of deduction
+ // for this template parameter pack.
+ bool HasPartiallySubstitutedPack = false;
+ for (unsigned I = 0, N = Builder.size(); I != N; ++I) {
+ const TemplateArgument &Arg = Builder[I];
+ if (Arg.getKind() == TemplateArgument::Pack) {
+ HasPartiallySubstitutedPack = true;
+ CurrentInstantiationScope->SetPartiallySubstitutedPack(
+ TemplateParams->getParam(I),
+ Arg.pack_begin(),
+ Arg.pack_size());
+ break;
+ }
+ }
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments.
if (SubstParmTypes(Function->getLocation(),
@@ -1927,11 +1963,18 @@
// template arguments can be deduced, they may all be omitted; in this
// case, the empty template argument list <> itself may also be omitted.
//
- // Take all of the explicitly-specified arguments and put them into the
- // set of deduced template arguments.
+ // Take all of the explicitly-specified arguments and put them into
+ // the set of deduced template arguments. Explicitly-specified
+ // parameter packs, however, will be set to NULL since the deduction
+ // mechanisms handle explicitly-specified argument packs directly.
Deduced.reserve(TemplateParams->size());
- for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I)
- Deduced.push_back(ExplicitArgumentList->get(I));
+ for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
+ const TemplateArgument &Arg = ExplicitArgumentList->get(I);
+ if (Arg.getKind() == TemplateArgument::Pack)
+ Deduced.push_back(DeducedTemplateArgument());
+ else
+ Deduced.push_back(Arg);
+ }
return TDK_Success;
}
@@ -2025,7 +2068,18 @@
// be deduced to an empty sequence of template arguments.
// FIXME: Where did the word "trailing" come from?
if (Param->isTemplateParameterPack()) {
- Builder.push_back(TemplateArgument(0, 0));
+ // We may have had explicitly-specified template arguments for this
+ // template parameter pack. If so, our empty deduction extends the
+ // explicitly-specified set (C++0x [temp.arg.explicit]p9).
+ const TemplateArgument *ExplicitArgs;
+ unsigned NumExplicitArgs;
+ if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs,
+ &NumExplicitArgs)
+ == Param)
+ Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs));
+ else
+ Builder.push_back(TemplateArgument(0, 0));
+
continue;
}
@@ -2446,20 +2500,36 @@
}
assert(!PackIndices.empty() && "Pack expansion without unexpanded packs?");
- // Save the deduced template arguments for each parameter pack expanded
- // by this pack expansion, then clear out the deduction.
- llvm::SmallVector<DeducedTemplateArgument, 2>
- SavedPacks(PackIndices.size());
- for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
- SavedPacks[I] = Deduced[PackIndices[I]];
- Deduced[PackIndices[I]] = DeducedTemplateArgument();
- }
-
// Keep track of the deduced template arguments for each parameter pack
// expanded by this pack expansion (the outer index) and for each
// template argument (the inner SmallVectors).
llvm::SmallVector<llvm::SmallVector<DeducedTemplateArgument, 4>, 2>
- NewlyDeducedPacks(PackIndices.size());
+ NewlyDeducedPacks(PackIndices.size());
+
+ // Save the deduced template arguments for each parameter pack expanded
+ // by this pack expansion, then clear out the deduction.
+ llvm::SmallVector<DeducedTemplateArgument, 2>
+ SavedPacks(PackIndices.size());
+ for (unsigned I = 0, N = PackIndices.size(); I != N; ++I) {
+ // Save the previously-deduced argument pack, then clear it out so that we
+ // can deduce a new argument pack.
+ SavedPacks[I] = Deduced[PackIndices[I]];
+ Deduced[PackIndices[I]] = TemplateArgument();
+
+ // If the template arugment pack was explicitly specified, add that to
+ // the set of deduced arguments.
+ const TemplateArgument *ExplicitArgs;
+ unsigned NumExplicitArgs;
+ if (NamedDecl *PartiallySubstitutedPack
+ = CurrentInstantiationScope->getPartiallySubstitutedPack(
+ &ExplicitArgs,
+ &NumExplicitArgs)) {
+ if (getDepthAndIndex(PartiallySubstitutedPack).second == PackIndices[I])
+ NewlyDeducedPacks[I].append(ExplicitArgs,
+ ExplicitArgs + NumExplicitArgs);
+ }
+ }
+
bool HasAnyArguments = false;
for (; ArgIdx < NumArgs; ++ArgIdx) {
HasAnyArguments = true;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 394f50e..5f181fb 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -564,6 +564,19 @@
return 0;
}
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned>
+getDepthAndIndex(NamedDecl *ND) {
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+ return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
//===----------------------------------------------------------------------===/
// Template Instantiation for Types
//===----------------------------------------------------------------------===/
@@ -608,12 +621,14 @@
const UnexpandedParameterPack *Unexpanded,
unsigned NumUnexpanded,
bool &ShouldExpand,
+ bool &RetainExpansion,
unsigned &NumExpansions) {
return getSema().CheckParameterPacksForExpansion(EllipsisLoc,
PatternRange, Unexpanded,
NumUnexpanded,
TemplateArgs,
ShouldExpand,
+ RetainExpansion,
NumExpansions);
}
@@ -621,6 +636,37 @@
SemaRef.CurrentInstantiationScope->MakeInstantiatedLocalArgPack(Pack);
}
+ TemplateArgument ForgetPartiallySubstitutedPack() {
+ TemplateArgument Result;
+ if (NamedDecl *PartialPack
+ = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+ MultiLevelTemplateArgumentList &TemplateArgs
+ = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ unsigned Depth, Index;
+ llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ if (TemplateArgs.hasTemplateArgument(Depth, Index)) {
+ Result = TemplateArgs(Depth, Index);
+ TemplateArgs.setArgument(Depth, Index, TemplateArgument());
+ }
+ }
+
+ return Result;
+ }
+
+ void RememberPartiallySubstitutedPack(TemplateArgument Arg) {
+ if (Arg.isNull())
+ return;
+
+ if (NamedDecl *PartialPack
+ = SemaRef.CurrentInstantiationScope->getPartiallySubstitutedPack()){
+ MultiLevelTemplateArgumentList &TemplateArgs
+ = const_cast<MultiLevelTemplateArgumentList &>(this->TemplateArgs);
+ unsigned Depth, Index;
+ llvm::tie(Depth, Index) = getDepthAndIndex(PartialPack);
+ TemplateArgs.setArgument(Depth, Index, Arg);
+ }
+ }
+
/// \brief Transform the given declaration by instantiating a reference to
/// this declaration.
Decl *TransformDecl(SourceLocation Loc, Decl *D);
@@ -713,6 +759,7 @@
return 0;
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -761,6 +808,7 @@
return 0;
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -877,6 +925,7 @@
return ExprError();
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -981,6 +1030,7 @@
return QualType();
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -1272,11 +1322,13 @@
collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(),
Unexpanded);
bool ShouldExpand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(),
Base->getSourceRange(),
Unexpanded.data(), Unexpanded.size(),
TemplateArgs, ShouldExpand,
+ RetainExpansion,
NumExpansions)) {
Invalid = true;
continue;
@@ -1959,9 +2011,13 @@
void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) {
llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D];
- assert((Stored.isNull() ||
- (Stored.get<Decl *>() == Inst)) && "Already instantiated this local");
- Stored = Inst;
+ if (Stored.isNull())
+ Stored = Inst;
+ else if (Stored.is<Decl *>()) {
+ assert(Stored.get<Decl *>() == Inst && "Already instantiated this local");
+ Stored = Inst;
+ } else
+ LocalDecls[D].get<DeclArgumentPack *>()->push_back(Inst);
}
void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D,
@@ -1978,3 +2034,41 @@
ArgumentPacks.push_back(Pack);
}
+void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack,
+ const TemplateArgument *ExplicitArgs,
+ unsigned NumExplicitArgs) {
+ assert((!PartiallySubstitutedPack || PartiallySubstitutedPack == Pack) &&
+ "Already have a partially-substituted pack");
+ assert((!PartiallySubstitutedPack
+ || NumArgsInPartiallySubstitutedPack == NumExplicitArgs) &&
+ "Wrong number of arguments in partially-substituted pack");
+ PartiallySubstitutedPack = Pack;
+ ArgsInPartiallySubstitutedPack = ExplicitArgs;
+ NumArgsInPartiallySubstitutedPack = NumExplicitArgs;
+}
+
+NamedDecl *LocalInstantiationScope::getPartiallySubstitutedPack(
+ const TemplateArgument **ExplicitArgs,
+ unsigned *NumExplicitArgs) const {
+ if (ExplicitArgs)
+ *ExplicitArgs = 0;
+ if (NumExplicitArgs)
+ *NumExplicitArgs = 0;
+
+ for (const LocalInstantiationScope *Current = this; Current;
+ Current = Current->Outer) {
+ if (Current->PartiallySubstitutedPack) {
+ if (ExplicitArgs)
+ *ExplicitArgs = Current->ArgsInPartiallySubstitutedPack;
+ if (NumExplicitArgs)
+ *NumExplicitArgs = Current->NumArgsInPartiallySubstitutedPack;
+
+ return Current->PartiallySubstitutedPack;
+ }
+
+ if (!Current->CombineWithOuterScope)
+ break;
+ }
+
+ return 0;
+}
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index e59f94a..c29ff86 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1973,13 +1973,16 @@
"Pack expansion without parameter packs?");
bool Expand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(),
SourceRange(),
Unexpanded.data(),
Unexpanded.size(),
TemplateArgs,
- Expand, NumExpansions))
+ Expand,
+ RetainExpansion,
+ NumExpansions))
break;
if (!Expand) {
@@ -2377,12 +2380,14 @@
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
bool ShouldExpand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
BaseTL.getSourceRange(),
Unexpanded.data(),
Unexpanded.size(),
TemplateArgs, ShouldExpand,
+ RetainExpansion,
NumExpansions)) {
AnyErrors = true;
New->setInvalidDecl();
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 1928c59..09e610c 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -419,14 +419,29 @@
EllipsisLoc));
}
+/// \brief Retrieve the depth and index of a parameter pack.
+static std::pair<unsigned, unsigned>
+getDepthAndIndex(NamedDecl *ND) {
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+
+ if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
+ return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
+
+ TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
+ return std::make_pair(TTP->getDepth(), TTP->getIndex());
+}
+
bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
SourceRange PatternRange,
const UnexpandedParameterPack *Unexpanded,
unsigned NumUnexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool &ShouldExpand,
+ bool &RetainExpansion,
unsigned &NumExpansions) {
ShouldExpand = true;
+ RetainExpansion = false;
std::pair<IdentifierInfo *, SourceLocation> FirstPack;
bool HaveFirstPack = false;
@@ -444,21 +459,11 @@
Name = TTP->getName();
} else {
NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>();
- if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
- } else if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(ND)) {
- Depth = NTTP->getDepth();
- Index = NTTP->getIndex();
- } else if (TemplateTemplateParmDecl *TTP
- = dyn_cast<TemplateTemplateParmDecl>(ND)) {
- Depth = TTP->getDepth();
- Index = TTP->getIndex();
- } else {
- assert(cast<ParmVarDecl>(ND)->isParameterPack());
+ if (isa<ParmVarDecl>(ND))
IsFunctionParameterPack = true;
- }
+ else
+ llvm::tie(Depth, Index) = getDepthAndIndex(ND);
+
Name = ND->getIdentifier();
}
@@ -495,6 +500,18 @@
NewPackSize = TemplateArgs(Depth, Index).pack_size();
}
+ // C++0x [temp.arg.explicit]p9:
+ // Template argument deduction can extend the sequence of template
+ // arguments corresponding to a template parameter pack, even when the
+ // sequence contains explicitly specified template arguments.
+ if (NamedDecl *PartialPack
+ = CurrentInstantiationScope->getPartiallySubstitutedPack()) {
+ unsigned PartialDepth, PartialIndex;
+ llvm::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
+ if (PartialDepth == Depth && PartialIndex == Index)
+ RetainExpansion = true;
+ }
+
if (!HaveFirstPack) {
// The is the first pack we've seen for which we have an argument.
// Record it.
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index e2bfb05..7eee444 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -89,6 +89,23 @@
/// (\c getBaseLocation(), \c getBaseEntity()).
template<typename Derived>
class TreeTransform {
+ /// \brief Private RAII object that helps us forget and then re-remember
+ /// the template argument corresponding to a partially-substituted parameter
+ /// pack.
+ class ForgetPartiallySubstitutedPackRAII {
+ Derived &Self;
+ TemplateArgument Old;
+
+ public:
+ ForgetPartiallySubstitutedPackRAII(Derived &Self) : Self(Self) {
+ Old = Self.ForgetPartiallySubstitutedPack();
+ }
+
+ ~ForgetPartiallySubstitutedPackRAII() {
+ Self.RememberPartiallySubstitutedPack(Old);
+ }
+ };
+
protected:
Sema &SemaRef;
@@ -204,6 +221,11 @@
/// expand the corresponding pack expansions into separate arguments. When
/// set, \c NumExpansions must also be set.
///
+ /// \param RetainExpansion Whether the caller should add an unexpanded
+ /// pack expansion after all of the expanded arguments. This is used
+ /// when extending explicitly-specified template argument packs per
+ /// C++0x [temp.arg.explicit]p9.
+ ///
/// \param NumExpansions The number of separate arguments that will be in
/// the expanded form of the corresponding pack expansion. Must be set when
/// \c ShouldExpand is \c true.
@@ -217,11 +239,28 @@
const UnexpandedParameterPack *Unexpanded,
unsigned NumUnexpanded,
bool &ShouldExpand,
+ bool &RetainExpansion,
unsigned &NumExpansions) {
ShouldExpand = false;
return false;
}
+ /// \brief "Forget" about the partially-substituted pack template argument,
+ /// when performing an instantiation that must preserve the parameter pack
+ /// use.
+ ///
+ /// This routine is meant to be overridden by the template instantiator.
+ TemplateArgument ForgetPartiallySubstitutedPack() {
+ return TemplateArgument();
+ }
+
+ /// \brief "Remember" the partially-substituted pack template argument
+ /// after performing an instantiation that must preserve the parameter pack
+ /// use.
+ ///
+ /// This routine is meant to be overridden by the template instantiator.
+ void RememberPartiallySubstitutedPack(TemplateArgument Arg) { }
+
/// \brief Note to the derived class when a function parameter pack is
/// being expanded.
void ExpandingFunctionParameterPack(ParmVarDecl *Pack) { }
@@ -2250,12 +2289,14 @@
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(),
Pattern->getSourceRange(),
Unexpanded.data(),
Unexpanded.size(),
- Expand, NumExpansions))
+ Expand, RetainExpansion,
+ NumExpansions))
return true;
if (!Expand) {
@@ -2770,12 +2811,15 @@
// Determine whether the set of unexpanded parameter packs can and should
// be expanded.
bool Expand = true;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (getDerived().TryExpandParameterPacks(Ellipsis,
Pattern.getSourceRange(),
Unexpanded.data(),
Unexpanded.size(),
- Expand, NumExpansions))
+ Expand,
+ RetainExpansion,
+ NumExpansions))
return true;
if (!Expand) {
@@ -2806,6 +2850,8 @@
Outputs.addArgument(Out);
}
+ // FIXME: Variadic templates retain expansion!
+
continue;
}
@@ -3415,12 +3461,15 @@
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(),
Pattern.getSourceRange(),
Unexpanded.data(),
Unexpanded.size(),
- ShouldExpand, NumExpansions)) {
+ ShouldExpand,
+ RetainExpansion,
+ NumExpansions)) {
return true;
}
@@ -3439,7 +3488,21 @@
if (PVars)
PVars->push_back(NewParm);
}
-
+
+ // If we're supposed to retain a pack expansion, do so by temporarily
+ // forgetting the partially-substituted parameter pack.
+ if (RetainExpansion) {
+ ForgetPartiallySubstitutedPackRAII Forget(getDerived());
+ ParmVarDecl *NewParm
+ = getDerived().TransformFunctionTypeParam(OldParm);
+ if (!NewParm)
+ return true;
+
+ OutParamTypes.push_back(NewParm->getType());
+ if (PVars)
+ PVars->push_back(NewParm);
+ }
+
// We're done with the pack expansion.
continue;
}
@@ -3472,11 +3535,14 @@
// Determine whether we should expand the parameter packs.
bool ShouldExpand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (getDerived().TryExpandParameterPacks(Loc, SourceRange(),
Unexpanded.data(),
Unexpanded.size(),
- ShouldExpand, NumExpansions)) {
+ ShouldExpand,
+ RetainExpansion,
+ NumExpansions)) {
return true;
}
@@ -3498,6 +3564,8 @@
continue;
}
+ // FIXME: Variadic templates retain pack expansion!
+
// We'll substitute the parameter now without expanding the pack
// expansion.
OldType = Expansion->getPattern();
@@ -6674,13 +6742,15 @@
// so
UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
bool ShouldExpand = false;
+ bool RetainExpansion = false;
unsigned NumExpansions = 0;
if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(),
&Unexpanded, 1,
- ShouldExpand, NumExpansions))
+ ShouldExpand, RetainExpansion,
+ NumExpansions))
return ExprError();
- if (!ShouldExpand)
+ if (!ShouldExpand || RetainExpansion)
return SemaRef.Owned(E);
// We now know the length of the parameter pack, so build a new expression