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 /lib/Sema | |
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
Diffstat (limited to 'lib/Sema')
-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 |
6 files changed, 313 insertions, 54 deletions
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, + 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 @@ bool TreeTransform<Derived>::TransformExprs(Expr **Inputs, // 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 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, // 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 @@ bool TreeTransform<Derived>::TransformTemplateArguments(InputIterator First, Outputs.addArgument(Out); } + // FIXME: Variadic templates retain expansion! + continue; } @@ -3415,12 +3461,15 @@ bool TreeTransform<Derived>:: // 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 @@ bool TreeTransform<Derived>:: 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 @@ bool TreeTransform<Derived>:: // 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 @@ bool TreeTransform<Derived>:: 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 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { // 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 |