diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 45 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 290 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 33 |
4 files changed, 253 insertions, 134 deletions
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 35c3612c71b..822c3c0c6b4 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/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<DFIParamWithArguments*>(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<TemplateTypeParmDecl>(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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index c1d8c24796d..935264cb8cc 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 51d2bae08ca..0b41a515d9a 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -662,6 +662,19 @@ static TemplateParameter makeTemplateParameter(Decl *D) { return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); } +/// If \p Param is an expanded parameter pack, get the number of expansions. +static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(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<DeducedTemplateArgument> &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<DeducedTemplateArgument> &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<unsigned> 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<UnexpandedParameterPack, 2> 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<UnexpandedParameterPack, 2> 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<unsigned> 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<unsigned> FixedNumExpansions; SmallVector<DeducedPack, 2> 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<TemplateArgument> 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<TemplateDecl>(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<unsigned> 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/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 71c583367bd..9dfdd0555f7 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -646,7 +646,9 @@ bool Sema::CheckParameterPacksForExpansion( RetainExpansion = false; std::pair<IdentifierInfo *, SourceLocation> FirstPack; bool HaveFirstPack = false; - + Optional<unsigned> NumPartialExpansions; + SourceLocation PartiallySubstitutedPackLoc; + for (ArrayRef<UnexpandedParameterPack>::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<typename ...T> struct A { + // template<typename ...U> void f(pair<T, U>...); + // }; + // + // ... a call to 'A<int, int>().f<int>' 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; } |