From: Richard Smith Date: Thu, 19 Jul 2018 19:00:37 +0000 (+0000) Subject: Fix template argument deduction when a parameter pack has a value X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0f6b139a0ce2f74a708f120da6336c05c14ea1cb;p=clang Fix template argument deduction when a parameter pack has a value provided by an outer template. We made the incorrect assumption in various places that the only way we can have any arguments already provided for a pack during template argument deduction was from a partially-specified pack. That's not true; we can also have arguments from an enclosing already-instantiated template, and that can even result in the function template's own pack parameters having a fixed length and not being packs for the purposes of template argument deduction. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@337481 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3bda262963..ee51db2d0a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3589,6 +3589,9 @@ def note_ovl_candidate_bad_deduction : Note< "candidate template ignored: failed template argument deduction">; def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: " "couldn't infer template argument %0">; +def note_ovl_candidate_incomplete_deduction_pack : Note<"candidate template ignored: " + "deduced too few arguments for expanded pack %0; no argument for %ordinal1 " + "expanded parameter in deduced argument pack %2">; def note_ovl_candidate_inconsistent_deduction : Note< "candidate template ignored: deduced conflicting %select{types|values|" "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">; @@ -4462,6 +4465,9 @@ def err_pack_expansion_length_conflict : Error< def err_pack_expansion_length_conflict_multilevel : Error< "pack expansion contains parameter pack %0 that has a different " "length (%1 vs. %2) from outer parameter packs">; +def err_pack_expansion_length_conflict_partial : Error< + "pack expansion contains parameter pack %0 that has a different " + "length (at least %1 vs. %2) from outer parameter packs">; def err_pack_expansion_member_init : Error< "pack expansion for initialization of member %0">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 4ef982e24f..0aa1fc42c6 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -6911,6 +6911,9 @@ public: /// Template argument deduction did not deduce a value /// for every template parameter. TDK_Incomplete, + /// Template argument deduction did not deduce a value for every + /// expansion of an expanded template parameter pack. + TDK_IncompletePack, /// Template argument deduction produced inconsistent /// deduced values for the given template parameter. TDK_Inconsistent, diff --git a/include/clang/Sema/TemplateDeduction.h b/include/clang/Sema/TemplateDeduction.h index bf379db2ae..93395b4945 100644 --- a/include/clang/Sema/TemplateDeduction.h +++ b/include/clang/Sema/TemplateDeduction.h @@ -51,6 +51,10 @@ class TemplateDeductionInfo { /// The template parameter depth for which we're performing deduction. unsigned DeducedDepth; + /// The number of parameters with explicitly-specified template arguments, + /// up to and including the partially-specified pack (if any). + unsigned ExplicitArgs = 0; + /// Warnings (and follow-on notes) that were suppressed due to /// SFINAE while performing template argument deduction. SmallVector SuppressedDiagnostics; @@ -73,6 +77,11 @@ public: return DeducedDepth; } + /// Get the number of explicitly-specified arguments. + unsigned getNumExplicitArgs() const { + return ExplicitArgs; + } + /// Take ownership of the deduced template argument list. TemplateArgumentList *take() { TemplateArgumentList *Result = Deduced; @@ -100,6 +109,13 @@ public: return SuppressedDiagnostics.front(); } + /// Provide an initial template argument list that contains the + /// explicitly-specified arguments. + void setExplicitArgs(TemplateArgumentList *NewDeduced) { + Deduced = NewDeduced; + ExplicitArgs = Deduced->size(); + } + /// Provide a new template argument list that contains the /// results of template argument deduction. void reset(TemplateArgumentList *NewDeduced) { @@ -149,6 +165,9 @@ public: /// TDK_Incomplete: this is the first template parameter whose /// corresponding template argument was not deduced. /// + /// TDK_IncompletePack: this is the expanded parameter pack for + /// which we deduced too few arguments. + /// /// TDK_Inconsistent: this is the template parameter for which /// two different template argument values were deduced. TemplateParameter Param; @@ -159,6 +178,9 @@ public: /// Depending on the result of the template argument deduction, /// this template argument may have different meanings: /// + /// TDK_IncompletePack: this is the number of arguments we deduced + /// for the pack. + /// /// TDK_Inconsistent: this argument is the first value deduced /// for the corresponding template parameter. /// diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 35c3612c71..822c3c0c6b 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -629,6 +629,8 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } + case Sema::TDK_IncompletePack: + // FIXME: It's slightly wasteful to allocate two TemplateArguments for this. case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. @@ -671,6 +673,7 @@ void DeductionFailureInfo::Destroy() { case Sema::TDK_NonDependentConversionFailure: break; + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: @@ -720,6 +723,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_InvalidExplicitArguments: return TemplateParameter::getFromOpaqueValue(Data); + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: return static_cast(Data)->Param; @@ -740,6 +744,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: @@ -777,6 +782,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { case Sema::TDK_NonDependentConversionFailure: return nullptr; + case Sema::TDK_IncompletePack: case Sema::TDK_Inconsistent: case Sema::TDK_Underqualified: case Sema::TDK_DeducedMismatch: @@ -798,6 +804,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: @@ -9893,6 +9900,17 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } + case Sema::TDK_IncompletePack: { + assert(ParamD && "no parameter found for incomplete deduction result"); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_incomplete_deduction_pack) + << ParamD->getDeclName() + << (DeductionFailure.getFirstArg()->pack_size() + 1) + << *DeductionFailure.getFirstArg(); + MaybeEmitInheritedConstructorNote(S, Found); + return; + } + case Sema::TDK_Underqualified: { assert(ParamD && "no parameter found for bad qualifiers deduction result"); TemplateTypeParmDecl *TParam = cast(ParamD); @@ -10372,6 +10390,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { case Sema::TDK_Invalid: case Sema::TDK_Incomplete: + case Sema::TDK_IncompletePack: return 1; case Sema::TDK_Underqualified: diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c1d8c24796..935264cb8c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4914,27 +4914,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return false; } -/// Diagnose an arity mismatch in the -static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, - SourceLocation TemplateLoc, - TemplateArgumentListInfo &TemplateArgs) { - TemplateParameterList *Params = Template->getTemplateParameters(); - unsigned NumParams = Params->size(); - unsigned NumArgs = TemplateArgs.size(); - - SourceRange Range; - if (NumArgs > NumParams) - Range = SourceRange(TemplateArgs[NumParams].getLocation(), - TemplateArgs.getRAngleLoc()); - S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << (NumArgs > NumParams) - << (int)S.getTemplateNameKindForDiagnostics(TemplateName(Template)) - << Template << Range; - S.Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; -} - /// Check whether the template parameter is a pack expansion, and if so, /// determine the number of parameters produced by that expansion. For instance: /// @@ -4988,7 +4967,15 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, // FIXME: If there's a more recent default argument that *is* visible, // diagnose that it was declared too late. - return diagnoseArityMismatch(S, TD, Loc, Args); + TemplateParameterList *Params = TD->getTemplateParameters(); + + S.Diag(Loc, diag::err_template_arg_list_different_arity) + << /*not enough args*/0 + << (int)S.getTemplateNameKindForDiagnostics(TemplateName(TD)) + << TD; + S.Diag(TD->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; } /// Check that the given template argument list is well-formed @@ -5040,7 +5027,7 @@ bool Sema::CheckTemplateArgumentList( } else if (ArgIdx == NumArgs && !PartialTemplateArgs) { // Not enough arguments for this parameter pack. Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << false + << /*not enough args*/0 << (int)getTemplateNameKindForDiagnostics(TemplateName(Template)) << Template; Diag(Template->getLocation(), diag::note_template_decl_here) @@ -5235,8 +5222,16 @@ bool Sema::CheckTemplateArgumentList( // If we have any leftover arguments, then there were too many arguments. // Complain and fail. - if (ArgIdx < NumArgs) - return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs); + if (ArgIdx < NumArgs) { + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << /*too many args*/1 + << (int)getTemplateNameKindForDiagnostics(TemplateName(Template)) + << Template + << SourceRange(NewArgs[ArgIdx].getLocation(), NewArgs.getRAngleLoc()); + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; + } // No problems found with the new argument list, propagate changes back // to caller. diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 51d2bae08c..0b41a515d9 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -662,6 +662,19 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast(D)); } +/// If \p Param is an expanded parameter pack, get the number of expansions. +static Optional getExpandedPackSize(NamedDecl *Param) { + if (auto *NTTP = dyn_cast(Param)) + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + + if (auto *TTP = dyn_cast(Param)) + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionTemplateParameters(); + + return None; +} + /// A pack that we're currently deducing. struct clang::DeducedPack { // The index of the pack. @@ -688,10 +701,83 @@ namespace { /// A scope in which we're performing pack deduction. class PackDeductionScope { public: + /// Prepare to deduce the packs named within Pattern. PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams, SmallVectorImpl &Deduced, TemplateDeductionInfo &Info, TemplateArgument Pattern) : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) { + unsigned NumNamedPacks = addPacks(Pattern); + finishConstruction(NumNamedPacks); + } + + /// Prepare to directly deduce arguments of the parameter with index \p Index. + PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams, + SmallVectorImpl &Deduced, + TemplateDeductionInfo &Info, unsigned Index) + : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) { + addPack(Index); + finishConstruction(1); + } + +private: + void addPack(unsigned Index) { + // Save the deduced template argument for the parameter pack expanded + // by this pack expansion, then clear out the deduction. + DeducedPack Pack(Index); + Pack.Saved = Deduced[Index]; + Deduced[Index] = TemplateArgument(); + + // FIXME: What if we encounter multiple packs with different numbers of + // pre-expanded expansions? (This should already have been diagnosed + // during substitution.) + if (Optional ExpandedPackExpansions = + getExpandedPackSize(TemplateParams->getParam(Index))) + FixedNumExpansions = ExpandedPackExpansions; + + Packs.push_back(Pack); + } + + unsigned addPacks(TemplateArgument Pattern) { + // Compute the set of template parameter indices that correspond to + // parameter packs expanded by the pack expansion. + llvm::SmallBitVector SawIndices(TemplateParams->size()); + + auto AddPack = [&](unsigned Index) { + if (SawIndices[Index]) + return; + SawIndices[Index] = true; + addPack(Index); + }; + + // First look for unexpanded packs in the pattern. + SmallVector Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == Info.getDeducedDepth()) + AddPack(Index); + } + assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); + + unsigned NumNamedPacks = Packs.size(); + + // We can also have deduced template parameters that do not actually + // appear in the pattern, but can be deduced by it (the type of a non-type + // template parameter pack, in particular). These won't have prevented us + // from partially expanding the pack. + llvm::SmallBitVector Used(TemplateParams->size()); + MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, + Info.getDeducedDepth(), Used); + for (int Index = Used.find_first(); Index != -1; + Index = Used.find_next(Index)) + if (TemplateParams->getParam(Index)->isParameterPack()) + AddPack(Index); + + return NumNamedPacks; + } + + void finishConstruction(unsigned NumNamedPacks) { // Dig out the partially-substituted pack, if there is one. const TemplateArgument *PartialPackArgs = nullptr; unsigned NumPartialPackArgs = 0; @@ -701,60 +787,29 @@ public: &PartialPackArgs, &NumPartialPackArgs)) PartialPackDepthIndex = getDepthAndIndex(Partial); - // Compute the set of template parameter indices that correspond to - // parameter packs expanded by the pack expansion. - { - llvm::SmallBitVector SawIndices(TemplateParams->size()); - - auto AddPack = [&](unsigned Index) { - if (SawIndices[Index]) - return; - SawIndices[Index] = true; - - // Save the deduced template argument for the parameter pack expanded - // by this pack expansion, then clear out the deduction. - DeducedPack Pack(Index); - Pack.Saved = Deduced[Index]; - Deduced[Index] = TemplateArgument(); - - Packs.push_back(Pack); - }; - - // First look for unexpanded packs in the pattern. - SmallVector Unexpanded; - S.collectUnexpandedParameterPacks(Pattern, Unexpanded); - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); - if (Depth == Info.getDeducedDepth()) - AddPack(Index); + // This pack expansion will have been partially or fully expanded if + // it only names explicitly-specified parameter packs (including the + // partially-substituted one, if any). + bool IsExpanded = true; + for (unsigned I = 0; I != NumNamedPacks; ++I) { + if (Packs[I].Index >= Info.getNumExplicitArgs()) { + IsExpanded = false; + IsPartiallyExpanded = false; + break; + } + if (PartialPackDepthIndex == + std::make_pair(Info.getDeducedDepth(), Packs[I].Index)) { + IsPartiallyExpanded = true; } - assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); - - // This pack expansion will have been partially expanded iff the only - // unexpanded parameter pack within it is the partially-substituted pack. - IsPartiallyExpanded = - Packs.size() == 1 && - PartialPackDepthIndex == - std::make_pair(Info.getDeducedDepth(), Packs.front().Index); - - // Skip over the pack elements that were expanded into separate arguments. - if (IsPartiallyExpanded) - PackElements += NumPartialPackArgs; - - // We can also have deduced template parameters that do not actually - // appear in the pattern, but can be deduced by it (the type of a non-type - // template parameter pack, in particular). These won't have prevented us - // from partially expanding the pack. - llvm::SmallBitVector Used(TemplateParams->size()); - MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, - Info.getDeducedDepth(), Used); - for (int Index = Used.find_first(); Index != -1; - Index = Used.find_next(Index)) - if (TemplateParams->getParam(Index)->isParameterPack()) - AddPack(Index); } + // Skip over the pack elements that were expanded into separate arguments. + // If we partially expanded, this is the number of partial arguments. + if (IsPartiallyExpanded) + PackElements += NumPartialPackArgs; + else if (IsExpanded) + PackElements += *FixedNumExpansions; + for (auto &Pack : Packs) { if (Info.PendingDeducedPacks.size() > Pack.Index) Pack.Outer = Info.PendingDeducedPacks[Pack.Index]; @@ -773,12 +828,13 @@ public: // FIXME: If we could represent a "depth i, index j, pack elem k" // parameter, we could substitute the partially-substituted pack // everywhere and avoid this. - if (Pack.New.size() > PackElements) + if (!IsPartiallyExpanded) Deduced[Pack.Index] = Pack.New[PackElements]; } } } +public: ~PackDeductionScope() { for (auto &Pack : Packs) Info.PendingDeducedPacks[Pack.Index] = Pack.Outer; @@ -788,6 +844,18 @@ public: /// sequence of (prior) function parameters / template arguments. bool isPartiallyExpanded() { return IsPartiallyExpanded; } + /// Determine whether this pack expansion scope has a known, fixed arity. + /// This happens if it involves a pack from an outer template that has + /// (notionally) already been expanded. + bool hasFixedArity() { return FixedNumExpansions.hasValue(); } + + /// Determine whether the next element of the argument is still part of this + /// pack. This is the case unless the pack is already expanded to a fixed + /// length. + bool hasNextElement() { + return !FixedNumExpansions || *FixedNumExpansions > PackElements; + } + /// Move to deducing the next element in each pack that is being deduced. void nextPackElement() { // Capture the deduced template arguments for each parameter pack expanded @@ -813,13 +881,21 @@ public: /// Finish template argument deduction for a set of argument packs, /// producing the argument packs and checking for consistency with prior /// deductions. - Sema::TemplateDeductionResult finish() { + Sema::TemplateDeductionResult + finish(bool TreatNoDeductionsAsNonDeduced = true) { // Build argument packs for each of the parameter packs expanded by this // pack expansion. for (auto &Pack : Packs) { // Put back the old value for this pack. Deduced[Pack.Index] = Pack.Saved; + // If we are deducing the size of this pack even if we didn't deduce any + // values for it, then make sure we build a pack of the right size. + // FIXME: Should we always deduce the size, even if the pack appears in + // a non-deduced context? + if (!TreatNoDeductionsAsNonDeduced) + Pack.New.resize(PackElements); + // Build or find a new value for this pack. DeducedTemplateArgument NewPack; if (PackElements && Pack.New.empty()) { @@ -875,14 +951,24 @@ public: Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack); } + NamedDecl *Param = TemplateParams->getParam(Pack.Index); if (Result.isNull()) { - Info.Param = - makeTemplateParameter(TemplateParams->getParam(Pack.Index)); + Info.Param = makeTemplateParameter(Param); Info.FirstArg = OldPack; Info.SecondArg = NewPack; return Sema::TDK_Inconsistent; } + // If we have a pre-expanded pack and we didn't deduce enough elements + // for it, fail deduction. + if (Optional Expansions = getExpandedPackSize(Param)) { + if (*Expansions != PackElements) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = Result; + return Sema::TDK_IncompletePack; + } + } + *Loc = Result; } @@ -896,6 +982,8 @@ private: TemplateDeductionInfo &Info; unsigned PackElements = 0; bool IsPartiallyExpanded = false; + /// The number of expansions, if we have a fully-expanded pack in this scope. + Optional FixedNumExpansions; SmallVector Packs; }; @@ -987,8 +1075,10 @@ DeduceTemplateArguments(Sema &S, QualType Pattern = Expansion->getPattern(); PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern); - if (ParamIdx + 1 == NumParams) { - for (; ArgIdx < NumArgs; ++ArgIdx) { + // A pack scope with fixed arity is not really a pack any more, so is not + // a non-deduced context. + if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { + for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern, @@ -2193,6 +2283,8 @@ static bool hasPackExpansionBeforeEnd(ArrayRef Args) { if (A.getKind() == TemplateArgument::Pack) return hasPackExpansionBeforeEnd(A.pack_elements()); + // FIXME: If this is a fixed-arity pack expansion from an outer level of + // templates, it should not be treated as a pack expansion. if (A.isPackExpansion()) FoundPackExpansion = true; } @@ -2262,7 +2354,9 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // 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). - for (; hasTemplateArgumentForDeduction(Args, ArgIdx); ++ArgIdx) { + for (; hasTemplateArgumentForDeduction(Args, ArgIdx) && + PackScope.hasNextElement(); + ++ArgIdx) { // Deduce template arguments from the pattern. if (Sema::TemplateDeductionResult Result = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx], @@ -2534,6 +2628,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NamedDecl *Param = TemplateParams->getParam(I); + // C++0x [temp.arg.explicit]p3: + // A trailing template parameter pack (14.5.3) not otherwise deduced will + // be deduced to an empty sequence of template arguments. + // FIXME: Where did the word "trailing" come from? + if (Deduced[I].isNull() && Param->isTemplateParameterPack()) { + if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I) + .finish(/*TreatNoDeductionsAsNonDeduced*/false)) + return Result; + } + if (!Deduced[I].isNull()) { if (I < NumAlreadyConverted) { // We may have had explicitly-specified template arguments for a @@ -2568,40 +2672,6 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( continue; } - // C++0x [temp.arg.explicit]p3: - // A trailing template parameter pack (14.5.3) not otherwise deduced will - // be deduced to an empty sequence of template arguments. - // FIXME: Where did the word "trailing" come from? - if (Param->isTemplateParameterPack()) { - // 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 && - CurrentInstantiationScope->getPartiallySubstitutedPack( - &ExplicitArgs, &NumExplicitArgs) == Param) { - Builder.push_back(TemplateArgument( - llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); - - // Forget the partially-substituted pack; its substitution is now - // complete. - CurrentInstantiationScope->ResetPartiallySubstitutedPack(); - } else { - // Go through the motions of checking the empty argument pack against - // the parameter pack. - DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack()); - if (ConvertDeducedTemplateArgument(S, Param, DeducedPack, Template, - Info, IsDeduced, Builder)) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); - return Sema::TDK_SubstitutionFailure; - } - } - continue; - } - // Substitute into the default template argument, if available. bool HasDefaultArg = false; TemplateDecl *TD = dyn_cast(Template); @@ -2962,7 +3032,7 @@ Sema::SubstituteExplicitTemplateArguments( Trap.hasErrorOccurred()) { unsigned Index = Builder.size(); if (Index >= TemplateParams->size()) - Index = TemplateParams->size() - 1; + return TDK_SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); return TDK_InvalidExplicitArguments; } @@ -2971,7 +3041,7 @@ Sema::SubstituteExplicitTemplateArguments( // template arguments. TemplateArgumentList *ExplicitArgumentList = TemplateArgumentList::CreateCopy(Context, Builder); - Info.reset(ExplicitArgumentList); + Info.setExplicitArgs(ExplicitArgumentList); // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit @@ -2983,14 +3053,19 @@ Sema::SubstituteExplicitTemplateArguments( // 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. - for (unsigned I = 0, N = Builder.size(); I != N; ++I) { - const TemplateArgument &Arg = Builder[I]; + unsigned PartiallySubstitutedPackIndex = -1u; + if (!Builder.empty()) { + const TemplateArgument &Arg = Builder.back(); if (Arg.getKind() == TemplateArgument::Pack) { - CurrentInstantiationScope->SetPartiallySubstitutedPack( - TemplateParams->getParam(I), - Arg.pack_begin(), - Arg.pack_size()); - break; + auto *Param = TemplateParams->getParam(Builder.size() - 1); + // If this is a fully-saturated fixed-size pack, it should be + // fully-substituted, not partially-substituted. + Optional Expansions = getExpandedPackSize(Param); + if (!Expansions || Arg.pack_size() < *Expansions) { + PartiallySubstitutedPackIndex = Builder.size() - 1; + CurrentInstantiationScope->SetPartiallySubstitutedPack( + Param, Arg.pack_begin(), Arg.pack_size()); + } } } @@ -3080,13 +3155,13 @@ Sema::SubstituteExplicitTemplateArguments( // 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. Explicitly-specified - // parameter packs, however, will be set to NULL since the deduction - // mechanisms handle explicitly-specified argument packs directly. + // the set of deduced template arguments. The partially-substituted + // parameter pack, however, will be set to NULL since the deduction + // mechanism handles the partially-substituted argument pack directly. Deduced.reserve(TemplateParams->size()); for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) { const TemplateArgument &Arg = ExplicitArgumentList->get(I); - if (Arg.getKind() == TemplateArgument::Pack) + if (I == PartiallySubstitutedPackIndex) Deduced.push_back(DeducedTemplateArgument()); else Deduced.push_back(Arg); @@ -3852,8 +3927,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // the length of the explicitly-specified pack if it's expanded by the // parameter pack and 0 otherwise, and we treat each deduction as a // non-deduced context. - if (ParamIdx + 1 == NumParamTypes) { - for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) { + if (ParamIdx + 1 == NumParamTypes || PackScope.hasFixedArity()) { + for (; ArgIdx < Args.size() && PackScope.hasNextElement(); + PackScope.nextPackElement(), ++ArgIdx) { ParamTypesForArgChecking.push_back(ParamPattern); if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx)) return Result; diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 71c583367b..9dfdd0555f 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -646,7 +646,9 @@ bool Sema::CheckParameterPacksForExpansion( RetainExpansion = false; std::pair FirstPack; bool HaveFirstPack = false; - + Optional NumPartialExpansions; + SourceLocation PartiallySubstitutedPackLoc; + for (ArrayRef::iterator i = Unexpanded.begin(), end = Unexpanded.end(); i != end; ++i) { @@ -711,8 +713,13 @@ bool Sema::CheckParameterPacksForExpansion( = CurrentInstantiationScope->getPartiallySubstitutedPack()){ unsigned PartialDepth, PartialIndex; std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack); - if (PartialDepth == Depth && PartialIndex == Index) + if (PartialDepth == Depth && PartialIndex == Index) { RetainExpansion = true; + // We don't actually know the new pack size yet. + NumPartialExpansions = NewPackSize; + PartiallySubstitutedPackLoc = i->second; + continue; + } } } @@ -742,6 +749,28 @@ bool Sema::CheckParameterPacksForExpansion( } } + // If we're performing a partial expansion but we also have a full expansion, + // expand to the number of common arguments. For example, given: + // + // template struct A { + // template void f(pair...); + // }; + // + // ... a call to 'A().f' should expand the pack once and + // retain an expansion. + if (NumPartialExpansions) { + if (NumExpansions && *NumExpansions < *NumPartialExpansions) { + NamedDecl *PartialPack = + CurrentInstantiationScope->getPartiallySubstitutedPack(); + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial) + << PartialPack << *NumPartialExpansions << *NumExpansions + << SourceRange(PartiallySubstitutedPackLoc); + return true; + } + + NumExpansions = NumPartialExpansions; + } + return false; } diff --git a/test/SemaTemplate/pack-deduction.cpp b/test/SemaTemplate/pack-deduction.cpp index 84eefa63d2..db0bb58526 100644 --- a/test/SemaTemplate/pack-deduction.cpp +++ b/test/SemaTemplate/pack-deduction.cpp @@ -65,3 +65,104 @@ namespace PR14615 { void f() { check(1, 2); } // expected-error {{no matching function}} } } + +namespace fully_expanded_packs { + template struct A { + template static constexpr int f() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{too many template arguments}} + return (X + ... + 0); // expected-warning {{extension}} + } + + template static constexpr int g() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{couldn't infer template argument 'Y'}} + // expected-note@-3 1+{{too many template arguments}} + return (X + ... + (1000 * Y)); // expected-warning {{extension}} + } + + template static constexpr int h() { + // expected-note@-1 1+{{deduced too few arguments for expanded pack 'X'}} + // expected-note@-2 1+{{couldn't infer template argument 'Y'}} + // expected-note@-3 1+{{deduced too few arguments for expanded pack 'Z'}} + // expected-note@-4 1+{{too many template arguments}} + return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + + template static constexpr int i() { + return (X + ... + 0) + 1000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + + template static constexpr int j() { + return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}} + } + }; + + void check_invalid_calls() { + A::f(); // expected-error {{no matching function}} + A::f<>(); // expected-error {{no matching function}} + A::f<0>(); // expected-error {{no matching function}} + A::g(); // expected-error {{no matching function}} + A::g<>(); // expected-error {{no matching function}} + A::g<0>(); // expected-error {{no matching function}} + A::g<0, 0>(); // expected-error {{no matching function}} + A<>::f<0>(); // expected-error {{no matching function}} + A<>::g(); // expected-error {{no matching function}} + A<>::g<>(); // expected-error {{no matching function}} + A<>::g<0, 0>(); // expected-error {{no matching function}} + A<>::h<>(); // expected-error {{no matching function}} + A::h<>(); // expected-error {{no matching function}} + A::h<0, 0>(); // expected-error {{no matching function}} + A<>::h<0, 0>(); // expected-error {{no matching function}} + } + + static_assert(A<>::f() == 0, ""); + static_assert(A::f<1>() == 1, ""); + static_assert(A<>::g<1>() == 1000, ""); + static_assert(A::g<1, 2>() == 2001, ""); + static_assert(A<>::h<1>() == 1000, ""); + static_assert(A::h<1, 2, 3>() == 3002001, ""); + static_assert(A::h<1, 20, 3, 4, 50>() == 54003021, ""); + static_assert(A<>::i<1>() == 1000, ""); + static_assert(A::i<1>() == 1, ""); + static_assert(A<>::j<1, 2, 30>() == 32001000, ""); + static_assert(A::j<1, 2, 3, 40>() == 43002001, ""); +} + +namespace partial_full_mix { + template struct pair {}; + template struct tuple {}; + template struct A { + template static pair, tuple> f(pair ...p); + // expected-note@-1 {{[with U = ]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + // expected-note@-2 {{[with U = ]: pack expansion contains parameter pack 'U' that has a different length (at least 3 vs. 2) from outer parameter packs}} + + template static pair, tuple> g(pair ...p, ...); + // expected-note@-1 {{[with U = ]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}} + + template static tuple h(tuple..., pair>); + // expected-note@-1 {{[with U = ]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 1) from outer parameter packs}} + }; + + pair, tuple> k1 = A().f(pair(), pair()); + pair, tuple> k2 = A().f(pair(), pair(), pair()); // expected-error {{no match}} + pair, tuple> k3 = A().f(pair(), pair()); // expected-error {{no match}} + + // FIXME: We should accept this by treating the pack 'p' as having a fixed length of 2 here. + pair, tuple> k4 = A().g(pair(), pair(), pair()); // expected-error {{no match}} + + // FIXME: We should accept this by treating the pack of pairs as having a fixed length of 2 here. + tuple k5 = A::h(tuple, pair, pair>()); // expected-error {{no match}} +} + +namespace substitution_vs_function_deduction { + template struct A { + template void f(void(*...)(T, U)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}} + template void g(void...(T, U)); // expected-note {{could not match 'void (T, U)' against 'void (*)(int, int)'}} + }; + void f(int, int) { + A().f(f); + // FIXME: We fail to decay the parameter to a pointer type. + A().g(f); // expected-error {{no match}} + } +}