diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-09-07 02:06:42 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2012-09-07 02:06:42 +0000 |
commit | 6964b3f80ce1ba489e7e25e7cd58062699af9b0c (patch) | |
tree | 23881676ffb0efdee3b8aa5ab6c88b89e7a181e4 /lib | |
parent | 8f0d0fef5f90b16600cdb802d5d7344417c34aad (diff) |
PR9023: A template template parameter whose template parameter list contains an
unexpanded parameter pack is a pack expansion. Thus, as with a non-type template
parameter which is a pack expansion, it needs to be expanded early into a fixed
list of template parameters.
Since the expanded list of template parameters is not itself a parameter pack,
it is permitted to appear before the end of the template parameter list, so also
remove that restriction (for both template template parameter pack expansions and
non-type template parameter pack expansions).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@163369 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 281 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 108 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 21 | ||||
-rw-r--r-- | lib/Serialization/ASTWriterDecl.cpp | 28 |
6 files changed, 351 insertions, 147 deletions
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a7e89994af..fc31d2f55b 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), - NumParams(NumParams) { - for (unsigned Idx = 0; Idx < NumParams; ++Idx) - begin()[Idx] = Params[Idx]; + NumParams(NumParams), ContainsUnexpandedParameterPack(false) { + assert(this->NumParams == NumParams && "Too many template parameters"); + for (unsigned Idx = 0; Idx < NumParams; ++Idx) { + NamedDecl *P = Params[Idx]; + begin()[Idx] = P; + + if (!P->isTemplateParameterPack()) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) + if (NTTP->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) + if (TTP->getTemplateParameters()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + // FIXME: If a default argument contains an unexpanded parameter pack, the + // template parameter list does too. + } + } } TemplateParameterList * @@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { void TemplateTemplateParmDecl::anchor() { } +TemplateTemplateParmDecl::TemplateTemplateParmDecl( + DeclContext *DC, SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, TemplateParameterList *Params, + unsigned NumExpansions, TemplateParameterList * const *Expansions) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), DefaultArgument(), + DefaultArgumentWasInherited(false), ParameterPack(true), + ExpandedParameterPack(true), NumExpandedParams(NumExpansions) { + if (Expansions) + std::memcpy(reinterpret_cast<void*>(this + 1), Expansions, + sizeof(TemplateParameterList*) * NumExpandedParams); +} + TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, @@ -587,12 +616,35 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, } TemplateTemplateParmDecl * +TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, + TemplateParameterList *Params, + llvm::ArrayRef<TemplateParameterList*> Expansions) { + void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * Expansions.size()); + return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params, + Expansions.size(), + Expansions.data()); +} + +TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl)); return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false, 0, 0); } +TemplateTemplateParmDecl * +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumExpansions) { + unsigned Size = sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * NumExpansions; + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0, + NumExpansions, 0); +} + //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index d6ad8ebf53..1e81f0d299 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1205,11 +1205,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, /// of a template template parameter, recursively. static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP) { + // A template template parameter which is a parameter pack is also a pack + // expansion. + if (TTP->isParameterPack()) + return false; + TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { - if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), + if (!NTTP->isParameterPack() && + S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), NTTP->getTypeSourceInfo(), Sema::UPPC_NonTypeTemplateParameterType)) return true; @@ -1322,7 +1328,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (NonTypeTemplateParmDecl *NewNonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), + if (!NewNonTypeParm->isParameterPack() && + DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), NewNonTypeParm->getTypeSourceInfo(), UPPC_NonTypeTemplateParameterType)) { Invalid = true; @@ -1343,7 +1350,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (NewNonTypeParm->isParameterPack()) { assert(!NewNonTypeParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); - SawParameterPack = true; + if (!NewNonTypeParm->isPackExpansion()) + SawParameterPack = true; } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && NewNonTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); @@ -1390,7 +1398,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (NewTemplateParm->isParameterPack()) { assert(!NewTemplateParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); - SawParameterPack = true; + if (!NewTemplateParm->isPackExpansion()) + SawParameterPack = true; } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); @@ -1417,10 +1426,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, MissingDefaultArg = true; } - // C++0x [temp.param]p11: + // C++11 [temp.param]p11: // If a template parameter of a primary class template or alias template // is a template parameter pack, it shall be the last template parameter. - if (SawParameterPack && (NewParam + 1) != NewParamEnd && + if (SawParameterPack && (NewParam + 1) != NewParamEnd && (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { Diag((*NewParam)->getLocation(), diag::err_template_param_pack_must_be_last_template_parameter); @@ -2950,7 +2959,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateArgument(TempParm, Arg)) + if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex)) return true; Converted.push_back(Arg.getArgument()); @@ -2999,6 +3008,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, return true; } +/// \brief Check whether the template parameter is a pack expansion, and if so, +/// determine the number of parameters produced by that expansion. For instance: +/// +/// \code +/// template<typename ...Ts> struct A { +/// template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B; +/// }; +/// \endcode +/// +/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us +/// is not a pack expansion, so returns an empty Optional. +static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + } + + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionTemplateParameters(); + } + + return llvm::Optional<unsigned>(); +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -3011,15 +3047,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, *ExpansionIntoFixedList = false; TemplateParameterList *Params = Template->getTemplateParameters(); - unsigned NumParams = Params->size(); - unsigned NumArgs = TemplateArgs.size(); - bool Invalid = false; SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc(); - bool HasParameterPack = - NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); - // C++ [temp.arg]p1: // [...] The type and form of each template-argument specified in // a template-id shall match the type and form specified for the @@ -3027,38 +3057,53 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // template-parameter-list. bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); SmallVector<TemplateArgument, 2> ArgumentPack; - TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - unsigned ArgIdx = 0; + unsigned ArgIdx = 0, NumArgs = TemplateArgs.size(); LocalInstantiationScope InstScope(*this, true); - bool SawPackExpansion = false; - while (Param != ParamEnd) { - if (ArgIdx < NumArgs) { - // If we have an expanded parameter pack, make sure we don't have too - // many arguments. - // FIXME: This really should fall out from the normal arity checking. - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << true - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) - << Template; - Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; /* increment in loop */) { + // If we have an expanded parameter pack, make sure we don't have too + // many arguments. + if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) { + if (*Expansions == ArgumentPack.size()) { + // We're done with this parameter pack. Pack up its arguments and add + // them to the list. + if (ArgumentPack.empty()) + Converted.push_back(TemplateArgument(0, 0)); + else { + Converted.push_back( + TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); } + // This argument is assigned to the next parameter. + ++Param; + continue; + } else if (ArgIdx == NumArgs && !PartialTemplateArgs) { + // Not enough arguments for this parameter pack. + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << false + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; } + } + if (ArgIdx < NumArgs) { // Check the template argument we were given. if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, TemplateLoc, RAngleLoc, ArgumentPack.size(), Converted)) return true; + // We're now done with this argument. + ++ArgIdx; + if ((*Param)->isTemplateParameterPack()) { // The template parameter was a template parameter pack, so take the // deduced argument and place it on the argument pack. Note that we @@ -3070,16 +3115,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Move to the next template parameter. ++Param; } - - // If this template argument is a pack expansion, record that fact - // and break out; we can't actually check any more. - if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) { - SawPackExpansion = true; - ++ArgIdx; - break; + + // If we just saw a pack expansion, then directly convert the remaining + // arguments, because we don't know what parameters they'll match up + // with. + if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) { + bool InFinalParameterPack = Param != ParamEnd && + Param + 1 == ParamEnd && + (*Param)->isTemplateParameterPack() && + !getExpandedPackSize(*Param); + + if (!InFinalParameterPack && !ArgumentPack.empty()) { + // If we were part way through filling in an expanded parameter pack, + // fall back to just producing individual arguments. + Converted.insert(Converted.end(), + ArgumentPack.begin(), ArgumentPack.end()); + ArgumentPack.clear(); + } + + while (ArgIdx < NumArgs) { + if (InFinalParameterPack) + ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument()); + else + Converted.push_back(TemplateArgs[ArgIdx].getArgument()); + ++ArgIdx; + } + + // Push the argument pack onto the list of converted arguments. + if (InFinalParameterPack) { + if (ArgumentPack.empty()) + Converted.push_back(TemplateArgument(0, 0)); + else { + Converted.push_back( + TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + } + } else if (ExpansionIntoFixedList) { + // We have expanded a pack into a fixed list. + *ExpansionIntoFixedList = true; + } + + return false; } - - ++ArgIdx; + continue; } @@ -3090,14 +3170,34 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ArgumentPack.data(), ArgumentPack.size())); - return Invalid; + return false; } // If we have a template parameter pack with no more corresponding // arguments, just break out now and we'll fill in the argument pack below. - if ((*Param)->isTemplateParameterPack()) - break; - + if ((*Param)->isTemplateParameterPack()) { + assert(!getExpandedPackSize(*Param) && + "Should have dealt with this already"); + + // A non-expanded parameter pack before the end of the parameter list + // only occurs for an ill-formed template parameter list, unless we've + // got a partial argument list for a function template, so just bail out. + if (Param + 1 != ParamEnd) + return true; + + if (ArgumentPack.empty()) + Converted.push_back(TemplateArgument(0, 0)); + else { + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + } + + ++Param; + continue; + } + // Check whether we have a default argument. TemplateArgumentLoc Arg; @@ -3184,86 +3284,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ++ArgIdx; } - // If we saw a pack expansion, then directly convert the remaining arguments, - // because we don't know what parameters they'll match up with. - if (SawPackExpansion) { - bool AddToArgumentPack - = Param != ParamEnd && (*Param)->isTemplateParameterPack(); - while (ArgIdx < NumArgs) { - if (AddToArgumentPack) - ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument()); - else - Converted.push_back(TemplateArgs[ArgIdx].getArgument()); - ++ArgIdx; - } - - // Push the argument pack onto the list of converted arguments. - if (AddToArgumentPack) { - if (ArgumentPack.empty()) - Converted.push_back(TemplateArgument(0, 0)); - else { - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, - ArgumentPack.data(), - ArgumentPack.size())); - ArgumentPack.clear(); - } - } else if (ExpansionIntoFixedList) { - // We have expanded a pack into a fixed list. - *ExpansionIntoFixedList = true; - } - - return Invalid; - } - // If we have any leftover arguments, then there were too many arguments. // Complain and fail. if (ArgIdx < NumArgs) return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); - - // If we have an expanded parameter pack, make sure we don't have too - // many arguments. - // FIXME: This really should fall out from the normal arity checking. - if (Param != ParamEnd) { - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() < NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << false - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) - << Template; - Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; - } - } - } - - // 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()) { - if (!HasParameterPack) - return true; - if (ArgumentPack.empty()) - Converted.push_back(TemplateArgument(0, 0)); - else { - Converted.push_back(TemplateArgument::CreatePackCopy(Context, - ArgumentPack.data(), - ArgumentPack.size())); - ArgumentPack.clear(); - } - } else if (!PartialTemplateArgs) - return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); - ++Param; - } - - return Invalid; + return false; } namespace { @@ -4420,7 +4446,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - const TemplateArgumentLoc &Arg) { + const TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex) { TemplateName Name = Arg.getArgument().getAsTemplate(); TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { @@ -4451,8 +4478,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, << Template; } + TemplateParameterList *Params = Param->getTemplateParameters(); + if (Param->isExpandedParameterPack()) + Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), - Param->getTemplateParameters(), + Params, true, TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index b8f0bca296..b236f2861e 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -573,7 +573,7 @@ static void PrepareArgumentPackDeduction(Sema &S, if (!S.CurrentInstantiationScope) continue; - // If the template arugment pack was explicitly specified, add that to + // If the template argument pack was explicitly specified, add that to // the set of deduced arguments. const TemplateArgument *ExplicitArgs; unsigned NumExplicitArgs; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 28e4116534..55462ff09b 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1657,7 +1657,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( IsExpandedParameterPack = true; DI = D->getTypeSourceInfo(); T = DI->getType(); - } else if (isa<PackExpansionTypeLoc>(TL)) { + } else if (D->isPackExpansion()) { // The non-type template parameter pack's type is a pack expansion of types. // Determine whether we need to expand this parameter pack into separate // types. @@ -1771,27 +1771,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return Param; } +static void collectUnexpandedParameterPacks( + Sema &S, + TemplateParameterList *Params, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + for (TemplateParameterList::const_iterator I = Params->begin(), + E = Params->end(); I != E; ++I) { + if ((*I)->isTemplateParameterPack()) + continue; + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I)) + S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(), + Unexpanded); + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I)) + collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(), + Unexpanded); + } +} + Decl * TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( TemplateTemplateParmDecl *D) { // Instantiate the template parameter list of the template template parameter. TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams; - { + SmallVector<TemplateParameterList*, 8> ExpandedParams; + + bool IsExpandedParameterPack = false; + + if (D->isExpandedParameterPack()) { + // The template template parameter pack is an already-expanded pack + // expansion of template parameters. Substitute into each of the expanded + // parameters. + ExpandedParams.reserve(D->getNumExpansionTemplateParameters()); + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) { + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *Expansion = + SubstTemplateParams(D->getExpansionTemplateParameters(I)); + if (!Expansion) + return 0; + ExpandedParams.push_back(Expansion); + } + + IsExpandedParameterPack = true; + InstParams = TempParams; + } else if (D->isPackExpansion()) { + // The template template parameter pack expands to a pack of template + // template parameters. Determine whether we need to expand this parameter + // pack into separate parameters. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(), + Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(), + TempParams->getSourceRange(), + Unexpanded, + TemplateArgs, + Expand, RetainExpansion, + NumExpansions)) + return 0; + + if (Expand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *Expansion = SubstTemplateParams(TempParams); + if (!Expansion) + return 0; + ExpandedParams.push_back(Expansion); + } + + // Note that we have an expanded parameter pack. The "type" of this + // expanded parameter pack is the original expansion type, but callers + // will end up using the expanded parameter pack types for type-checking. + IsExpandedParameterPack = true; + InstParams = TempParams; + } else { + // We cannot fully expand the pack expansion now, so just substitute + // into the pattern. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + + LocalInstantiationScope Scope(SemaRef); + InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + } + } else { // Perform the actual substitution of template parameters within a new, // local instantiation scope. LocalInstantiationScope Scope(SemaRef); InstParams = SubstTemplateParams(TempParams); if (!InstParams) - return NULL; + return 0; } // Build the template template parameter. - TemplateTemplateParmDecl *Param - = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + TemplateTemplateParmDecl *Param; + if (IsExpandedParameterPack) + Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), InstParams, + ExpandedParams); + else + Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->isParameterPack(), - D->getIdentifier(), InstParams); + D->getPosition(), + D->isParameterPack(), + D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); Param->setAccess(AS_public); diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 2418f3a167..ba830d172c 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1486,11 +1486,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // TemplateParmPosition. D->setDepth(Record[Idx++]); D->setPosition(Record[Idx++]); - // Rest of TemplateTemplateParmDecl. - TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx); - bool IsInherited = Record[Idx++]; - D->setDefaultArgument(Arg, IsInherited); - D->ParameterPack = Record[Idx++]; + if (D->isExpandedParameterPack()) { + void **Data = reinterpret_cast<void **>(D + 1); + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) + Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx); + } else { + // Rest of TemplateTemplateParmDecl. + TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx); + bool IsInherited = Record[Idx++]; + D->setDefaultArgument(Arg, IsInherited); + D->ParameterPack = Record[Idx++]; + } } void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { @@ -2004,6 +2011,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_TEMPLATE_TEMPLATE_PARM: D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID); break; + case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK: + D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID, + Record[Idx++]); + break; case DECL_TYPE_ALIAS_TEMPLATE: D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID); break; diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 602943b9ba..baa8a0e4cd 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -1172,7 +1172,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // For an expanded parameter pack, record the number of expansion types here - // so that it's easier for + // so that it's easier for deserialization to allocate the right amount of + // memory. if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); @@ -1201,15 +1202,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { } void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + // For an expanded parameter pack, record the number of expansion types here + // so that it's easier for deserialization to allocate the right amount of + // memory. + if (D->isExpandedParameterPack()) + Record.push_back(D->getNumExpansionTemplateParameters()); + VisitTemplateDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); - // Rest of TemplateTemplateParmDecl. - Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); - Record.push_back(D->defaultArgumentWasInherited()); - Record.push_back(D->isParameterPack()); - Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; + + if (D->isExpandedParameterPack()) { + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) + Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I), + Record); + Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; + } else { + // Rest of TemplateTemplateParmDecl. + Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); + Record.push_back(D->defaultArgumentWasInherited()); + Record.push_back(D->isParameterPack()); + Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; + } } void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { |