diff options
Diffstat (limited to 'clang/lib/Sema/SemaTemplateDeduction.cpp')
-rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 1170 |
1 files changed, 697 insertions, 473 deletions
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9ec33e898198..9e48a2a35a34 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -45,7 +45,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" @@ -54,7 +53,9 @@ #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <cassert> +#include <optional> #include <tuple> +#include <type_traits> #include <utility> namespace clang { @@ -235,11 +236,13 @@ checkDeducedTemplateArguments(ASTContext &Context, case TemplateArgument::Null: llvm_unreachable("Non-deduced template arguments handled above"); - case TemplateArgument::Type: + case TemplateArgument::Type: { // If two template type arguments have the same type, they're compatible. - if (Y.getKind() == TemplateArgument::Type && - Context.hasSameType(X.getAsType(), Y.getAsType())) - return X; + QualType TX = X.getAsType(), TY = Y.getAsType(); + if (Y.getKind() == TemplateArgument::Type && Context.hasSameType(TX, TY)) + return DeducedTemplateArgument(Context.getCommonSugaredType(TX, TY), + X.wasDeducedFromArrayBound() || + Y.wasDeducedFromArrayBound()); // If one of the two arguments was deduced from an array bound, the other // supersedes it. @@ -248,6 +251,7 @@ checkDeducedTemplateArguments(ASTContext &Context, // The arguments are not compatible. return DeducedTemplateArgument(); + } case TemplateArgument::Integral: // If we deduced a constant in one case and either a dependent expression or @@ -325,7 +329,9 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced a null pointer and a dependent expression, keep the // null pointer. if (Y.getKind() == TemplateArgument::Expression) - return X; + return TemplateArgument(Context.getCommonSugaredType( + X.getNullPtrType(), Y.getAsExpr()->getType()), + true); // If we deduced a null pointer and an integral constant, keep the // integral constant. @@ -334,7 +340,9 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced two null pointers, they are the same. if (Y.getKind() == TemplateArgument::NullPtr) - return X; + return TemplateArgument( + Context.getCommonSugaredType(X.getNullPtrType(), Y.getNullPtrType()), + true); // All other combinations are incompatible. return DeducedTemplateArgument(); @@ -555,6 +563,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // FIXME: Try to preserve type sugar here, which is hard // because of the unresolved template arguments. const auto *TP = UP.getCanonicalType()->castAs<TemplateSpecializationType>(); + TemplateName TNP = TP->getTemplateName(); + + // If the parameter is an alias template, there is nothing to deduce. + if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) + return Sema::TDK_Success; + ArrayRef<TemplateArgument> PResolved = TP->template_arguments(); QualType UA = A; @@ -566,10 +580,15 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // FIXME: Should not lose sugar here. if (const auto *SA = dyn_cast<TemplateSpecializationType>(UA.getCanonicalType())) { + TemplateName TNA = SA->getTemplateName(); + + // If the argument is an alias template, there is nothing to deduce. + if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias()) + return Sema::TDK_Success; + // Perform template argument deduction for the template name. if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TP->getTemplateName(), - SA->getTemplateName(), Info, Deduced)) + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced)) return Result; // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be @@ -700,7 +719,7 @@ private: // 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 = + if (std::optional<unsigned> ExpandedPackExpansions = getExpandedPackSize(TemplateParams->getParam(Index))) FixedNumExpansions = ExpandedPackExpansions; @@ -737,8 +756,11 @@ private: 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]); + UnexpandedParameterPack U = Unexpanded[I]; + if (U.first.is<const SubstTemplateTypeParmPackType *>() || + U.first.is<const SubstNonTypeTemplateParmPackExpr *>()) + continue; + auto [Depth, Index] = getDepthAndIndex(U); if (Depth == Info.getDeducedDepth()) AddPack(Index); } @@ -894,7 +916,7 @@ public: new (S.Context) TemplateArgument[Pack.New.size()]; std::copy(Pack.New.begin(), Pack.New.end(), ArgumentPack); NewPack = DeducedTemplateArgument( - TemplateArgument(llvm::makeArrayRef(ArgumentPack, Pack.New.size())), + TemplateArgument(llvm::ArrayRef(ArgumentPack, Pack.New.size())), // FIXME: This is wrong, it's possible that some pack elements are // deduced from an array bound and others are not: // template<typename ...T, T ...V> void g(const T (&...p)[V]); @@ -939,7 +961,7 @@ public: // 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 (std::optional<unsigned> Expansions = getExpandedPackSize(Param)) { if (*Expansions != PackElements) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Result; @@ -961,7 +983,7 @@ private: unsigned PackElements = 0; bool IsPartiallyExpanded = false; /// The number of expansions, if we have a fully-expanded pack in this scope. - Optional<unsigned> FixedNumExpansions; + std::optional<unsigned> FixedNumExpansions; SmallVector<DeducedPack, 2> Packs; }; @@ -1086,7 +1108,7 @@ DeduceTemplateArguments(Sema &S, // If the parameter type contains an explicitly-specified pack that we // could not expand, skip the number of parameters notionally created // by the expansion. - Optional<unsigned> NumExpansions = Expansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = Expansion->getNumExpansions(); if (NumExpansions && !PackScope.isPartiallyExpanded()) { for (unsigned I = 0; I != *NumExpansions && ArgIdx < NumArgs; ++I, ++ArgIdx) @@ -1100,6 +1122,16 @@ DeduceTemplateArguments(Sema &S, return Result; } + // DR692, DR1395 + // C++0x [temp.deduct.type]p10: + // If the parameter-declaration corresponding to P_i ... + // During partial ordering, if Ai was originally a function parameter pack: + // - if P does not contain a function parameter type corresponding to Ai then + // Ai is ignored; + if (PartialOrdering && ArgIdx + 1 == NumArgs && + isa<PackExpansionType>(Args[ArgIdx])) + return Sema::TDK_Success; + // Make sure we don't have any extra arguments. if (ArgIdx < NumArgs) return Sema::TDK_MiscellaneousDeductionFailure; @@ -1587,7 +1619,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // FIXME: Implement deduction in dependent case. if (P->isDependentType()) return Sema::TDK_Success; - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::Builtin: case Type::VariableArray: case Type::Vector: @@ -1755,7 +1787,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, - TDF & TDF_TopLevelParameterTypeList)) + TDF & TDF_TopLevelParameterTypeList, PartialOrdering)) return Result; if (TDF & TDF_AllowCompatibleFunctionType) @@ -1775,7 +1807,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( switch (FPA->canThrow()) { case CT_Cannot: Noexcept = 1; - LLVM_FALLTHROUGH; + [[fallthrough]]; case CT_Can: // We give E in noexcept(E) the "deduced from array bound" treatment. @@ -2049,7 +2081,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *ACM = dyn_cast<ConstantMatrixType>(A); const auto *ADM = dyn_cast<DependentSizedMatrixType>(A); if (!ParamExpr->isValueDependent()) { - Optional<llvm::APSInt> ParamConst = + std::optional<llvm::APSInt> ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) return Sema::TDK_NonDeducedMismatch; @@ -2061,7 +2093,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( } Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); - if (Optional<llvm::APSInt> ArgConst = + if (std::optional<llvm::APSInt> ArgConst = ArgExpr->getIntegerConstantExpr(S.Context)) if (*ArgConst == *ParamConst) return Sema::TDK_Success; @@ -2422,6 +2454,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, static bool isSameTemplateArg(ASTContext &Context, TemplateArgument X, const TemplateArgument &Y, + bool PartialOrdering, bool PackExpansionMatchesPack = false) { // If we're checking deduced arguments (X) against original arguments (Y), // we will have flattened packs to non-expansions in X. @@ -2462,18 +2495,33 @@ static bool isSameTemplateArg(ASTContext &Context, return XID == YID; } - case TemplateArgument::Pack: - if (X.pack_size() != Y.pack_size()) - return false; + case TemplateArgument::Pack: { + unsigned PackIterationSize = X.pack_size(); + if (X.pack_size() != Y.pack_size()) { + if (!PartialOrdering) + return false; - for (TemplateArgument::pack_iterator XP = X.pack_begin(), - XPEnd = X.pack_end(), - YP = Y.pack_begin(); - XP != XPEnd; ++XP, ++YP) - if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack)) + // C++0x [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion: + // - if P does not contain a template argument corresponding to Ai + // then Ai is ignored; + bool XHasMoreArg = X.pack_size() > Y.pack_size(); + if (!(XHasMoreArg && X.pack_elements().back().isPackExpansion()) && + !(!XHasMoreArg && Y.pack_elements().back().isPackExpansion())) return false; + if (XHasMoreArg) + PackIterationSize = Y.pack_size(); + } + + ArrayRef<TemplateArgument> XP = X.pack_elements(); + ArrayRef<TemplateArgument> YP = Y.pack_elements(); + for (unsigned i = 0; i < PackIterationSize; ++i) + if (!isSameTemplateArg(Context, XP[i], YP[i], PartialOrdering, + PackExpansionMatchesPack)) + return false; return true; + } } llvm_unreachable("Invalid TemplateArgument Kind!"); @@ -2563,13 +2611,11 @@ Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, /// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. -static bool -ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, - DeducedTemplateArgument Arg, - NamedDecl *Template, - TemplateDeductionInfo &Info, - bool IsDeduced, - SmallVectorImpl<TemplateArgument> &Output) { +static bool ConvertDeducedTemplateArgument( + Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, + TemplateDeductionInfo &Info, bool IsDeduced, + SmallVectorImpl<TemplateArgument> &SugaredOutput, + SmallVectorImpl<TemplateArgument> &CanonicalOutput) { auto ConvertArg = [&](DeducedTemplateArgument Arg, unsigned ArgumentPackIndex) { // Convert the deduced template argument into a template @@ -2581,7 +2627,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), - Template->getSourceRange().getEnd(), ArgumentPackIndex, Output, + Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput, + CanonicalOutput, IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) @@ -2591,7 +2638,8 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. - SmallVector<TemplateArgument, 2> PackedArgsBuilder; + SmallVector<TemplateArgument, 2> SugaredPackedArgsBuilder, + CanonicalPackedArgsBuilder; for (const auto &P : Arg.pack_elements()) { // When converting the deduced template argument, append it to the // general output list. We need to do this so that the template argument @@ -2610,23 +2658,24 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, << Arg << Param; return true; } - if (ConvertArg(InnerArg, PackedArgsBuilder.size())) + if (ConvertArg(InnerArg, SugaredPackedArgsBuilder.size())) return true; // Move the converted template argument into our argument pack. - PackedArgsBuilder.push_back(Output.pop_back_val()); + SugaredPackedArgsBuilder.push_back(SugaredOutput.pop_back_val()); + CanonicalPackedArgsBuilder.push_back(CanonicalOutput.pop_back_val()); } // If the pack is empty, we still need to substitute into the parameter // itself, in case that substitution fails. - if (PackedArgsBuilder.empty()) { + if (SugaredPackedArgsBuilder.empty()) { LocalInstantiationScope Scope(S); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output); - MultiLevelTemplateArgumentList Args(TemplateArgs); + MultiLevelTemplateArgumentList Args(Template, SugaredOutput, + /*Final=*/true); if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - NTTP, Output, + NTTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || S.SubstType(NTTP->getType(), Args, NTTP->getLocation(), @@ -2634,7 +2683,7 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, return true; } else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - TTP, Output, + TTP, SugaredOutput, Template->getSourceRange()); if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args)) return true; @@ -2643,8 +2692,10 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, } // Create the resulting argument pack. - Output.push_back( - TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder)); + SugaredOutput.push_back( + TemplateArgument::CreatePackCopy(S.Context, SugaredPackedArgsBuilder)); + CanonicalOutput.push_back(TemplateArgument::CreatePackCopy( + S.Context, CanonicalPackedArgsBuilder)); return false; } @@ -2654,11 +2705,13 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, // FIXME: This should not be a template, but // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. -template<typename TemplateDeclT> +template <typename TemplateDeclT> static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( Sema &S, TemplateDeclT *Template, bool IsDeduced, SmallVectorImpl<DeducedTemplateArgument> &Deduced, - TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder, + TemplateDeductionInfo &Info, + SmallVectorImpl<TemplateArgument> &SugaredBuilder, + SmallVectorImpl<TemplateArgument> &CanonicalBuilder, LocalInstantiationScope *CurrentInstantiationScope = nullptr, unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { TemplateParameterList *TemplateParams = Template->getTemplateParameters(); @@ -2692,7 +2745,9 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // We have already fully type-checked and converted this // argument, because it was explicitly-specified. Just record the // presence of this argument. - Builder.push_back(Deduced[I]); + SugaredBuilder.push_back(Deduced[I]); + CanonicalBuilder.push_back( + S.Context.getCanonicalTemplateArgument(Deduced[I])); continue; } } @@ -2700,10 +2755,13 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // We may have deduced this argument, so it still needs to be // checked and converted. if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, - IsDeduced, Builder)) { + IsDeduced, SugaredBuilder, + CanonicalBuilder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2734,15 +2792,16 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( S.getLangOpts().CPlusPlus17); DefArg = S.SubstDefaultTemplateArgumentIfAvailable( - TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, - HasDefaultArg); + TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, + SugaredBuilder, CanonicalBuilder, HasDefaultArg); } // If there was no default argument, deduction is incomplete. if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); if (PartialOverloading) break; return HasDefaultArg ? Sema::TDK_SubstitutionFailure @@ -2750,13 +2809,14 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( } // Check whether we can actually use the default argument. - if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(), - TD->getSourceRange().getEnd(), 0, Builder, - Sema::CTAK_Specified)) { + if (S.CheckTemplateArgument( + Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(), + 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); return Sema::TDK_SubstitutionFailure; } @@ -2783,19 +2843,54 @@ template<> struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> { static constexpr bool value = true; }; +template <typename TemplateDeclT> +static bool DeducedArgsNeedReplacement(TemplateDeclT *Template) { + return false; +} +template <> +bool DeducedArgsNeedReplacement<VarTemplatePartialSpecializationDecl>( + VarTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} +template <> +bool DeducedArgsNeedReplacement<ClassTemplatePartialSpecializationDecl>( + ClassTemplatePartialSpecializationDecl *Spec) { + return !Spec->isClassScopeExplicitSpecialization(); +} -template<typename TemplateDeclT> +template <typename TemplateDeclT> static Sema::TemplateDeductionResult -CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, - ArrayRef<TemplateArgument> DeducedArgs, - TemplateDeductionInfo& Info) { +CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, + ArrayRef<TemplateArgument> SugaredDeducedArgs, + ArrayRef<TemplateArgument> CanonicalDeducedArgs, + TemplateDeductionInfo &Info) { llvm::SmallVector<const Expr *, 3> AssociatedConstraints; Template->getAssociatedConstraints(AssociatedConstraints); - if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, - DeducedArgs, Info.getLocation(), + + bool NeedsReplacement = DeducedArgsNeedReplacement(Template); + TemplateArgumentList DeducedTAL{TemplateArgumentList::OnStack, + CanonicalDeducedArgs}; + + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + Template, /*Final=*/false, + /*InnerMost=*/NeedsReplacement ? nullptr : &DeducedTAL, + /*RelativeToPrimary=*/true, /*Pattern=*/ + nullptr, /*ForConstraintInstantiation=*/true); + + // getTemplateInstantiationArgs picks up the non-deduced version of the + // template args when this is a variable template partial specialization and + // not class-scope explicit specialization, so replace with Deduced Args + // instead of adding to inner-most. + if (NeedsReplacement) + MLTAL.replaceInnermostTemplateArguments(CanonicalDeducedArgs); + + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL, + Info.getLocation(), Info.AssociatedConstraintsSatisfaction) || !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); + Info.reset( + TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs), + TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs)); return Sema::TDK_ConstraintsNotSatisfied; } return Sema::TDK_Success; @@ -2820,16 +2915,19 @@ FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Partial, IsPartialOrdering, Deduced, Info, Builder)) + S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, + CanonicalBuilder)) return Result; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(S.Context, Builder); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder); - Info.reset(DeducedArgumentList); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the template // arguments of the class template partial specialization, and @@ -2844,9 +2942,11 @@ FinishTemplateArgumentDeduction( TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); - if (S.SubstTemplateArguments( - PartialTemplArgInfo->arguments(), - MultiLevelTemplateArgumentList(*DeducedArgumentList), InstArgs)) { + if (S.SubstTemplateArguments(PartialTemplArgInfo->arguments(), + MultiLevelTemplateArgumentList(Partial, + SugaredBuilder, + /*Final=*/true), + InstArgs)) { unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; @@ -2859,18 +2959,20 @@ FinishTemplateArgumentDeduction( } bool ConstraintsNotSatisfied; - SmallVector<TemplateArgument, 4> ConvertedInstArgs; - if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs, - /*UpdateArgsWithConversions=*/true, - &ConstraintsNotSatisfied)) - return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied : - Sema::TDK_SubstitutionFailure; + SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs, + CanonicalConvertedInstArgs; + if (S.CheckTemplateArgumentList( + Template, Partial->getLocation(), InstArgs, false, + SugaredConvertedInstArgs, CanonicalConvertedInstArgs, + /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) + return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied + : Sema::TDK_SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = ConvertedInstArgs.data()[I]; - if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { + TemplateArgument InstArg = SugaredConvertedInstArgs.data()[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, + IsPartialOrdering)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; @@ -2881,7 +2983,8 @@ FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -2905,17 +3008,20 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, + SugaredBuilder, CanonicalBuilder, + /*CurrentInstantiationScope=*/nullptr, + /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false)) return Result; // Check that we produced the correct argument list. TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = Builder[I]; - if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, - /*PackExpansionMatchesPack*/true)) { + TemplateArgument InstArg = CanonicalBuilder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, PartialOrdering, + /*PackExpansionMatchesPack=*/true)) { Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; @@ -2926,8 +3032,8 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder, - Info)) + if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder, + CanonicalBuilder, Info)) return Result; return Sema::TDK_Success; @@ -3079,14 +3185,12 @@ static bool isSimpleTemplateIdType(QualType T) { /// /// \returns TDK_Success if substitution was successful, or some failure /// condition. -Sema::TemplateDeductionResult -Sema::SubstituteExplicitTemplateArguments( - FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo &ExplicitTemplateArgs, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - SmallVectorImpl<QualType> &ParamTypes, - QualType *FunctionType, - TemplateDeductionInfo &Info) { +Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo &ExplicitTemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + SmallVectorImpl<QualType> &ParamTypes, QualType *FunctionType, + TemplateDeductionInfo &Info) { FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -3094,7 +3198,7 @@ Sema::SubstituteExplicitTemplateArguments( if (ExplicitTemplateArgs.size() == 0) { // No arguments to substitute; just copy over the parameter types and // fill in the function type. - for (auto P : Function->parameters()) + for (auto *P : Function->parameters()) ParamTypes.push_back(P->getType()); if (FunctionType) @@ -3112,7 +3216,7 @@ Sema::SubstituteExplicitTemplateArguments( // declaration order of their corresponding template-parameters. The // template argument list shall not specify more template-arguments than // there are corresponding template-parameters. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; // Enter a new template instantiation context where we check the // explicitly-specified template arguments against this function template, @@ -3125,9 +3229,11 @@ Sema::SubstituteExplicitTemplateArguments( return TDK_InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), - ExplicitTemplateArgs, true, Builder, false) || + ExplicitTemplateArgs, true, SugaredBuilder, + CanonicalBuilder, + /*UpdateArgsWithConversions=*/false) || Trap.hasErrorOccurred()) { - unsigned Index = Builder.size(); + unsigned Index = SugaredBuilder.size(); if (Index >= TemplateParams->size()) return TDK_SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); @@ -3136,9 +3242,12 @@ Sema::SubstituteExplicitTemplateArguments( // Form the template argument list from the explicitly-specified // template arguments. - TemplateArgumentList *ExplicitArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.setExplicitArgs(ExplicitArgumentList); + TemplateArgumentList *SugaredExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalExplicitArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.setExplicitArgs(SugaredExplicitArgumentList, + CanonicalExplicitArgumentList); // Template argument deduction and the final substitution should be // done in the context of the templated declaration. Explicit @@ -3151,15 +3260,15 @@ Sema::SubstituteExplicitTemplateArguments( // the explicit template arguments. They'll be used as part of deduction // for this template parameter pack. unsigned PartiallySubstitutedPackIndex = -1u; - if (!Builder.empty()) { - const TemplateArgument &Arg = Builder.back(); + if (!CanonicalBuilder.empty()) { + const TemplateArgument &Arg = CanonicalBuilder.back(); if (Arg.getKind() == TemplateArgument::Pack) { - auto *Param = TemplateParams->getParam(Builder.size() - 1); + auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1); // If this is a fully-saturated fixed-size pack, it should be // fully-substituted, not partially-substituted. - Optional<unsigned> Expansions = getExpandedPackSize(Param); + std::optional<unsigned> Expansions = getExpandedPackSize(Param); if (!Expansions || Arg.pack_size() < *Expansions) { - PartiallySubstitutedPackIndex = Builder.size() - 1; + PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1; CurrentInstantiationScope->SetPartiallySubstitutedPack( Param, Arg.pack_begin(), Arg.pack_size()); } @@ -3175,15 +3284,18 @@ Sema::SubstituteExplicitTemplateArguments( ExtParameterInfoBuilder ExtParamInfos; + MultiLevelTemplateArgumentList MLTAL(FunctionTemplate, + SugaredExplicitArgumentList->asArray(), + /*Final=*/true); + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { if (SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params=*/nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } @@ -3207,8 +3319,7 @@ Sema::SubstituteExplicitTemplateArguments( getLangOpts().CPlusPlus11); ResultType = - SubstType(Proto->getReturnType(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), + SubstType(Proto->getReturnType(), MLTAL, Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; @@ -3225,9 +3336,8 @@ Sema::SubstituteExplicitTemplateArguments( // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && SubstParmTypes(Function->getLocation(), Function->parameters(), - Proto->getExtParameterInfosOrNull(), - MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes, /*params*/ nullptr, ExtParamInfos)) + Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, + /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; if (FunctionType) { @@ -3239,9 +3349,8 @@ Sema::SubstituteExplicitTemplateArguments( // specification. SmallVector<QualType, 4> ExceptionStorage; if (getLangOpts().CPlusPlus17 && - SubstExceptionSpec( - Function->getLocation(), EPI.ExceptionSpec, ExceptionStorage, - MultiLevelTemplateArgumentList(*ExplicitArgumentList))) + SubstExceptionSpec(Function->getLocation(), EPI.ExceptionSpec, + ExceptionStorage, MLTAL)) return TDK_SubstitutionFailure; *FunctionType = BuildFunctionType(ResultType, ParamTypes, @@ -3263,8 +3372,8 @@ Sema::SubstituteExplicitTemplateArguments( // 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); + for (unsigned I = 0, N = SugaredExplicitArgumentList->size(); I != N; ++I) { + const TemplateArgument &Arg = SugaredExplicitArgumentList->get(I); if (I == PartiallySubstitutedPackIndex) Deduced.push_back(DeducedTemplateArgument()); else @@ -3452,11 +3561,11 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // C++ [temp.deduct.type]p2: // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; + SmallVector<TemplateArgument, 4> SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( - *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder, - CurrentInstantiationScope, NumExplicitlySpecified, - PartialOverloading)) + *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, + SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, + NumExplicitlySpecified, PartialOverloading)) return Result; // C++ [temp.deduct.call]p10: [DR1391] @@ -3472,16 +3581,20 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( return TDK_NonDependentConversionFailure; // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder); - Info.reset(DeducedArgumentList); + TemplateArgumentList *SugaredDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, SugaredBuilder); + TemplateArgumentList *CanonicalDeducedArgumentList = + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder); + Info.reset(SugaredDeducedArgumentList, CanonicalDeducedArgumentList); // Substitute the deduced template arguments into the function template // declaration to produce the function template specialization. DeclContext *Owner = FunctionTemplate->getDeclContext(); if (FunctionTemplate->getFriendObjectKind()) Owner = FunctionTemplate->getLexicalDeclContext(); - MultiLevelTemplateArgumentList SubstArgs(*DeducedArgumentList); + MultiLevelTemplateArgumentList SubstArgs( + FunctionTemplate, CanonicalDeducedArgumentList->asArray(), + /*Final=*/false); Specialization = cast_or_null<FunctionDecl>( SubstDecl(FunctionTemplate->getTemplatedDecl(), Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) @@ -3492,9 +3605,10 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // If the template argument list is owned by the function template // specialization, release it. - if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList && + if (Specialization->getTemplateSpecializationArgs() == + CanonicalDeducedArgumentList && !Trap.hasErrorOccurred()) - Info.take(); + Info.takeCanonical(); // There may have been an error that did not prevent us from constructing a // declaration. Mark the declaration invalid and return with a substitution @@ -3513,13 +3627,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. if (!PartialOverloading || - (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) { - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + (CanonicalBuilder.size() == + FunctionTemplate->getTemplateParameters()->size())) { + if (CheckInstantiatedFunctionTemplateConstraints( + Info.getLocation(), Specialization, CanonicalBuilder, + Info.AssociatedConstraintsSatisfaction)) return TDK_MiscellaneousDeductionFailure; if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + Info.reset(Info.takeSugared(), + TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); return TDK_ConstraintsNotSatisfied; } } @@ -3765,13 +3882,11 @@ static bool AdjustFunctionParmAndArgTypesForDeduction( // - If A is an array type, the pointer type produced by the // array-to-pointer standard conversion (4.2) is used in place of // A for type deduction; otherwise, - if (ArgType->isArrayType()) - ArgType = S.Context.getArrayDecayedType(ArgType); // - If A is a function type, the pointer type produced by the // function-to-pointer standard conversion (4.3) is used in place // of A for type deduction; otherwise, - else if (ArgType->isFunctionType()) - ArgType = S.Context.getPointerType(ArgType); + if (ArgType->canDecayToPointerType()) + ArgType = S.Context.getDecayedType(ArgType); else { // - If A is a cv-qualified type, the top level cv-qualifiers of A's // type are ignored for type deduction. @@ -4068,7 +4183,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // If the parameter type contains an explicitly-specified pack that we // could not expand, skip the number of parameters notionally created // by the expansion. - Optional<unsigned> NumExpansions = ParamExpansion->getNumExpansions(); + std::optional<unsigned> NumExpansions = + ParamExpansion->getNumExpansions(); if (NumExpansions && !PackScope.isPartiallyExpanded()) { for (unsigned I = 0; I != *NumExpansions && ArgIdx < Args.size(); ++I, ++ArgIdx) { @@ -4521,42 +4637,9 @@ namespace { } // namespace -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth, - bool IgnoreConstraints) { - return DeduceAutoType(Type->getTypeLoc(), Init, Result, - DependentDeductionDepth, IgnoreConstraints); -} - -/// Attempt to produce an informative diagostic explaining why auto deduction -/// failed. -/// \return \c true if diagnosed, \c false if not. -static bool diagnoseAutoDeductionFailure(Sema &S, - Sema::TemplateDeductionResult TDK, - TemplateDeductionInfo &Info, - ArrayRef<SourceRange> Ranges) { - switch (TDK) { - case Sema::TDK_Inconsistent: { - // Inconsistent deduction means we were deducing from an initializer list. - auto D = S.Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction); - D << Info.FirstArg << Info.SecondArg; - for (auto R : Ranges) - D << R; - return true; - } - - // FIXME: Are there other cases for which a custom diagnostic is more useful - // than the basic "types don't match" diagnostic? - - default: - return false; - } -} - -static Sema::DeduceAutoResult -CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, - AutoTypeLoc TypeLoc, QualType Deduced) { +static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, + AutoTypeLoc TypeLoc, + QualType Deduced) { ConstraintSatisfaction Satisfaction; ConceptDecl *Concept = Type.getTypeConstraintConcept(); TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), @@ -4568,14 +4651,17 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); - llvm::SmallVector<TemplateArgument, 4> Converted; + llvm::SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted; if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, - /*PartialTemplateArgs=*/false, Converted)) - return Sema::DAR_FailedAlreadyDiagnosed; + /*PartialTemplateArgs=*/false, + SugaredConverted, CanonicalConverted)) + return true; + MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted, + /*Final=*/false); if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, - Converted, TypeLoc.getLocalSourceRange(), + MLTAL, TypeLoc.getLocalSourceRange(), Satisfaction)) - return Sema::DAR_FailedAlreadyDiagnosed; + return true; if (!Satisfaction.IsSatisfied) { std::string Buf; llvm::raw_string_ostream OS(Buf); @@ -4589,11 +4675,11 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, OS.flush(); S.Diag(TypeLoc.getConceptNameLoc(), diag::err_placeholder_constraints_not_satisfied) - << Deduced << Buf << TypeLoc.getLocalSourceRange(); + << Deduced << Buf << TypeLoc.getLocalSourceRange(); S.DiagnoseUnsatisfiedConstraint(Satisfaction); - return Sema::DAR_FailedAlreadyDiagnosed; + return true; } - return Sema::DAR_Succeeded; + return false; } /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) @@ -4606,184 +4692,165 @@ CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, /// \param Init the initializer for the variable whose type is to be deduced. /// \param Result if type deduction was successful, this will be set to the /// deduced type. -/// \param DependentDeductionDepth Set if we should permit deduction in +/// \param Info the argument will be updated to provide additional information +/// about template argument deduction. +/// \param DependentDeduction Set if we should permit deduction in /// dependent cases. This is necessary for template partial ordering with -/// 'auto' template parameters. The value specified is the template -/// parameter depth at which we should perform 'auto' deduction. +/// 'auto' template parameters. The template parameter depth to be used +/// should be specified in the 'Info' parameter. /// \param IgnoreConstraints Set if we should not fail if the deduced type does /// not satisfy the type-constraint in the auto type. -Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth, - bool IgnoreConstraints) { +Sema::TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, + QualType &Result, + TemplateDeductionInfo &Info, + bool DependentDeduction, + bool IgnoreConstraints) { + assert(DependentDeduction || Info.getDeducedDepth() == 0); if (Init->containsErrors()) - return DAR_FailedAlreadyDiagnosed; - if (Init->getType()->isNonOverloadPlaceholderType()) { + return TDK_AlreadyDiagnosed; + + const AutoType *AT = Type.getType()->getContainedAutoType(); + assert(AT); + + if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) - return DAR_FailedAlreadyDiagnosed; + return TDK_AlreadyDiagnosed; Init = NonPlaceholder.get(); } DependentAuto DependentResult = { /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()}; - if (!DependentDeductionDepth && + if (!DependentDeduction && (Type.getType()->isDependentType() || Init->isTypeDependent() || Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return DAR_Succeeded; + return TDK_Success; } - // Find the depth of template parameter to synthesize. - unsigned Depth = DependentDeductionDepth.value_or(0); - - // If this is a 'decltype(auto)' specifier, do the decltype dance. - // Since 'decltype(auto)' can only occur at the top of the type, we - // don't need to go digging for it. - if (const AutoType *AT = Type.getType()->getAs<AutoType>()) { - if (AT->isDecltypeAuto()) { - if (isa<InitListExpr>(Init)) { - Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list); - return DAR_FailedAlreadyDiagnosed; - } - - ExprResult ER = CheckPlaceholderExpr(Init); - if (ER.isInvalid()) - return DAR_FailedAlreadyDiagnosed; - QualType Deduced = getDecltypeForExpr(ER.get()); - assert(!Deduced.isNull()); - if (AT->isConstrained() && !IgnoreConstraints) { - auto ConstraintsResult = - CheckDeducedPlaceholderConstraints(*this, *AT, - Type.getContainedAutoTypeLoc(), - Deduced); - if (ConstraintsResult != DAR_Succeeded) - return ConstraintsResult; - } - Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); - if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; - return DAR_Succeeded; - } else if (!getLangOpts().CPlusPlus) { - if (isa<InitListExpr>(Init)) { - Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); - return DAR_FailedAlreadyDiagnosed; - } - } + auto *InitList = dyn_cast<InitListExpr>(Init); + if (!getLangOpts().CPlusPlus && InitList) { + Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c); + return TDK_AlreadyDiagnosed; } - SourceLocation Loc = Init->getExprLoc(); - - LocalInstantiationScope InstScope(*this); - - // Build template<class TemplParam> void Func(FuncParam); - TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( - Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false, - false); - QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); - NamedDecl *TemplParamPtr = TemplParam; - FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( - Context, Loc, Loc, TemplParamPtr, Loc, nullptr); - - QualType FuncParam = - SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/ true) - .Apply(Type); - assert(!FuncParam.isNull() && - "substituting template parameter for 'auto' failed"); - // Deduce type of TemplParam in Func(Init) SmallVector<DeducedTemplateArgument, 1> Deduced; Deduced.resize(1); - TemplateDeductionInfo Info(Loc, Depth); - // If deduction failed, don't diagnose if the initializer is dependent; it // might acquire a matching type in the instantiation. - auto DeductionFailed = [&](TemplateDeductionResult TDK, - ArrayRef<SourceRange> Ranges) -> DeduceAutoResult { + auto DeductionFailed = [&](TemplateDeductionResult TDK) { if (Init->isTypeDependent()) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return DAR_Succeeded; + return TDK_Success; } - if (diagnoseAutoDeductionFailure(*this, TDK, Info, Ranges)) - return DAR_FailedAlreadyDiagnosed; - return DAR_Failed; + return TDK; }; SmallVector<OriginalCallArg, 4> OriginalCallArgs; - InitListExpr *InitList = dyn_cast<InitListExpr>(Init); - if (InitList) { - // Notionally, we substitute std::initializer_list<T> for 'auto' and deduce - // against that. Such deduction only succeeds if removing cv-qualifiers and - // references results in std::initializer_list<T>. - if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) - return DAR_Failed; - - // Resolving a core issue: a braced-init-list containing any designators is - // a non-deduced context. - for (Expr *E : InitList->inits()) - if (isa<DesignatedInitExpr>(E)) - return DAR_Failed; + QualType DeducedType; + // If this is a 'decltype(auto)' specifier, do the decltype dance. + if (AT->isDecltypeAuto()) { + if (InitList) { + Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list); + return TDK_AlreadyDiagnosed; + } - SourceRange DeducedFromInitRange; - for (unsigned i = 0, e = InitList->getNumInits(); i < e; ++i) { - Expr *Init = InitList->getInit(i); + DeducedType = getDecltypeForExpr(Init); + assert(!DeducedType.isNull()); + } else { + LocalInstantiationScope InstScope(*this); + + // Build template<class TemplParam> void Func(FuncParam); + SourceLocation Loc = Init->getExprLoc(); + TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( + Context, nullptr, SourceLocation(), Loc, Info.getDeducedDepth(), 0, + nullptr, false, false, false); + QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); + NamedDecl *TemplParamPtr = TemplParam; + FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( + Context, Loc, Loc, TemplParamPtr, Loc, nullptr); + + if (InitList) { + // Notionally, we substitute std::initializer_list<T> for 'auto' and + // deduce against that. Such deduction only succeeds if removing + // cv-qualifiers and references results in std::initializer_list<T>. + if (!Type.getType().getNonReferenceType()->getAs<AutoType>()) + return TDK_Invalid; + + SourceRange DeducedFromInitRange; + for (Expr *Init : InitList->inits()) { + // Resolving a core issue: a braced-init-list containing any designators + // is a non-deduced context. + if (isa<DesignatedInitExpr>(Init)) + return TDK_Invalid; + if (auto TDK = DeduceTemplateArgumentsFromCallArgument( + *this, TemplateParamsSt.get(), 0, TemplArg, Init, Info, Deduced, + OriginalCallArgs, /*Decomposed=*/true, + /*ArgIdx=*/0, /*TDF=*/0)) { + if (TDK == TDK_Inconsistent) { + Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction) + << Info.FirstArg << Info.SecondArg << DeducedFromInitRange + << Init->getSourceRange(); + return DeductionFailed(TDK_AlreadyDiagnosed); + } + return DeductionFailed(TDK); + } + if (DeducedFromInitRange.isInvalid() && + Deduced[0].getKind() != TemplateArgument::Null) + DeducedFromInitRange = Init->getSourceRange(); + } + } else { + if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { + Diag(Loc, diag::err_auto_bitfield); + return TDK_AlreadyDiagnosed; + } + QualType FuncParam = + SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type); + assert(!FuncParam.isNull() && + "substituting template parameter for 'auto' failed"); if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, TemplArg, Init, - Info, Deduced, OriginalCallArgs, /*Decomposed*/ true, - /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(TDK, {DeducedFromInitRange, - Init->getSourceRange()}); - - if (DeducedFromInitRange.isInvalid() && - Deduced[0].getKind() != TemplateArgument::Null) - DeducedFromInitRange = Init->getSourceRange(); - } - } else { - if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { - Diag(Loc, diag::err_auto_bitfield); - return DAR_FailedAlreadyDiagnosed; + *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, + OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0)) + return DeductionFailed(TDK); } - if (auto TDK = DeduceTemplateArgumentsFromCallArgument( - *this, TemplateParamsSt.get(), 0, FuncParam, Init, Info, Deduced, - OriginalCallArgs, /*Decomposed*/ false, /*ArgIdx*/ 0, /*TDF*/ 0)) - return DeductionFailed(TDK, {}); - } - - // Could be null if somehow 'auto' appears in a non-deduced context. - if (Deduced[0].getKind() != TemplateArgument::Type) - return DeductionFailed(TDK_Incomplete, {}); - - QualType DeducedType = Deduced[0].getAsType(); + // Could be null if somehow 'auto' appears in a non-deduced context. + if (Deduced[0].getKind() != TemplateArgument::Type) + return DeductionFailed(TDK_Incomplete); + DeducedType = Deduced[0].getAsType(); - if (InitList) { - DeducedType = BuildStdInitializerList(DeducedType, Loc); - if (DeducedType.isNull()) - return DAR_FailedAlreadyDiagnosed; + if (InitList) { + DeducedType = BuildStdInitializerList(DeducedType, Loc); + if (DeducedType.isNull()) + return TDK_AlreadyDiagnosed; + } } - QualType MaybeAuto = Type.getType().getNonReferenceType(); - while (MaybeAuto->isPointerType()) - MaybeAuto = MaybeAuto->getPointeeType(); - if (const auto *AT = MaybeAuto->getAs<AutoType>()) { - if (AT->isConstrained() && !IgnoreConstraints) { - auto ConstraintsResult = CheckDeducedPlaceholderConstraints( - *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType); - if (ConstraintsResult != DAR_Succeeded) - return ConstraintsResult; + if (!Result.isNull()) { + if (!Context.hasSameType(DeducedType, Result)) { + Info.FirstArg = Result; + Info.SecondArg = DeducedType; + return DeductionFailed(TDK_Inconsistent); } + DeducedType = Context.getCommonSugaredType(Result, DeducedType); } + if (AT->isConstrained() && !IgnoreConstraints && + CheckDeducedPlaceholderConstraints( + *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType)) + return TDK_AlreadyDiagnosed; + Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; + return TDK_AlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -4794,11 +4861,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, if (auto TDK = CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { Result = QualType(); - return DeductionFailed(TDK, {}); + return DeductionFailed(TDK); } } - return DAR_Succeeded; + return TDK_Success; } QualType Sema::SubstAutoType(QualType TypeWithAuto, @@ -5102,27 +5169,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, return true; } -/// Determine whether this a function template whose parameter-type-list -/// ends with a function parameter pack. -static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { - FunctionDecl *Function = FunTmpl->getTemplatedDecl(); - unsigned NumParams = Function->getNumParams(); - if (NumParams == 0) - return false; - - ParmVarDecl *Last = Function->getParamDecl(NumParams - 1); - if (!Last->isParameterPack()) - return false; - - // Make sure that no previous parameter is a parameter pack. - while (--NumParams > 0) { - if (Function->getParamDecl(NumParams - 1)->isParameterPack()) - return false; - } - - return true; -} - /// Returns the more specialized function template according /// to the rules of function template partial ordering (C++ [temp.func.order]). /// @@ -5143,53 +5189,128 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { /// candidate with a reversed parameter order. In this case, the corresponding /// P/A pairs between FT1 and FT2 are reversed. /// -/// \param AllowOrderingByConstraints If \c is false, don't check whether one -/// of the templates is more constrained than the other. Default is true. -/// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, - unsigned NumCallArguments2, bool Reversed, - bool AllowOrderingByConstraints) { - - auto JudgeByConstraints = [&]() -> FunctionTemplateDecl * { - if (!AllowOrderingByConstraints) - return nullptr; - llvm::SmallVector<const Expr *, 3> AC1, AC2; - FT1->getAssociatedConstraints(AC1); - FT2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? FT1 : FT2; - }; + unsigned NumCallArguments2, bool Reversed) { bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1, Reversed); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, NumCallArguments2, Reversed); + // C++ [temp.deduct.partial]p10: + // F is more specialized than G if F is at least as specialized as G and G + // is not at least as specialized as F. if (Better1 != Better2) // We have a clear winner return Better1 ? FT1 : FT2; if (!Better1 && !Better2) // Neither is better than the other - return JudgeByConstraints(); + return nullptr; - // FIXME: This mimics what GCC implements, but doesn't match up with the - // proposed resolution for core issue 692. This area needs to be sorted out, - // but for now we attempt to maintain compatibility. - bool Variadic1 = isVariadicFunctionTemplate(FT1); - bool Variadic2 = isVariadicFunctionTemplate(FT2); - if (Variadic1 != Variadic2) - return Variadic1? FT2 : FT1; + // C++ [temp.deduct.partial]p11: + // ... and if G has a trailing function parameter pack for which F does not + // have a corresponding parameter, and if F does not have a trailing + // function parameter pack, then F is more specialized than G. + FunctionDecl *FD1 = FT1->getTemplatedDecl(); + FunctionDecl *FD2 = FT2->getTemplatedDecl(); + unsigned NumParams1 = FD1->getNumParams(); + unsigned NumParams2 = FD2->getNumParams(); + bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack(); + bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack(); + if (Variadic1 != Variadic2) { + if (Variadic1 && NumParams1 > NumParams2) + return FT2; + if (Variadic2 && NumParams2 > NumParams1) + return FT1; + } + + // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that + // there is no wording or even resolution for this issue. + for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) { + QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType(); + QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType(); + auto *TST1 = dyn_cast<TemplateSpecializationType>(T1); + auto *TST2 = dyn_cast<TemplateSpecializationType>(T2); + if (!TST1 || !TST2) + continue; + const TemplateArgument &TA1 = TST1->template_arguments().back(); + if (TA1.getKind() == TemplateArgument::Pack) { + assert(TST1->template_arguments().size() == + TST2->template_arguments().size()); + const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TA2.getKind() == TemplateArgument::Pack); + unsigned PackSize1 = TA1.pack_size(); + unsigned PackSize2 = TA2.pack_size(); + bool IsPackExpansion1 = + PackSize1 && TA1.pack_elements().back().isPackExpansion(); + bool IsPackExpansion2 = + PackSize2 && TA2.pack_elements().back().isPackExpansion(); + if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) { + if (PackSize1 > PackSize2 && IsPackExpansion1) + return FT2; + if (PackSize1 < PackSize2 && IsPackExpansion2) + return FT1; + } + } + } + + if (!Context.getLangOpts().CPlusPlus20) + return nullptr; + + // Match GCC on not implementing [temp.func.order]p6.2.1. + + // C++20 [temp.func.order]p6: + // If deduction against the other template succeeds for both transformed + // templates, constraints can be considered as follows: + + // C++20 [temp.func.order]p6.1: + // If their template-parameter-lists (possibly including template-parameters + // invented for an abbreviated function template ([dcl.fct])) or function + // parameter lists differ in length, neither template is more specialized + // than the other. + TemplateParameterList *TPL1 = FT1->getTemplateParameters(); + TemplateParameterList *TPL2 = FT2->getTemplateParameters(); + if (TPL1->size() != TPL2->size() || NumParams1 != NumParams2) + return nullptr; + + // C++20 [temp.func.order]p6.2.2: + // Otherwise, if the corresponding template-parameters of the + // template-parameter-lists are not equivalent ([temp.over.link]) or if the + // function parameters that positionally correspond between the two + // templates are not of the same type, neither template is more specialized + // than the other. + if (!TemplateParameterListsAreEqual( + TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + return nullptr; + + for (unsigned i = 0; i < NumParams1; ++i) + if (!Context.hasSameType(FD1->getParamDecl(i)->getType(), + FD2->getParamDecl(i)->getType())) + return nullptr; + + // C++20 [temp.func.order]p6.3: + // Otherwise, if the context in which the partial ordering is done is + // that of a call to a conversion function and the return types of the + // templates are not the same, then neither template is more specialized + // than the other. + if (TPOC == TPOC_Conversion && + !Context.hasSameType(FD1->getReturnType(), FD2->getReturnType())) + return nullptr; - return JudgeByConstraints(); + llvm::SmallVector<const Expr *, 3> AC1, AC2; + FT1->getAssociatedConstraints(AC1); + FT2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) + return nullptr; + if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? FT1 : FT2; } /// Determine if the two templates are equivalent. @@ -5354,7 +5475,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, if (Inst.isInvalid()) return false; - auto *TST1 = T1->castAs<TemplateSpecializationType>(); + const auto *TST1 = cast<TemplateSpecializationType>(T1); bool AtLeastAsSpecialized; S.runWithSufficientStackSpace(Info.getLocation(), [&] { AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( @@ -5366,6 +5487,180 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, return AtLeastAsSpecialized; } +namespace { +// A dummy class to return nullptr instead of P2 when performing "more +// specialized than primary" check. +struct GetP2 { + template <typename T1, typename T2, + std::enable_if_t<std::is_same_v<T1, T2>, bool> = true> + T2 *operator()(T1 *, T2 *P2) { + return P2; + } + template <typename T1, typename T2, + std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true> + T1 *operator()(T1 *, T2 *) { + return nullptr; + } +}; + +// The assumption is that two template argument lists have the same size. +struct TemplateArgumentListAreEqual { + ASTContext &Ctx; + TemplateArgumentListAreEqual(ASTContext &Ctx) : Ctx(Ctx) {} + + template <typename T1, typename T2, + std::enable_if_t<std::is_same_v<T1, T2>, bool> = true> + bool operator()(T1 *PS1, T2 *PS2) { + ArrayRef<TemplateArgument> Args1 = PS1->getTemplateArgs().asArray(), + Args2 = PS2->getTemplateArgs().asArray(); + + for (unsigned I = 0, E = Args1.size(); I < E; ++I) { + // We use profile, instead of structural comparison of the arguments, + // because canonicalization can't do the right thing for dependent + // expressions. + llvm::FoldingSetNodeID IDA, IDB; + Args1[I].Profile(IDA, Ctx); + Args2[I].Profile(IDB, Ctx); + if (IDA != IDB) + return false; + } + return true; + } + + template <typename T1, typename T2, + std::enable_if_t<!std::is_same_v<T1, T2>, bool> = true> + bool operator()(T1 *Spec, T2 *Primary) { + ArrayRef<TemplateArgument> Args1 = Spec->getTemplateArgs().asArray(), + Args2 = Primary->getInjectedTemplateArgs(); + + for (unsigned I = 0, E = Args1.size(); I < E; ++I) { + // We use profile, instead of structural comparison of the arguments, + // because canonicalization can't do the right thing for dependent + // expressions. + llvm::FoldingSetNodeID IDA, IDB; + Args1[I].Profile(IDA, Ctx); + // Unlike the specialization arguments, the injected arguments are not + // always canonical. + Ctx.getCanonicalTemplateArgument(Args2[I]).Profile(IDB, Ctx); + if (IDA != IDB) + return false; + } + return true; + } +}; +} // namespace + +/// Returns the more specialized template specialization between T1/P1 and +/// T2/P2. +/// - If IsMoreSpecialThanPrimaryCheck is true, T1/P1 is the partial +/// specialization and T2/P2 is the primary template. +/// - otherwise, both T1/P1 and T2/P2 are the partial specialization. +/// +/// \param T1 the type of the first template partial specialization +/// +/// \param T2 if IsMoreSpecialThanPrimaryCheck is true, the type of the second +/// template partial specialization; otherwise, the type of the +/// primary template. +/// +/// \param P1 the first template partial specialization +/// +/// \param P2 if IsMoreSpecialThanPrimaryCheck is true, the second template +/// partial specialization; otherwise, the primary template. +/// +/// \returns - If IsMoreSpecialThanPrimaryCheck is true, returns P1 if P1 is +/// more specialized, returns nullptr if P1 is not more specialized. +/// - otherwise, returns the more specialized template partial +/// specialization. If neither partial specialization is more +/// specialized, returns NULL. +template <typename TemplateLikeDecl, typename PrimaryDel> +static TemplateLikeDecl * +getMoreSpecialized(Sema &S, QualType T1, QualType T2, TemplateLikeDecl *P1, + PrimaryDel *P2, TemplateDeductionInfo &Info) { + constexpr bool IsMoreSpecialThanPrimaryCheck = + !std::is_same_v<TemplateLikeDecl, PrimaryDel>; + + bool Better1 = isAtLeastAsSpecializedAs(S, T1, T2, P2, Info); + if (IsMoreSpecialThanPrimaryCheck && !Better1) + return nullptr; + + bool Better2 = isAtLeastAsSpecializedAs(S, T2, T1, P1, Info); + if (IsMoreSpecialThanPrimaryCheck && !Better2) + return P1; + + // C++ [temp.deduct.partial]p10: + // F is more specialized than G if F is at least as specialized as G and G + // is not at least as specialized as F. + if (Better1 != Better2) // We have a clear winner + return Better1 ? P1 : GetP2()(P1, P2); + + if (!Better1 && !Better2) + return nullptr; + + // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that + // there is no wording or even resolution for this issue. + auto *TST1 = cast<TemplateSpecializationType>(T1); + auto *TST2 = cast<TemplateSpecializationType>(T2); + const TemplateArgument &TA1 = TST1->template_arguments().back(); + if (TA1.getKind() == TemplateArgument::Pack) { + assert(TST1->template_arguments().size() == + TST2->template_arguments().size()); + const TemplateArgument &TA2 = TST2->template_arguments().back(); + assert(TA2.getKind() == TemplateArgument::Pack); + unsigned PackSize1 = TA1.pack_size(); + unsigned PackSize2 = TA2.pack_size(); + bool IsPackExpansion1 = + PackSize1 && TA1.pack_elements().back().isPackExpansion(); + bool IsPackExpansion2 = + PackSize2 && TA2.pack_elements().back().isPackExpansion(); + if (PackSize1 != PackSize2 && IsPackExpansion1 != IsPackExpansion2) { + if (PackSize1 > PackSize2 && IsPackExpansion1) + return GetP2()(P1, P2); + if (PackSize1 < PackSize2 && IsPackExpansion2) + return P1; + } + } + + if (!S.Context.getLangOpts().CPlusPlus20) + return nullptr; + + // Match GCC on not implementing [temp.func.order]p6.2.1. + + // C++20 [temp.func.order]p6: + // If deduction against the other template succeeds for both transformed + // templates, constraints can be considered as follows: + + TemplateParameterList *TPL1 = P1->getTemplateParameters(); + TemplateParameterList *TPL2 = P2->getTemplateParameters(); + if (TPL1->size() != TPL2->size()) + return nullptr; + + // C++20 [temp.func.order]p6.2.2: + // Otherwise, if the corresponding template-parameters of the + // template-parameter-lists are not equivalent ([temp.over.link]) or if the + // function parameters that positionally correspond between the two + // templates are not of the same type, neither template is more specialized + // than the other. + if (!S.TemplateParameterListsAreEqual( + TPL1, TPL2, false, Sema::TPL_TemplateMatch, SourceLocation(), true)) + return nullptr; + + if (!TemplateArgumentListAreEqual(S.getASTContext())(P1, P2)) + return nullptr; + + llvm::SmallVector<const Expr *, 3> AC1, AC2; + P1->getAssociatedConstraints(AC1); + P2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (S.IsAtLeastAsConstrained(P1, AC1, P2, AC2, AtLeastAsConstrained1) || + (IsMoreSpecialThanPrimaryCheck && !AtLeastAsConstrained1)) + return nullptr; + if (S.IsAtLeastAsConstrained(P2, AC2, P1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? P1 : GetP2()(P1, P2); +} + /// Returns the more specialized class template partial specialization /// according to the rules of partial ordering of class template partial /// specializations (C++ [temp.class.order]). @@ -5385,26 +5680,7 @@ Sema::getMoreSpecializedPartialSpecialization( QualType PT2 = PS2->getInjectedSpecializationType(); TemplateDeductionInfo Info(Loc); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; - } - - return Better1 ? PS1 : PS2; + return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); } bool Sema::isMoreSpecializedThanPrimary( @@ -5412,24 +5688,12 @@ bool Sema::isMoreSpecializedThanPrimary( ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); QualType PartialT = Spec->getInjectedSpecializationType(); - if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) - return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) - return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) - return false; - return !AtLeastAsConstrainedPrimary; + + ClassTemplatePartialSpecializationDecl *MaybeSpec = + getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); + if (MaybeSpec) + Info.clearSFINAEDiagnostic(); + return MaybeSpec; } VarTemplatePartialSpecializationDecl * @@ -5449,62 +5713,24 @@ Sema::getMoreSpecializedPartialSpecialization( CanonTemplate, PS2->getTemplateArgs().asArray()); TemplateDeductionInfo Info(Loc); - bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); - bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - - if (!Better1 && !Better2) - return nullptr; - if (Better1 && Better2) { - llvm::SmallVector<const Expr *, 3> AC1, AC2; - PS1->getAssociatedConstraints(AC1); - PS2->getAssociatedConstraints(AC2); - bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) - return nullptr; - if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) - return nullptr; - if (AtLeastAsConstrained1 == AtLeastAsConstrained2) - return nullptr; - return AtLeastAsConstrained1 ? PS1 : PS2; - } - - return Better1 ? PS1 : PS2; + return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info); } bool Sema::isMoreSpecializedThanPrimary( VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { - TemplateDecl *Primary = Spec->getSpecializedTemplate(); - // FIXME: Cache the injected template arguments rather than recomputing - // them for each partial specialization. - SmallVector<TemplateArgument, 8> PrimaryArgs; - Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), - PrimaryArgs); - + VarTemplateDecl *Primary = Spec->getSpecializedTemplate(); TemplateName CanonTemplate = Context.getCanonicalTemplateName(TemplateName(Primary)); QualType PrimaryT = Context.getTemplateSpecializationType( - CanonTemplate, PrimaryArgs); + CanonTemplate, Primary->getInjectedTemplateArgs()); QualType PartialT = Context.getTemplateSpecializationType( CanonTemplate, Spec->getTemplateArgs().asArray()); - if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) - return false; - if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) - return true; - Info.clearSFINAEDiagnostic(); - llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; - Primary->getAssociatedConstraints(PrimaryAC); - Spec->getAssociatedConstraints(SpecAC); - bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; - if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, - AtLeastAsConstrainedSpec)) - return false; - if (!AtLeastAsConstrainedSpec) - return false; - if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, - AtLeastAsConstrainedPrimary)) - return false; - return !AtLeastAsConstrainedPrimary; + VarTemplatePartialSpecializationDecl *MaybeSpec = + getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info); + if (MaybeSpec) + Info.clearSFINAEDiagnostic(); + return MaybeSpec; } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( @@ -5556,13 +5782,15 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( // C++1z [temp.arg.template]p3: // If the rewrite produces an invalid type, then P is not at least as // specialized as A. - if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) || + SmallVector<TemplateArgument, 4> SugaredPArgs; + if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, SugaredPArgs, + PArgs) || Trap.hasErrorOccurred()) return false; } - QualType AType = Context.getTemplateSpecializationType(X, AArgs); - QualType PType = Context.getTemplateSpecializationType(X, PArgs); + QualType AType = Context.getCanonicalTemplateSpecializationType(X, AArgs); + QualType PType = Context.getCanonicalTemplateSpecializationType(X, PArgs); // ... the function template corresponding to P is at least as specialized // as the function template corresponding to A according to the partial @@ -5588,8 +5816,8 @@ struct MarkUsedTemplateParameterVisitor : } bool TraverseTemplateName(TemplateName Template) { - if (auto *TTP = - dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl())) + if (auto *TTP = llvm::dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) if (TTP->getDepth() == Depth) Used[TTP->getIndex()] = true; RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>:: @@ -5734,7 +5962,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, cast<DependentSizedArrayType>(T)->getSizeExpr(), OnlyDeduced, Depth, Used); // Fall through to check the element type - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::ConstantArray: case Type::IncompleteArray: @@ -5834,9 +6062,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::SubstTemplateTypeParmPack: { const SubstTemplateTypeParmPackType *Subst = cast<SubstTemplateTypeParmPackType>(T); - MarkUsedTemplateParameters(Ctx, - QualType(Subst->getReplacedParameter(), 0), - OnlyDeduced, Depth, Used); + if (Subst->getReplacedParameter()->getDepth() == Depth) + Used[Subst->getIndex()] = true; MarkUsedTemplateParameters(Ctx, Subst->getArgumentPack(), OnlyDeduced, Depth, Used); break; @@ -5844,7 +6071,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::InjectedClassName: T = cast<InjectedClassNameType>(T)->getInjectedSpecializationType(); - LLVM_FALLTHROUGH; + [[fallthrough]]; case Type::TemplateSpecialization: { const TemplateSpecializationType *Spec @@ -5860,9 +6087,8 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, hasPackExpansionBeforeEnd(Spec->template_arguments())) break; - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const auto &Arg : Spec->template_arguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } @@ -5906,16 +6132,14 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, MarkUsedTemplateParameters(Ctx, Spec->getQualifier(), OnlyDeduced, Depth, Used); - for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) - MarkUsedTemplateParameters(Ctx, Spec->getArg(I), OnlyDeduced, Depth, - Used); + for (const auto &Arg : Spec->template_arguments()) + MarkUsedTemplateParameters(Ctx, Arg, OnlyDeduced, Depth, Used); break; } case Type::TypeOf: if (!OnlyDeduced) - MarkUsedTemplateParameters(Ctx, - cast<TypeOfType>(T)->getUnderlyingType(), + MarkUsedTemplateParameters(Ctx, cast<TypeOfType>(T)->getUnmodifiedType(), OnlyDeduced, Depth, Used); break; |