aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-01-10 07:32:04 +0000
committerDouglas Gregor <dgregor@apple.com>2011-01-10 07:32:04 +0000
commitd3731198193eee92796ddeb493973b7a598b003e (patch)
tree2e177b315fbcbb6cbfbeb16e30171da0cc1e2e3f
parent2770eb1294f425710e5802011e302a91a3614eb2 (diff)
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
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h16
-rw-r--r--include/clang/AST/TemplateBase.h4
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--include/clang/Sema/Template.h51
-rw-r--r--lib/Sema/SemaTemplate.cpp11
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp120
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp100
-rw-r--r--lib/Sema/SemaTemplateInstantiateDecl.cpp7
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp45
-rw-r--r--lib/Sema/TreeTransform.h84
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp352
-rw-r--r--test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp4
-rw-r--r--test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp8
13 files changed, 738 insertions, 70 deletions
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index ad9f6ddef3..b1fbaa32bb 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1801,7 +1801,7 @@ DEF_TRAVERSE_STMT(CXXDefaultArgExpr, { })
DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
-DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { })
+ DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, { }) // FIXME: Incomplete!
DEF_TRAVERSE_STMT(CXXThisExpr, { })
DEF_TRAVERSE_STMT(CXXThrowExpr, { })
DEF_TRAVERSE_STMT(DesignatedInitExpr, { })
@@ -1820,8 +1820,18 @@ DEF_TRAVERSE_STMT(ParenListExpr, { })
DEF_TRAVERSE_STMT(PredefinedExpr, { })
DEF_TRAVERSE_STMT(ShuffleVectorExpr, { })
DEF_TRAVERSE_STMT(StmtExpr, { })
-DEF_TRAVERSE_STMT(UnresolvedLookupExpr, { })
-DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { })
+DEF_TRAVERSE_STMT(UnresolvedLookupExpr, {
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ S->getNumTemplateArgs()));
+})
+
+DEF_TRAVERSE_STMT(UnresolvedMemberExpr, {
+ TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
+ TRY_TO(TraverseTemplateArgumentLocsHelper(S->getTemplateArgs(),
+ S->getNumTemplateArgs()));
+})
+
DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
DEF_TRAVERSE_STMT(OpaqueValueExpr, { })
diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h
index 22ca164d38..5c7dae0a7c 100644
--- a/include/clang/AST/TemplateBase.h
+++ b/include/clang/AST/TemplateBase.h
@@ -77,7 +77,7 @@ private:
void *Type;
} Integer;
struct {
- TemplateArgument *Args;
+ const TemplateArgument *Args;
unsigned NumArgs;
} Args;
};
@@ -136,7 +136,7 @@ public:
///
/// We assume that storage for the template arguments provided
/// outlives the TemplateArgument itself.
- TemplateArgument(TemplateArgument *Args, unsigned NumArgs) : Kind(Pack) {
+ TemplateArgument(const TemplateArgument *Args, unsigned NumArgs) : Kind(Pack){
this->Args.Args = Args;
this->Args.NumArgs = NumArgs;
}
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 0f15ab85d3..368fe9dffa 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3361,6 +3361,11 @@ public:
/// 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.
@@ -3375,6 +3380,7 @@ public:
unsigned NumUnexpanded,
const MultiLevelTemplateArgumentList &TemplateArgs,
bool &ShouldExpand,
+ bool &RetainExpansion,
unsigned &NumExpansions);
/// \brief Determine whether the given declarator contains any unexpanded
diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h
index 929da6c564..abdec2b8d5 100644
--- a/include/clang/Sema/Template.h
+++ b/include/clang/Sema/Template.h
@@ -81,6 +81,16 @@ namespace clang {
return !(*this)(Depth, Index).isNull();
}
+ /// \brief Clear out a specific template argument.
+ void setArgument(unsigned Depth, unsigned Index,
+ TemplateArgument Arg) {
+ assert(Depth < TemplateArgumentLists.size());
+ assert(Index < TemplateArgumentLists[getNumLevels() - Depth - 1].second);
+ const_cast<TemplateArgument&>(
+ TemplateArgumentLists[getNumLevels() - Depth - 1].first[Index])
+ = Arg;
+ }
+
/// \brief Add a new outermost level to the multi-level template argument
/// list.
void addOuterTemplateArguments(const TemplateArgumentList *TemplateArgs) {
@@ -141,7 +151,7 @@ namespace clang {
: TemplateArgument(Arg), DeducedFromArrayBound(DeducedFromArrayBound) { }
/// \brief Construct an integral non-type template argument that
- /// has been deduced, possible from an array bound.
+ /// has been deduced, possibly from an array bound.
DeducedTemplateArgument(const llvm::APSInt &Value,
QualType ValueType,
bool DeducedFromArrayBound)
@@ -214,6 +224,19 @@ namespace clang {
/// lookup will search our outer scope.
bool CombineWithOuterScope;
+ /// \brief If non-NULL, the template parameter pack that has been
+ /// partially substituted per C++0x [temp.arg.explicit]p9.
+ NamedDecl *PartiallySubstitutedPack;
+
+ /// \brief If \c PartiallySubstitutedPack is non-null, the set of
+ /// explicitly-specified template arguments in that pack.
+ const TemplateArgument *ArgsInPartiallySubstitutedPack;
+
+ /// \brief If \c PartiallySubstitutedPack, the number of
+ /// explicitly-specified template arguments in
+ /// ArgsInPartiallySubstitutedPack.
+ unsigned NumArgsInPartiallySubstitutedPack;
+
// This class is non-copyable
LocalInstantiationScope(const LocalInstantiationScope &);
LocalInstantiationScope &operator=(const LocalInstantiationScope &);
@@ -221,7 +244,8 @@ namespace clang {
public:
LocalInstantiationScope(Sema &SemaRef, bool CombineWithOuterScope = false)
: SemaRef(SemaRef), Outer(SemaRef.CurrentInstantiationScope),
- Exited(false), CombineWithOuterScope(CombineWithOuterScope)
+ Exited(false), CombineWithOuterScope(CombineWithOuterScope),
+ PartiallySubstitutedPack(0)
{
SemaRef.CurrentInstantiationScope = this;
}
@@ -271,6 +295,29 @@ namespace clang {
void InstantiatedLocal(const Decl *D, Decl *Inst);
void InstantiatedLocalPackArg(const Decl *D, Decl *Inst);
void MakeInstantiatedLocalArgPack(const Decl *D);
+
+ /// \brief Note that the given parameter pack has been partially substituted
+ /// via explicit specification of template arguments
+ /// (C++0x [temp.arg.explicit]p9).
+ ///
+ /// \param Pack The parameter pack, which will always be a template
+ /// parameter pack.
+ ///
+ /// \param ExplicitArgs The explicitly-specified template arguments provided
+ /// for this parameter pack.
+ ///
+ /// \param NumExplicitArgs The number of explicitly-specified template
+ /// arguments provided for this parameter pack.
+ void SetPartiallySubstitutedPack(NamedDecl *Pack,
+ const TemplateArgument *ExplicitArgs,
+ unsigned NumExplicitArgs);
+
+ /// \brief Retrieve the partially-substitued template parameter pack.
+ ///
+ /// If there is no partially-substituted parameter pack, returns NULL.
+ NamedDecl *getPartiallySubstitutedPack(
+ const TemplateArgument **ExplicitArgs = 0,
+ unsigned *NumExplicitArgs = 0) const;
};
class TemplateDeclInstantiator
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 2c9a4307ed..f540c7b935 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2550,10 +2550,13 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
// 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 @@ ExprResult
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 8832447314..ff084c34c2 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -478,14 +478,9 @@ static bool IsPossiblyOpaquelyQualifiedType(QualType T) {
}
}
-/// \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 @@ getDepthAndIndex(UnexpandedParameterPack UPP) {
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 @@ DeduceTemplateArguments(Sema &S,
}
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 @@ DeduceTemplateArguments(Sema &S,
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 @@ Sema::SubstituteExplicitTemplateArguments(
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 @@ Sema::SubstituteExplicitTemplateArguments(
// 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 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// 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 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
}
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>
- SavedPacks(PackIndices.size());
+ 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]] = DeducedTemplateArgument();
+ 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);
+ }
}
- // 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;
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 394f50ef69..5f181fb5e1 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -564,6 +564,19 @@ TemplateDeductionInfo *Sema::isSFINAEContext() const {
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 @@ namespace {
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 @@ namespace {
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 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) {
return 0;
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -761,6 +808,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D,
return 0;
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -877,6 +925,7 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E,
return ExprError();
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -981,6 +1030,7 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
return QualType();
}
+ assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size());
Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex];
}
@@ -1272,11 +1322,13 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
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 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) {
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 @@ void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) {
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 e59f94a2ca..c29ff865b2 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1973,13 +1973,16 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
"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 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
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 1928c59642..09e610c675 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -419,14 +419,29 @@ ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
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 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
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 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
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 e2bfb05088..7eee444174 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -89,6 +89,23 @@ using namespace sema;
/// (\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 @@ public:
/// 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 @@ public:
const UnexpandedParameterPack *Unexpanded,
unsigned NumUnexpanded,
bool &ShouldExpand,
+