diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-01-10 07:32:04 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-01-10 07:32:04 +0000 |
commit | d3731198193eee92796ddeb493973b7a598b003e (patch) | |
tree | 2e177b315fbcbb6cbfbeb16e30171da0cc1e2e3f | |
parent | 2770eb1294f425710e5802011e302a91a3614eb2 (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.h | 16 | ||||
-rw-r--r-- | include/clang/AST/TemplateBase.h | 4 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 6 | ||||
-rw-r--r-- | include/clang/Sema/Template.h | 51 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 120 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 100 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 84 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/example-bind.cpp | 352 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/example-tuple.cpp | 4 | ||||
-rw-r--r-- | test/CXX/temp/temp.fct.spec/temp.arg.explicit/p9-0x.cpp | 8 |
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, + |