https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/133426
>From 464aaf0944cac75ccc689ebb82e08554c12c6340 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Thu, 27 Mar 2025 16:25:07 +0100 Subject: [PATCH 1/6] [Clang][WIP][RFC] Bypass TAD during overload resolution if a perfect match exists This implements the same overload resolution behavior as GCC, as described in https://wg21.link/p3606 (section 1-2, not 3) If during overload resolution, there is a non-template candidate that would be always be picked - because each of the argument is a perfect match (ie the source and target types are the same), we do not perform deduction for any template candidate that might exists. The goal is to be able to merge #122423 without being too disruptive. This change means that the selection of the best viable candidate and template argument deduction become interleaved. To avoid rewriting half of Clang we store in `OverloadCandidateSet` enough information to be able to deduce template candidates from `OverloadCandidateSet::BestViableFunction`. Which means the lifetime of any object used by template argument must outlive a call to `Add*Template*Candidate`. This two phase resolution is not performed for some initialization as there are cases where template candidate are better match in these cases per the standard. It's also bypassed for code completion. The change has a nice impact on compile times https://llvm-compile-time-tracker.com/compare.php?from=719b029c16eeb1035da522fd641dfcc4cee6be74&to=bf7041045c9408490c395230047c5461de72fc39&stat=instructions%3Au Fixes #62096 Fixes #74581 --- clang/include/clang/Sema/Overload.h | 130 +++++++++++++- clang/include/clang/Sema/Sema.h | 25 +++ clang/lib/Sema/SemaCodeComplete.cpp | 6 +- clang/lib/Sema/SemaInit.cpp | 11 +- clang/lib/Sema/SemaOverload.cpp | 263 +++++++++++++++++++++++++--- 5 files changed, 395 insertions(+), 40 deletions(-) diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 6e08762dcc6d7..2cc7e1809e26c 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -38,6 +38,7 @@ #include <cstddef> #include <cstdint> #include <utility> +#include <variant> namespace clang { @@ -743,6 +744,12 @@ class Sema; Standard.setAllToTypes(T); } + bool isPerfect(const ASTContext &C) const { + return (isStandard() && Standard.isIdentityConversion() && + C.hasSameType(Standard.getFromType(), Standard.getToType(2))) || + getKind() == StaticObjectArgumentConversion; + } + // True iff this is a conversion sequence from an initializer list to an // array or std::initializer. bool hasInitializerListContainerType() const { @@ -979,6 +986,18 @@ class Sema; return false; } + bool isPerfectMatch(const ASTContext &Ctx) const { + if (!Viable) + return false; + for (auto &C : Conversions) { + if (!C.isInitialized()) + return false; + if (!C.isPerfect(Ctx)) + return false; + } + return true; + } + bool TryToFixBadConversion(unsigned Idx, Sema &S) { bool CanFix = Fix.tryToFixConversion( Conversions[Idx].Bad.FromExpr, @@ -1015,6 +1034,61 @@ class Sema; RewriteKind(CRK_None) {} }; + struct NonDeducedConversionTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + CXXRecordDecl *ActingContext; + Expr *From; + QualType ToType; + + LLVM_PREFERRED_TYPE(bool) + unsigned AllowObjCConversionOnExplicit : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowExplicit : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowResultConversion : 1; + }; + + struct NonDeducedMethodTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + ArrayRef<Expr *> Args; + CXXRecordDecl *ActingContext; + Expr::Classification ObjectClassification; + QualType ObjectType; + + OverloadCandidateParamOrder PO; + LLVM_PREFERRED_TYPE(bool) + unsigned SuppressUserConversions : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned PartialOverloading : 1; + }; + + struct NonDeducedFunctionTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + ArrayRef<Expr *> Args; + + CallExpr::ADLCallKind IsADLCandidate; + OverloadCandidateParamOrder PO; + LLVM_PREFERRED_TYPE(bool) + unsigned SuppressUserConversions : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned PartialOverloading : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowExplicit : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AggregateCandidateDeduction : 1; + }; + + using NonDeducedTemplateOverloadCandidate = + std::variant<NonDeducedConversionTemplateOverloadCandidate, + NonDeducedMethodTemplateOverloadCandidate, + NonDeducedFunctionTemplateOverloadCandidate>; + + static_assert( + std::is_trivially_destructible_v<NonDeducedTemplateOverloadCandidate>); + /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). class OverloadCandidateSet { @@ -1043,6 +1117,8 @@ class Sema; /// C++ [over.match.call.general] /// Resolve a call through the address of an overload set. CSK_AddressOfOverloadSet, + + CSK_CodeCompletion, }; /// Information about operator rewrites to consider when adding operator @@ -1116,6 +1192,7 @@ class Sema; private: SmallVector<OverloadCandidate, 16> Candidates; llvm::SmallPtrSet<uintptr_t, 16> Functions; + SmallVector<NonDeducedTemplateOverloadCandidate, 8> NonDeducedCandidates; // Allocator for ConversionSequenceLists. We store the first few of these // inline to avoid allocation for small sets. @@ -1126,7 +1203,7 @@ class Sema; OperatorRewriteInfo RewriteInfo; constexpr static unsigned NumInlineBytes = - 24 * sizeof(ImplicitConversionSequence); + 32 * sizeof(ImplicitConversionSequence); unsigned NumInlineBytesUsed = 0; alignas(void *) char InlineSpace[NumInlineBytes]; @@ -1144,8 +1221,8 @@ class Sema; // It's simpler if this doesn't need to consider alignment. static_assert(alignof(T) == alignof(void *), "Only works for pointer-aligned types."); - static_assert(std::is_trivial<T>::value || - std::is_same<ImplicitConversionSequence, T>::value, + static_assert(std::is_trivially_destructible_v<T> || + (std::is_same_v<ImplicitConversionSequence, T>), "Add destruction logic to OverloadCandidateSet::clear()."); unsigned NBytes = sizeof(T) * N; @@ -1199,8 +1276,12 @@ class Sema; iterator begin() { return Candidates.begin(); } iterator end() { return Candidates.end(); } - size_t size() const { return Candidates.size(); } - bool empty() const { return Candidates.empty(); } + size_t size() const { + return Candidates.size() + NonDeducedCandidates.size(); + } + bool empty() const { + return Candidates.empty() && NonDeducedCandidates.empty(); + } /// Allocate storage for conversion sequences for NumConversions /// conversions. @@ -1216,6 +1297,19 @@ class Sema; return ConversionSequenceList(Conversions, NumConversions); } + llvm::MutableArrayRef<Expr *> getPersistentArgsArray(unsigned N) { + Expr **Exprs = slabAllocate<Expr *>(N); + return llvm::MutableArrayRef<Expr *>(Exprs, N); + } + + template <typename... T> + llvm::MutableArrayRef<Expr *> getPersistentArgsArray(T *...Exprs) { + llvm::MutableArrayRef<Expr *> Arr = + getPersistentArgsArray(sizeof...(Exprs)); + llvm::copy(std::initializer_list<Expr *>{Exprs...}, Arr.data()); + return Arr; + } + /// Add a new candidate with NumConversions conversion sequence slots /// to the overload set. OverloadCandidate &addCandidate(unsigned NumConversions = 0, @@ -1231,10 +1325,36 @@ class Sema; return C; } + void AddNonDeducedTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + ArrayRef<Expr *> Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction); + + void AddNonDeducedMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO); + + void AddNonDeducedConversionTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion); + + void InjectNonDeducedTemplateCandidates(Sema &S); + /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator& Best); + OverloadingResult + BestViableFunctionImpl(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator &Best); + SmallVector<OverloadCandidate *, 32> CompleteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, SourceLocation OpLoc = SourceLocation(), diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 066bce61c74c1..90ea990315cff 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -60,6 +60,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/IdentifierResolver.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Redeclaration.h" @@ -10342,9 +10343,26 @@ class Sema final : public SemaBase { OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); + void AddMethodTemplateCandidateImmediately( + OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *MethodTmpl, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO); + /// Add a C++ function template specialization as a candidate /// in the candidate set, using template argument deduction to produce /// an appropriate function template specialization. + + void AddTemplateOverloadCandidateImmediately( + OverloadCandidateSet &CandidateSet, + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, + ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction); + void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, @@ -10389,6 +10407,13 @@ class Sema final : public SemaBase { OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); + void AddTemplateConversionCandidateImmediately( + OverloadCandidateSet &CandidateSet, + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion); + /// AddSurrogateCandidate - Adds a "surrogate" candidate function that /// converts the given @c Object to a function pointer via the /// conversion function @c Conversion, and then attempts to call it diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 2003701b65654..e314f6859d71c 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -6364,7 +6364,8 @@ SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef<Expr *> Args, Expr *NakedFn = Fn->IgnoreParenCasts(); // Build an overload candidate set based on the functions we find. SourceLocation Loc = Fn->getExprLoc(); - OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet(Loc, + OverloadCandidateSet::CSK_CodeCompletion); if (auto ULE = dyn_cast<UnresolvedLookupExpr>(NakedFn)) { SemaRef.AddOverloadedCallCandidates(ULE, ArgsWithoutDependentTypes, @@ -6567,7 +6568,8 @@ QualType SemaCodeCompletion::ProduceConstructorSignatureHelp( // FIXME: Provide support for variadic template constructors. if (CRD) { - OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); + OverloadCandidateSet CandidateSet(Loc, + OverloadCandidateSet::CSK_CodeCompletion); for (NamedDecl *C : SemaRef.LookupConstructors(CRD)) { if (auto *FD = dyn_cast<FunctionDecl>(C)) { // FIXME: we can't yet provide correct signature help for initializer diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 9814c3f456f0d..f947b29e16881 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10043,12 +10043,15 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // When [...] the constructor [...] is a candidate by // - [over.match.copy] (in all cases) if (TD) { - SmallVector<Expr *, 8> TmpInits; - for (Expr *E : Inits) + MutableArrayRef<Expr *> TmpInits = + Candidates.getPersistentArgsArray(Inits.size()); + for (auto [I, E] : llvm::enumerate(Inits)) { if (auto *DI = dyn_cast<DesignatedInitExpr>(E)) - TmpInits.push_back(DI->getInit()); + TmpInits[I] = DI->getInit(); else - TmpInits.push_back(E); + TmpInits[I] = E; + } + AddTemplateOverloadCandidate( TD, FoundDecl, /*ExplicitArgs=*/nullptr, TmpInits, Candidates, /*SuppressUserConversions=*/false, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 6d8006b35dcf4..b2a99de9d38e2 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -31,6 +31,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaObjC.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -45,6 +46,7 @@ #include <cstddef> #include <cstdlib> #include <optional> +#include <variant> using namespace clang; using namespace sema; @@ -7797,6 +7799,28 @@ void Sema::AddMethodTemplateCandidate( if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) return; + if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion || + ExplicitTemplateArgs) { + AddMethodTemplateCandidateImmediately( + CandidateSet, MethodTmpl, FoundDecl, ActingContext, + ExplicitTemplateArgs, ObjectType, ObjectClassification, Args, + SuppressUserConversions, PartialOverloading, PO); + return; + } + + CandidateSet.AddNonDeducedMethodTemplateCandidate( + MethodTmpl, FoundDecl, ActingContext, ObjectType, ObjectClassification, + Args, SuppressUserConversions, PartialOverloading, PO); +} + +void Sema::AddMethodTemplateCandidateImmediately( + OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *MethodTmpl, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO) { + // C++ [over.match.funcs]p7: // In each case where a candidate is a function template, candidate // function template specializations are generated using template argument @@ -7826,7 +7850,7 @@ void Sema::AddMethodTemplateCandidate( Candidate.Function = MethodTmpl->getTemplatedDecl(); Candidate.Viable = false; Candidate.RewriteKind = - CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); + CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); Candidate.IsSurrogate = false; Candidate.IgnoreObjectArgument = cast<CXXMethodDecl>(Candidate.Function)->isStatic() || @@ -7836,8 +7860,8 @@ void Sema::AddMethodTemplateCandidate( Candidate.FailureKind = ovl_fail_bad_conversion; else { Candidate.FailureKind = ovl_fail_bad_deduction; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, - Info); + Candidate.DeductionFailure = + MakeDeductionFailureInfo(Context, Result, Info); } return; } @@ -7868,6 +7892,28 @@ void Sema::AddTemplateOverloadCandidate( if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) return; + if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion || + ExplicitTemplateArgs) { + AddTemplateOverloadCandidateImmediately( + CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs, Args, + SuppressUserConversions, PartialOverloading, AllowExplicit, + IsADLCandidate, PO, AggregateCandidateDeduction); + return; + } + + CandidateSet.AddNonDeducedTemplateCandidate( + FunctionTemplate, FoundDecl, Args, SuppressUserConversions, + PartialOverloading, AllowExplicit, IsADLCandidate, PO, + AggregateCandidateDeduction); +} + +void Sema::AddTemplateOverloadCandidateImmediately( + OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, + ArrayRef<Expr *> Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { + // If the function template has a non-dependent explicit specification, // exclude it now if appropriate; we are not permitted to perform deduction // and substitution in this case. @@ -7911,7 +7957,7 @@ void Sema::AddTemplateOverloadCandidate( Candidate.Function = FunctionTemplate->getTemplatedDecl(); Candidate.Viable = false; Candidate.RewriteKind = - CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); + CandidateSet.getRewriteInfo().getRewriteKind(Candidate.Function, PO); Candidate.IsSurrogate = false; Candidate.IsADLCandidate = llvm::to_underlying(IsADLCandidate); // Ignore the object argument if there is one, since we don't have an object @@ -7924,8 +7970,8 @@ void Sema::AddTemplateOverloadCandidate( Candidate.FailureKind = ovl_fail_bad_conversion; else { Candidate.FailureKind = ovl_fail_bad_deduction; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, - Info); + Candidate.DeductionFailure = + MakeDeductionFailureInfo(Context, Result, Info); } return; } @@ -8267,6 +8313,25 @@ void Sema::AddTemplateConversionCandidate( if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; + if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion) { + AddTemplateConversionCandidateImmediately( + CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From, ToType, + AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); + + return; + } + + CandidateSet.AddNonDeducedConversionTemplateCandidate( + FunctionTemplate, FoundDecl, ActingDC, From, ToType, + AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); +} + +void Sema::AddTemplateConversionCandidateImmediately( + OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *FunctionTemplate, + DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, + QualType ToType, bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion) { + // If the function template has a non-dependent explicit specification, // exclude it now if appropriate; we are not permitted to perform deduction // and substitution in this case. @@ -8294,15 +8359,15 @@ void Sema::AddTemplateConversionCandidate( Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.ExplicitCallArguments = 1; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, - Info); + Candidate.DeductionFailure = + MakeDeductionFailureInfo(Context, Result, Info); return; } // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, FoundDecl, ActingDC, From, ToType, + AddConversionCandidate(Specialization, FoundDecl, ActingContext, From, ToType, CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion, Info.hasStrictPackMatch()); @@ -8441,6 +8506,13 @@ void Sema::AddNonMemberOperatorCandidates( NamedDecl *D = F.getDecl()->getUnderlyingDecl(); ArrayRef<Expr *> FunctionArgs = Args; + auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { + if (Arr.empty()) + Arr = CandidateSet.getPersistentArgsArray(FunctionArgs[1], + FunctionArgs[0]); + return Arr; + }; + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); FunctionDecl *FD = FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D); @@ -8455,18 +8527,18 @@ void Sema::AddNonMemberOperatorCandidates( if (FunTmpl) { AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) - AddTemplateOverloadCandidate( - FunTmpl, F.getPair(), ExplicitTemplateArgs, - {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false, - true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed); + if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { + AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, + ReversedArgs(), CandidateSet, false, false, + true, ADLCallKind::NotADL, + OverloadCandidateParamOrder::Reversed); + } } else { if (ExplicitTemplateArgs) continue; AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) - AddOverloadCandidate(FD, F.getPair(), - {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, + AddOverloadCandidate(FD, F.getPair(), ReversedArgs(), CandidateSet, false, false, true, false, ADLCallKind::NotADL, {}, OverloadCandidateParamOrder::Reversed); } @@ -10191,6 +10263,12 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // FIXME: Pass in the explicit template arguments? ArgumentDependentLookup(Name, Loc, Args, Fns); + auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { + if (Arr.empty()) + Arr = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); + return Arr; + }; + // Erase all of the candidates we already knew about. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), CandEnd = CandidateSet.end(); @@ -10217,7 +10295,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { AddOverloadCandidate( - FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, + FD, FoundDecl, ReversedArgs(), CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL, {}, OverloadCandidateParamOrder::Reversed); @@ -10231,8 +10309,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, if (CandidateSet.getRewriteInfo().shouldAddReversed( *this, Args, FTD->getTemplatedDecl())) { AddTemplateOverloadCandidate( - FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]}, - CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, + FTD, FoundDecl, ExplicitTemplateArgs, ReversedArgs(), CandidateSet, + /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, ADLCallKind::UsesADL, OverloadCandidateParamOrder::Reversed); } @@ -10905,6 +10983,93 @@ bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { ->Satisfaction.ContainsErrors; } +void OverloadCandidateSet::AddNonDeducedTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + ArrayRef<Expr *> Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction) { + NonDeducedFunctionTemplateOverloadCandidate C{FunctionTemplate, + FoundDecl, + Args, + IsADLCandidate, + PO, + SuppressUserConversions, + PartialOverloading, + AllowExplicit, + AggregateCandidateDeduction}; + NonDeducedCandidates.emplace_back(std::move(C)); +} + +void OverloadCandidateSet::AddNonDeducedMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO) { + NonDeducedMethodTemplateOverloadCandidate C{ + MethodTmpl, FoundDecl, Args, ActingContext, + ObjectClassification, ObjectType, PO, SuppressUserConversions, + PartialOverloading}; + NonDeducedCandidates.emplace_back(std::move(C)); +} + +void OverloadCandidateSet::AddNonDeducedConversionTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion) { + + NonDeducedConversionTemplateOverloadCandidate C{ + FunctionTemplate, FoundDecl, + ActingContext, From, + ToType, AllowObjCConversionOnExplicit, + AllowExplicit, AllowResultConversion}; + + NonDeducedCandidates.emplace_back(std::move(C)); +} + +static void +AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, + NonDeducedMethodTemplateOverloadCandidate &&C) { + + S.AddMethodTemplateCandidateImmediately( + CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, + /*ExplicitTemplateArgs=*/nullptr, C.ObjectType, C.ObjectClassification, + C.Args, C.SuppressUserConversions, C.PartialOverloading, C.PO); +} + +static void +AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, + NonDeducedFunctionTemplateOverloadCandidate &&C) { + S.AddTemplateOverloadCandidateImmediately( + CandidateSet, C.FunctionTemplate, C.FoundDecl, + /*ExplicitTemplateArgs=*/nullptr, C.Args, C.SuppressUserConversions, + C.PartialOverloading, C.AllowExplicit, C.IsADLCandidate, C.PO, + C.AggregateCandidateDeduction); +} + +static void AddTemplateOverloadCandidate( + Sema &S, OverloadCandidateSet &CandidateSet, + NonDeducedConversionTemplateOverloadCandidate &&C) { + return S.AddTemplateConversionCandidateImmediately( + CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, C.From, + C.ToType, C.AllowObjCConversionOnExplicit, C.AllowExplicit, + C.AllowResultConversion); +} + +void OverloadCandidateSet::InjectNonDeducedTemplateCandidates(Sema &S) { + Candidates.reserve(Candidates.size() + NonDeducedCandidates.size()); + for (auto &&Elem : NonDeducedCandidates) { + std::visit( + [&](auto &&Cand) { + AddTemplateOverloadCandidate(S, *this, std::move(Cand)); + }, + Elem); + } + NonDeducedCandidates.clear(); +} + /// Computes the best viable function (C++ 13.3.3) /// within an overload candidate set. /// @@ -10918,7 +11083,44 @@ bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, iterator &Best) { + + bool TwoPhaseResolution = + !NonDeducedCandidates.empty() && Kind != CSK_CodeCompletion && + Kind != CSK_InitByUserDefinedConversion && Kind != CSK_InitByConstructor; + + if (TwoPhaseResolution) { + Best = end(); + for (auto It = begin(); It != end(); ++It) { + if (It->isPerfectMatch(S.getASTContext())) { + if (Best == end()) { + Best = It; + } else { + Best = end(); + break; + } + } + } + if (Best != end()) { + Best->Best = true; + if (Best->Function && Best->Function->isDeleted()) + return OR_Deleted; + if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function); + Kind == CSK_AddressOfOverloadSet && M && + M->isImplicitObjectMemberFunction()) { + return OR_No_Viable_Function; + } + return OR_Success; + } + } + InjectNonDeducedTemplateCandidates(S); + return BestViableFunctionImpl(S, Loc, Best); +} + +OverloadingResult OverloadCandidateSet::BestViableFunctionImpl( + Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best) { + llvm::SmallVector<OverloadCandidate *, 16> Candidates; + Candidates.reserve(this->Candidates.size()); std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); @@ -10953,7 +11155,6 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, } } - // Find the best viable function. Best = end(); for (auto *Cand : Candidates) { Cand->Best = false; @@ -10975,9 +11176,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, if (Best == end()) return OR_No_Viable_Function; + llvm::SmallVector<OverloadCandidate *, 4> PendingBest; llvm::SmallVector<const NamedDecl *, 4> EquivalentCands; - - llvm::SmallVector<OverloadCandidate*, 4> PendingBest; PendingBest.push_back(&*Best); Best->Best = true; @@ -10999,8 +11199,6 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, } } } - - // If we found more than one best candidate, this is ambiguous. if (Best == end()) return OR_Ambiguous; @@ -11014,10 +11212,9 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, return OR_No_Viable_Function; } - if (!EquivalentCands.empty()) + if (NonDeducedCandidates.empty() && !EquivalentCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); - return OR_Success; } @@ -12714,6 +12911,9 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, SourceLocation OpLoc, llvm::function_ref<bool(OverloadCandidate &)> Filter) { + + InjectNonDeducedTemplateCandidates(S); + // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. SmallVector<OverloadCandidate*, 32> Cands; @@ -14689,18 +14889,23 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, // rewritten candidates using these functions if necessary. AddNonMemberOperatorCandidates(Fns, Args, CandidateSet); + auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { + if (Arr.empty()) + Arr = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); + return Arr; + }; + // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); if (CandidateSet.getRewriteInfo().allowsReversed(Op)) - AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet, + AddMemberOperatorCandidates(Op, OpLoc, ReversedArgs(), CandidateSet, OverloadCandidateParamOrder::Reversed); // In C++20, also add any rewritten member candidates. if (ExtraOp) { AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet); if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp)) - AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]}, - CandidateSet, + AddMemberOperatorCandidates(ExtraOp, OpLoc, ReversedArgs(), CandidateSet, OverloadCandidateParamOrder::Reversed); } >From 7e9dc4be74a69b5a89d024f801b7135ff4df7a80 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Sat, 29 Mar 2025 12:34:55 +0100 Subject: [PATCH 2/6] avoid comparing types --- clang/include/clang/Sema/Overload.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 2cc7e1809e26c..4fb6bfe0aa55b 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -745,8 +745,9 @@ class Sema; } bool isPerfect(const ASTContext &C) const { - return (isStandard() && Standard.isIdentityConversion() && - C.hasSameType(Standard.getFromType(), Standard.getToType(2))) || + return (isStandard() && Standard.isIdentityConversion() + && !Standard.DirectBinding + ) || getKind() == StaticObjectArgumentConversion; } @@ -989,7 +990,7 @@ class Sema; bool isPerfectMatch(const ASTContext &Ctx) const { if (!Viable) return false; - for (auto &C : Conversions) { + for (const auto &C : Conversions) { if (!C.isInitialized()) return false; if (!C.isPerfect(Ctx)) >From f63761f5b6db9b38ed21b23337b43e28da418658 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Sat, 29 Mar 2025 13:57:47 +0100 Subject: [PATCH 3/6] Fix logic --- clang/include/clang/Sema/Overload.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 4fb6bfe0aa55b..4bd94ce7bff94 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -745,10 +745,9 @@ class Sema; } bool isPerfect(const ASTContext &C) const { - return (isStandard() && Standard.isIdentityConversion() - && !Standard.DirectBinding - ) || - getKind() == StaticObjectArgumentConversion; + return isStandard() && Standard.isIdentityConversion() && + (!Standard.ReferenceBinding || C.hasSameType(Standard.getFromType(), Standard.getToType(2))) + ; } // True iff this is a conversion sequence from an initializer list to an >From e660ace1d2b52ef6455eecc96a45a13fa42e6869 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Sat, 29 Mar 2025 15:19:03 +0100 Subject: [PATCH 4/6] optimize --- clang/lib/Sema/SemaOverload.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index b2a99de9d38e2..8d1d73a9a6ebe 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11112,7 +11112,10 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, return OR_Success; } } - InjectNonDeducedTemplateCandidates(S); + + if(!NonDeducedCandidates.empty()) + InjectNonDeducedTemplateCandidates(S); + return BestViableFunctionImpl(S, Loc, Best); } >From 8dd498a2999810a8b8fb50518867f85f26753760 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Sat, 29 Mar 2025 15:26:52 +0100 Subject: [PATCH 5/6] optimize again --- clang/lib/Sema/SemaOverload.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 8d1d73a9a6ebe..e6657471a0144 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -8506,13 +8506,6 @@ void Sema::AddNonMemberOperatorCandidates( NamedDecl *D = F.getDecl()->getUnderlyingDecl(); ArrayRef<Expr *> FunctionArgs = Args; - auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { - if (Arr.empty()) - Arr = CandidateSet.getPersistentArgsArray(FunctionArgs[1], - FunctionArgs[0]); - return Arr; - }; - FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); FunctionDecl *FD = FunTmpl ? FunTmpl->getTemplatedDecl() : cast<FunctionDecl>(D); @@ -8528,8 +8521,10 @@ void Sema::AddNonMemberOperatorCandidates( AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { + ArrayRef<Expr *> Reversed = CandidateSet.getPersistentArgsArray(FunctionArgs[1], + FunctionArgs[0]); AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, - ReversedArgs(), CandidateSet, false, false, + Reversed, CandidateSet, false, false, true, ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed); } @@ -8538,7 +8533,8 @@ void Sema::AddNonMemberOperatorCandidates( continue; AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) - AddOverloadCandidate(FD, F.getPair(), ReversedArgs(), CandidateSet, + AddOverloadCandidate(FD, F.getPair(), {FunctionArgs[1], + FunctionArgs[0]}, CandidateSet, false, false, true, false, ADLCallKind::NotADL, {}, OverloadCandidateParamOrder::Reversed); } >From 901287d946d4b6dbfdbd689c7bd7318f386c584f Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Mon, 31 Mar 2025 16:34:02 +0200 Subject: [PATCH 6/6] Cleanups, fix tests --- clang/include/clang/Sema/Overload.h | 67 ++- clang/include/clang/Sema/Sema.h | 23 - clang/lib/Sema/SemaInit.cpp | 4 + clang/lib/Sema/SemaOverload.cpp | 475 ++++++++++-------- .../constrant-satisfaction-conversions.cpp | 8 +- .../SemaCXX/implicit-member-functions.cpp | 21 +- .../instantiate-function-params.cpp | 7 +- .../Templight/templight-empty-entries-fix.cpp | 34 +- 8 files changed, 336 insertions(+), 303 deletions(-) diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 4bd94ce7bff94..63339a917c3a4 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -408,6 +408,11 @@ class Sema; Third == ICK_Identity; } + bool isPerfect(const ASTContext &C) const { + return isIdentityConversion() && + (!ReferenceBinding || C.hasSameType(getFromType(), getToType(2))); + } + ImplicitConversionRank getRank() const; NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, @@ -745,9 +750,7 @@ class Sema; } bool isPerfect(const ASTContext &C) const { - return isStandard() && Standard.isIdentityConversion() && - (!Standard.ReferenceBinding || C.hasSameType(Standard.getFromType(), Standard.getToType(2))) - ; + return isStandard() && Standard.isPerfect(C); } // True iff this is a conversion sequence from an initializer list to an @@ -995,6 +998,8 @@ class Sema; if (!C.isPerfect(Ctx)) return false; } + if (isa_and_nonnull<CXXConversionDecl>(Function)) + return FinalConversion.isPerfect(Ctx); return true; } @@ -1034,7 +1039,7 @@ class Sema; RewriteKind(CRK_None) {} }; - struct NonDeducedConversionTemplateOverloadCandidate { + struct DeferredConversionTemplateOverloadCandidate { FunctionTemplateDecl *FunctionTemplate; DeclAccessPair FoundDecl; CXXRecordDecl *ActingContext; @@ -1049,7 +1054,7 @@ class Sema; unsigned AllowResultConversion : 1; }; - struct NonDeducedMethodTemplateOverloadCandidate { + struct DeferredMethodTemplateOverloadCandidate { FunctionTemplateDecl *FunctionTemplate; DeclAccessPair FoundDecl; ArrayRef<Expr *> Args; @@ -1064,7 +1069,7 @@ class Sema; unsigned PartialOverloading : 1; }; - struct NonDeducedFunctionTemplateOverloadCandidate { + struct DeferredFunctionTemplateOverloadCandidate { FunctionTemplateDecl *FunctionTemplate; DeclAccessPair FoundDecl; ArrayRef<Expr *> Args; @@ -1081,13 +1086,13 @@ class Sema; unsigned AggregateCandidateDeduction : 1; }; - using NonDeducedTemplateOverloadCandidate = - std::variant<NonDeducedConversionTemplateOverloadCandidate, - NonDeducedMethodTemplateOverloadCandidate, - NonDeducedFunctionTemplateOverloadCandidate>; + using DeferredTemplateOverloadCandidate = + std::variant<DeferredConversionTemplateOverloadCandidate, + DeferredMethodTemplateOverloadCandidate, + DeferredFunctionTemplateOverloadCandidate>; static_assert( - std::is_trivially_destructible_v<NonDeducedTemplateOverloadCandidate>); + std::is_trivially_destructible_v<DeferredTemplateOverloadCandidate>); /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). @@ -1192,7 +1197,7 @@ class Sema; private: SmallVector<OverloadCandidate, 16> Candidates; llvm::SmallPtrSet<uintptr_t, 16> Functions; - SmallVector<NonDeducedTemplateOverloadCandidate, 8> NonDeducedCandidates; + SmallVector<DeferredTemplateOverloadCandidate, 8> DeferredCandidates; // Allocator for ConversionSequenceLists. We store the first few of these // inline to avoid allocation for small sets. @@ -1204,6 +1209,7 @@ class Sema; constexpr static unsigned NumInlineBytes = 32 * sizeof(ImplicitConversionSequence); + unsigned NumInlineBytesUsed = 0; alignas(void *) char InlineSpace[NumInlineBytes]; @@ -1214,8 +1220,6 @@ class Sema; /// from the slab allocator. /// FIXME: It would probably be nice to have a SmallBumpPtrAllocator /// instead. - /// FIXME: Now that this only allocates ImplicitConversionSequences, do we - /// want to un-generalize this? template <typename T> T *slabAllocate(unsigned N) { // It's simpler if this doesn't need to consider alignment. @@ -1253,6 +1257,9 @@ class Sema; /// Whether diagnostics should be deferred. bool shouldDeferDiags(Sema &S, ArrayRef<Expr *> Args, SourceLocation OpLoc); + // Whether the resolution of template candidates should be defered + bool shouldDeferTemplateArgumentDeduction(const LangOptions &Opts) const; + /// Determine when this overload candidate will be new to the /// overload set. bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO = @@ -1277,10 +1284,10 @@ class Sema; iterator end() { return Candidates.end(); } size_t size() const { - return Candidates.size() + NonDeducedCandidates.size(); + return Candidates.size() + DeferredCandidates.size(); } bool empty() const { - return Candidates.empty() && NonDeducedCandidates.empty(); + return Candidates.empty() && DeferredCandidates.empty(); } /// Allocate storage for conversion sequences for NumConversions @@ -1325,21 +1332,21 @@ class Sema; return C; } - void AddNonDeducedTemplateCandidate( + void AddDeferredTemplateCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction); - void AddNonDeducedMethodTemplateCandidate( + void AddDeferredMethodTemplateCandidate( FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, bool SuppressUserConversions, bool PartialOverloading, OverloadCandidateParamOrder PO); - void AddNonDeducedConversionTemplateCandidate( + void AddDeferredConversionTemplateCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, bool AllowObjCConversionOnExplicit, bool AllowExplicit, @@ -1351,10 +1358,6 @@ class Sema; OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator& Best); - OverloadingResult - BestViableFunctionImpl(Sema &S, SourceLocation Loc, - OverloadCandidateSet::iterator &Best); - SmallVector<OverloadCandidate *, 32> CompleteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, SourceLocation OpLoc = SourceLocation(), @@ -1383,6 +1386,14 @@ class Sema; DestAS = AS; } + private: + OverloadingResult ResultForBestCandidate(const iterator &Best); + void CudaExcludeWrongSideCandidates(Sema &S); + OverloadingResult + BestViableFunctionImpl(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator &Best); + void PerfectViableFunction(Sema &S, SourceLocation Loc, + OverloadCandidateSet::iterator &Best); }; bool isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, @@ -1431,6 +1442,16 @@ class Sema; // parameter. bool shouldEnforceArgLimit(bool PartialOverloading, FunctionDecl *Function); + inline bool OverloadCandidateSet::shouldDeferTemplateArgumentDeduction( + const LangOptions &Opts) const { + return + // For user defined conversion we need to check against different + // combination of CV qualifiers and look at any expicit specifier, so + // always deduce template candidate. + Kind != CSK_InitByUserDefinedConversion && Kind != CSK_CodeCompletion && + Opts.CPlusPlus && (!Opts.CUDA || Opts.GPUExcludeWrongSideOverloads); + } + } // namespace clang #endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 90ea990315cff..ab2a94584d46c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10343,26 +10343,10 @@ class Sema final : public SemaBase { OverloadCandidateSet &CandidateSet, bool SuppressUserConversions = false, bool PartialOverloading = false, OverloadCandidateParamOrder PO = {}); - void AddMethodTemplateCandidateImmediately( - OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *MethodTmpl, - DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, - TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, - Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, - bool SuppressUserConversions, bool PartialOverloading, - OverloadCandidateParamOrder PO); - /// Add a C++ function template specialization as a candidate /// in the candidate set, using template argument deduction to produce /// an appropriate function template specialization. - void AddTemplateOverloadCandidateImmediately( - OverloadCandidateSet &CandidateSet, - FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, - TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, - bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, - ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, - bool AggregateCandidateDeduction); - void AddTemplateOverloadCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, @@ -10407,13 +10391,6 @@ class Sema final : public SemaBase { OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion = true); - void AddTemplateConversionCandidateImmediately( - OverloadCandidateSet &CandidateSet, - FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingContext, Expr *From, QualType ToType, - bool AllowObjCConversionOnExplicit, bool AllowExplicit, - bool AllowResultConversion); - /// AddSurrogateCandidate - Adds a "surrogate" candidate function that /// converts the given @c Object to a function pointer via the /// conversion function @c Conversion, and then attempts to call it diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index f947b29e16881..a8ab43776a6de 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10043,8 +10043,12 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // When [...] the constructor [...] is a candidate by // - [over.match.copy] (in all cases) if (TD) { + + // As template candidates are not deduced immediately, + // persist the arry in the overload set. MutableArrayRef<Expr *> TmpInits = Candidates.getPersistentArgsArray(Inits.size()); + for (auto [I, E] : llvm::enumerate(Inits)) { if (auto *DI = dyn_cast<DesignatedInitExpr>(E)) TmpInits[I] = DI->getInit(); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index e6657471a0144..ddf4d26ee5b13 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -7789,35 +7789,12 @@ void Sema::AddMethodCandidate( } } -void Sema::AddMethodTemplateCandidate( +static void AddMethodTemplateCandidateImmediately( + Sema &S, OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, - OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, OverloadCandidateParamOrder PO) { - if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) - return; - - if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion || - ExplicitTemplateArgs) { - AddMethodTemplateCandidateImmediately( - CandidateSet, MethodTmpl, FoundDecl, ActingContext, - ExplicitTemplateArgs, ObjectType, ObjectClassification, Args, - SuppressUserConversions, PartialOverloading, PO); - return; - } - - CandidateSet.AddNonDeducedMethodTemplateCandidate( - MethodTmpl, FoundDecl, ActingContext, ObjectType, ObjectClassification, - Args, SuppressUserConversions, PartialOverloading, PO); -} - -void Sema::AddMethodTemplateCandidateImmediately( - OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *MethodTmpl, - DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, - TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, - Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, bool SuppressUserConversions, bool PartialOverloading, OverloadCandidateParamOrder PO) { @@ -7833,12 +7810,12 @@ void Sema::AddMethodTemplateCandidateImmediately( TemplateDeductionInfo Info(CandidateSet.getLocation()); FunctionDecl *Specialization = nullptr; ConversionSequenceList Conversions; - if (TemplateDeductionResult Result = DeduceTemplateArguments( + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, /*AggregateDeductionCandidate=*/false, /*PartialOrdering=*/false, ObjectType, ObjectClassification, [&](ArrayRef<QualType> ParamTypes) { - return CheckNonDependentConversions( + return S.CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, ActingContext, ObjectType, ObjectClassification, PO); @@ -7861,7 +7838,7 @@ void Sema::AddMethodTemplateCandidateImmediately( else { Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.DeductionFailure = - MakeDeductionFailureInfo(Context, Result, Info); + MakeDeductionFailureInfo(S.Context, Result, Info); } return; } @@ -7871,48 +7848,49 @@ void Sema::AddMethodTemplateCandidateImmediately( assert(Specialization && "Missing member function template specialization?"); assert(isa<CXXMethodDecl>(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast<CXXMethodDecl>(Specialization), FoundDecl, - ActingContext, ObjectType, ObjectClassification, Args, - CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO, Info.hasStrictPackMatch()); + S.AddMethodCandidate( + cast<CXXMethodDecl>(Specialization), FoundDecl, ActingContext, ObjectType, + ObjectClassification, Args, CandidateSet, SuppressUserConversions, + PartialOverloading, Conversions, PO, Info.hasStrictPackMatch()); } -/// Determine whether a given function template has a simple explicit specifier -/// or a non-value-dependent explicit-specification that evaluates to true. -static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) { - return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit(); -} - -void Sema::AddTemplateOverloadCandidate( - FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, - TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, +void Sema::AddMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, - bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, - OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { - if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) + bool PartialOverloading, OverloadCandidateParamOrder PO) { + if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) return; - if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion || - ExplicitTemplateArgs) { - AddTemplateOverloadCandidateImmediately( - CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs, Args, - SuppressUserConversions, PartialOverloading, AllowExplicit, - IsADLCandidate, PO, AggregateCandidateDeduction); + if (ExplicitTemplateArgs || + !CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) { + AddMethodTemplateCandidateImmediately( + *this, CandidateSet, MethodTmpl, FoundDecl, ActingContext, + ExplicitTemplateArgs, ObjectType, ObjectClassification, Args, + SuppressUserConversions, PartialOverloading, PO); return; } - CandidateSet.AddNonDeducedTemplateCandidate( - FunctionTemplate, FoundDecl, Args, SuppressUserConversions, - PartialOverloading, AllowExplicit, IsADLCandidate, PO, - AggregateCandidateDeduction); + CandidateSet.AddDeferredMethodTemplateCandidate( + MethodTmpl, FoundDecl, ActingContext, ObjectType, ObjectClassification, + Args, SuppressUserConversions, PartialOverloading, PO); } -void Sema::AddTemplateOverloadCandidateImmediately( - OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, TemplateArgumentListInfo *ExplicitTemplateArgs, - ArrayRef<Expr *> Args, bool SuppressUserConversions, - bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, - OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { +/// Determine whether a given function template has a simple explicit specifier +/// or a non-value-dependent explicit-specification that evaluates to true. +static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) { + return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit(); +} + +static void AddTemplateOverloadCandidateImmediately( + Sema &S, OverloadCandidateSet &CandidateSet, + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, + Sema::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction) { // If the function template has a non-dependent explicit specification, // exclude it now if appropriate; we are not permitted to perform deduction @@ -7939,14 +7917,14 @@ void Sema::AddTemplateOverloadCandidateImmediately( FunctionTemplate->getTemplateDepth()); FunctionDecl *Specialization = nullptr; ConversionSequenceList Conversions; - if (TemplateDeductionResult Result = DeduceTemplateArguments( + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( FunctionTemplate, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, AggregateCandidateDeduction, /*PartialOrdering=*/false, /*ObjectType=*/QualType(), /*ObjectClassification=*/Expr::Classification(), [&](ArrayRef<QualType> ParamTypes) { - return CheckNonDependentConversions( + return S.CheckNonDependentConversions( FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, nullptr, QualType(), {}, PO); }); @@ -7971,7 +7949,7 @@ void Sema::AddTemplateOverloadCandidateImmediately( else { Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.DeductionFailure = - MakeDeductionFailureInfo(Context, Result, Info); + MakeDeductionFailureInfo(S.Context, Result, Info); } return; } @@ -7979,7 +7957,7 @@ void Sema::AddTemplateOverloadCandidateImmediately( // Add the function template specialization produced by template argument // deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddOverloadCandidate( + S.AddOverloadCandidate( Specialization, FoundDecl, Args, CandidateSet, SuppressUserConversions, PartialOverloading, AllowExplicit, /*AllowExplicitConversions=*/false, IsADLCandidate, Conversions, PO, @@ -7987,6 +7965,30 @@ void Sema::AddTemplateOverloadCandidateImmediately( Info.hasStrictPackMatch()); } +void Sema::AddTemplateOverloadCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef<Expr *> Args, + OverloadCandidateSet &CandidateSet, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, ADLCallKind IsADLCandidate, + OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { + if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) + return; + + if (ExplicitTemplateArgs || + !CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) { + AddTemplateOverloadCandidateImmediately( + *this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs, + Args, SuppressUserConversions, PartialOverloading, AllowExplicit, + IsADLCandidate, PO, AggregateCandidateDeduction); + return; + } + + CandidateSet.AddDeferredTemplateCandidate( + FunctionTemplate, FoundDecl, Args, SuppressUserConversions, + PartialOverloading, AllowExplicit, IsADLCandidate, PO, + AggregateCandidateDeduction); +} + bool Sema::CheckNonDependentConversions( FunctionTemplateDecl *FunctionTemplate, ArrayRef<QualType> ParamTypes, ArrayRef<Expr *> Args, OverloadCandidateSet &CandidateSet, @@ -8302,34 +8304,11 @@ void Sema::AddConversionCandidate( } } -void Sema::AddTemplateConversionCandidate( +static void AddTemplateConversionCandidateImmediately( + Sema &S, OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, - CXXRecordDecl *ActingDC, Expr *From, QualType ToType, - OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, - bool AllowExplicit, bool AllowResultConversion) { - assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && - "Only conversion function templates permitted here"); - - if (!CandidateSet.isNewCandidate(FunctionTemplate)) - return; - - if (CandidateSet.getKind() == OverloadCandidateSet::CSK_CodeCompletion) { - AddTemplateConversionCandidateImmediately( - CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From, ToType, - AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); - - return; - } - - CandidateSet.AddNonDeducedConversionTemplateCandidate( - FunctionTemplate, FoundDecl, ActingDC, From, ToType, - AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); -} - -void Sema::AddTemplateConversionCandidateImmediately( - OverloadCandidateSet &CandidateSet, FunctionTemplateDecl *FunctionTemplate, - DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, - QualType ToType, bool AllowObjCConversionOnExplicit, bool AllowExplicit, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion) { // If the function template has a non-dependent explicit specification, @@ -8345,11 +8324,11 @@ void Sema::AddTemplateConversionCandidateImmediately( } QualType ObjectType = From->getType(); - Expr::Classification ObjectClassification = From->Classify(getASTContext()); + Expr::Classification ObjectClassification = From->Classify(S.Context); TemplateDeductionInfo Info(CandidateSet.getLocation()); CXXConversionDecl *Specialization = nullptr; - if (TemplateDeductionResult Result = DeduceTemplateArguments( + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( FunctionTemplate, ObjectType, ObjectClassification, ToType, Specialization, Info); Result != TemplateDeductionResult::Success) { @@ -8360,17 +8339,42 @@ void Sema::AddTemplateConversionCandidateImmediately( Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.ExplicitCallArguments = 1; Candidate.DeductionFailure = - MakeDeductionFailureInfo(Context, Result, Info); + MakeDeductionFailureInfo(S.Context, Result, Info); return; } // Add the conversion function template specialization produced by // template argument deduction as a candidate. assert(Specialization && "Missing function template specialization?"); - AddConversionCandidate(Specialization, FoundDecl, ActingContext, From, ToType, - CandidateSet, AllowObjCConversionOnExplicit, - AllowExplicit, AllowResultConversion, - Info.hasStrictPackMatch()); + S.AddConversionCandidate(Specialization, FoundDecl, ActingContext, From, + ToType, CandidateSet, AllowObjCConversionOnExplicit, + AllowExplicit, AllowResultConversion, + Info.hasStrictPackMatch()); +} + +void Sema::AddTemplateConversionCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingDC, Expr *From, QualType ToType, + OverloadCandidateSet &CandidateSet, bool AllowObjCConversionOnExplicit, + bool AllowExplicit, bool AllowResultConversion) { + assert(isa<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()) && + "Only conversion function templates permitted here"); + + if (!CandidateSet.isNewCandidate(FunctionTemplate)) + return; + + if (!CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) { + AddTemplateConversionCandidateImmediately( + *this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From, + ToType, AllowObjCConversionOnExplicit, AllowExplicit, + AllowResultConversion); + + return; + } + + CandidateSet.AddDeferredConversionTemplateCandidate( + FunctionTemplate, FoundDecl, ActingDC, From, ToType, + AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); } void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, @@ -8521,11 +8525,14 @@ void Sema::AddNonMemberOperatorCandidates( AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { - ArrayRef<Expr *> Reversed = CandidateSet.getPersistentArgsArray(FunctionArgs[1], - FunctionArgs[0]); + + // As template candidates are not deduced immediately, + // persist the arry in the overload set. + ArrayRef<Expr *> Reversed = CandidateSet.getPersistentArgsArray( + FunctionArgs[1], FunctionArgs[0]); AddTemplateOverloadCandidate(FunTmpl, F.getPair(), ExplicitTemplateArgs, - Reversed, CandidateSet, false, false, - true, ADLCallKind::NotADL, + Reversed, CandidateSet, false, false, true, + ADLCallKind::NotADL, OverloadCandidateParamOrder::Reversed); } } else { @@ -8533,8 +8540,8 @@ void Sema::AddNonMemberOperatorCandidates( continue; AddOverloadCandidate(FD, F.getPair(), FunctionArgs, CandidateSet); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) - AddOverloadCandidate(FD, F.getPair(), {FunctionArgs[1], - FunctionArgs[0]}, CandidateSet, + AddOverloadCandidate(FD, F.getPair(), + {FunctionArgs[1], FunctionArgs[0]}, CandidateSet, false, false, true, false, ADLCallKind::NotADL, {}, OverloadCandidateParamOrder::Reversed); } @@ -10259,11 +10266,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // FIXME: Pass in the explicit template arguments? ArgumentDependentLookup(Name, Loc, Args, Fns); - auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { - if (Arr.empty()) - Arr = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); - return Arr; - }; + ArrayRef<Expr *> ReversedArgs; // Erase all of the candidates we already knew about. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), @@ -10291,7 +10294,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed(*this, Args, FD)) { AddOverloadCandidate( - FD, FoundDecl, ReversedArgs(), CandidateSet, + FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, /*AllowExplicitConversion=*/false, ADLCallKind::UsesADL, {}, OverloadCandidateParamOrder::Reversed); @@ -10304,8 +10307,14 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, /*AllowExplicit=*/true, ADLCallKind::UsesADL); if (CandidateSet.getRewriteInfo().shouldAddReversed( *this, Args, FTD->getTemplatedDecl())) { + + // As template candidates are not deduced immediately, + // persist the arry in the overload set. + if (ReversedArgs.empty()) + ReversedArgs = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); + AddTemplateOverloadCandidate( - FTD, FoundDecl, ExplicitTemplateArgs, ReversedArgs(), CandidateSet, + FTD, FoundDecl, ExplicitTemplateArgs, ReversedArgs, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, /*AllowExplicit=*/true, ADLCallKind::UsesADL, OverloadCandidateParamOrder::Reversed); @@ -10979,91 +10988,143 @@ bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { ->Satisfaction.ContainsErrors; } -void OverloadCandidateSet::AddNonDeducedTemplateCandidate( +void OverloadCandidateSet::AddDeferredTemplateCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, ArrayRef<Expr *> Args, bool SuppressUserConversions, bool PartialOverloading, bool AllowExplicit, CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, bool AggregateCandidateDeduction) { - NonDeducedFunctionTemplateOverloadCandidate C{FunctionTemplate, - FoundDecl, - Args, - IsADLCandidate, - PO, - SuppressUserConversions, - PartialOverloading, - AllowExplicit, - AggregateCandidateDeduction}; - NonDeducedCandidates.emplace_back(std::move(C)); + DeferredFunctionTemplateOverloadCandidate C{FunctionTemplate, + FoundDecl, + Args, + IsADLCandidate, + PO, + SuppressUserConversions, + PartialOverloading, + AllowExplicit, + AggregateCandidateDeduction}; + DeferredCandidates.emplace_back(std::move(C)); } -void OverloadCandidateSet::AddNonDeducedMethodTemplateCandidate( +void OverloadCandidateSet::AddDeferredMethodTemplateCandidate( FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, QualType ObjectType, Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, bool SuppressUserConversions, bool PartialOverloading, OverloadCandidateParamOrder PO) { - NonDeducedMethodTemplateOverloadCandidate C{ + DeferredMethodTemplateOverloadCandidate C{ MethodTmpl, FoundDecl, Args, ActingContext, ObjectClassification, ObjectType, PO, SuppressUserConversions, PartialOverloading}; - NonDeducedCandidates.emplace_back(std::move(C)); + DeferredCandidates.emplace_back(std::move(C)); } -void OverloadCandidateSet::AddNonDeducedConversionTemplateCandidate( +void OverloadCandidateSet::AddDeferredConversionTemplateCandidate( FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, CXXRecordDecl *ActingContext, Expr *From, QualType ToType, bool AllowObjCConversionOnExplicit, bool AllowExplicit, bool AllowResultConversion) { - NonDeducedConversionTemplateOverloadCandidate C{ + DeferredConversionTemplateOverloadCandidate C{ FunctionTemplate, FoundDecl, ActingContext, From, ToType, AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion}; - NonDeducedCandidates.emplace_back(std::move(C)); + DeferredCandidates.emplace_back(std::move(C)); } static void AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, - NonDeducedMethodTemplateOverloadCandidate &&C) { + DeferredMethodTemplateOverloadCandidate &&C) { - S.AddMethodTemplateCandidateImmediately( - CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, + AddMethodTemplateCandidateImmediately( + S, CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, /*ExplicitTemplateArgs=*/nullptr, C.ObjectType, C.ObjectClassification, C.Args, C.SuppressUserConversions, C.PartialOverloading, C.PO); } static void AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, - NonDeducedFunctionTemplateOverloadCandidate &&C) { - S.AddTemplateOverloadCandidateImmediately( - CandidateSet, C.FunctionTemplate, C.FoundDecl, + DeferredFunctionTemplateOverloadCandidate &&C) { + AddTemplateOverloadCandidateImmediately( + S, CandidateSet, C.FunctionTemplate, C.FoundDecl, /*ExplicitTemplateArgs=*/nullptr, C.Args, C.SuppressUserConversions, C.PartialOverloading, C.AllowExplicit, C.IsADLCandidate, C.PO, C.AggregateCandidateDeduction); } -static void AddTemplateOverloadCandidate( - Sema &S, OverloadCandidateSet &CandidateSet, - NonDeducedConversionTemplateOverloadCandidate &&C) { - return S.AddTemplateConversionCandidateImmediately( - CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, C.From, +static void +AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, + DeferredConversionTemplateOverloadCandidate &&C) { + return AddTemplateConversionCandidateImmediately( + S, CandidateSet, C.FunctionTemplate, C.FoundDecl, C.ActingContext, C.From, C.ToType, C.AllowObjCConversionOnExplicit, C.AllowExplicit, C.AllowResultConversion); } void OverloadCandidateSet::InjectNonDeducedTemplateCandidates(Sema &S) { - Candidates.reserve(Candidates.size() + NonDeducedCandidates.size()); - for (auto &&Elem : NonDeducedCandidates) { + Candidates.reserve(Candidates.size() + DeferredCandidates.size()); + for (auto &&Elem : DeferredCandidates) { std::visit( [&](auto &&Cand) { AddTemplateOverloadCandidate(S, *this, std::move(Cand)); }, Elem); } - NonDeducedCandidates.clear(); + DeferredCandidates.clear(); +} + +OverloadingResult +OverloadCandidateSet::ResultForBestCandidate(const iterator &Best) { + Best->Best = true; + if (Best->Function && Best->Function->isDeleted()) + return OR_Deleted; + if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function); + Kind == CSK_AddressOfOverloadSet && M && + M->isImplicitObjectMemberFunction()) { + return OR_No_Viable_Function; + } + return OR_Success; +} + +void OverloadCandidateSet::CudaExcludeWrongSideCandidates(Sema &S) { + // [CUDA] HD->H or HD->D calls are technically not allowed by CUDA but + // are accepted by both clang and NVCC. However, during a particular + // compilation mode only one call variant is viable. We need to + // exclude non-viable overload candidates from consideration based + // only on their host/device attributes. Specifically, if one + // candidate call is WrongSide and the other is SameSide, we ignore + // the WrongSide candidate. + // We only need to remove wrong-sided candidates here if + // -fgpu-exclude-wrong-side-overloads is off. When + // -fgpu-exclude-wrong-side-overloads is on, all candidates are compared + // uniformly in isBetterOverloadCandidate. + if (!S.getLangOpts().CUDA || S.getLangOpts().GPUExcludeWrongSideOverloads) + return; + const FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true); + + bool ContainsSameSideCandidate = + llvm::any_of(Candidates, [&](const OverloadCandidate &Cand) { + // Check viable function only. + return Cand.Viable && Cand.Function && + S.CUDA().IdentifyPreference(Caller, Cand.Function) == + SemaCUDA::CFP_SameSide; + }); + if (!ContainsSameSideCandidate) + return; + + auto IsWrongSideCandidate = [&](const OverloadCandidate &Cand) { + // Check viable function only to avoid unnecessary data copying/moving. + return Cand.Viable && Cand.Function && + S.CUDA().IdentifyPreference(Caller, Cand.Function) == + SemaCUDA::CFP_WrongSide; + }; + + for (auto &Cand : Candidates) { + if (IsWrongSideCandidate(Cand)) + Cand.Viable = false; + } } /// Computes the best viable function (C++ 13.3.3) @@ -11080,41 +11141,56 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, iterator &Best) { - bool TwoPhaseResolution = - !NonDeducedCandidates.empty() && Kind != CSK_CodeCompletion && - Kind != CSK_InitByUserDefinedConversion && Kind != CSK_InitByConstructor; + assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) || + DeferredCandidates.empty() && + "Unexpected deferred template candidate"); + + if (S.getLangOpts().CUDA) + CudaExcludeWrongSideCandidates(S); + + bool TwoPhaseResolution = !DeferredCandidates.empty(); if (TwoPhaseResolution) { - Best = end(); - for (auto It = begin(); It != end(); ++It) { - if (It->isPerfectMatch(S.getASTContext())) { - if (Best == end()) { - Best = It; - } else { - Best = end(); - break; - } - } - } - if (Best != end()) { - Best->Best = true; - if (Best->Function && Best->Function->isDeleted()) - return OR_Deleted; - if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function); - Kind == CSK_AddressOfOverloadSet && M && - M->isImplicitObjectMemberFunction()) { - return OR_No_Viable_Function; - } - return OR_Success; - } - } - if(!NonDeducedCandidates.empty()) + PerfectViableFunction(S, Loc, Best); + if (Best != end()) + return ResultForBestCandidate(Best); + InjectNonDeducedTemplateCandidates(S); + if (S.getLangOpts().CUDA) + CudaExcludeWrongSideCandidates(S); + } + return BestViableFunctionImpl(S, Loc, Best); } +void OverloadCandidateSet::PerfectViableFunction( + Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best) { + Best = end(); + for (auto It = begin(); It != end(); ++It) { + if (It->isPerfectMatch(S.getASTContext())) { + if (Best == end()) { + Best = It; + } else { + if (Best->Function && It->Function) { + FunctionDecl *D = + S.getMoreConstrainedFunction(Best->Function, It->Function); + if (D == nullptr) { + Best = end(); + break; + } + if (D == It->Function) + Best = It; + continue; + } + Best = end(); + break; + } + } + } +} + OverloadingResult OverloadCandidateSet::BestViableFunctionImpl( Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator &Best) { @@ -11123,37 +11199,6 @@ OverloadingResult OverloadCandidateSet::BestViableFunctionImpl( std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); - // [CUDA] HD->H or HD->D calls are technically not allowed by CUDA but - // are accepted by both clang and NVCC. However, during a particular - // compilation mode only one call variant is viable. We need to - // exclude non-viable overload candidates from consideration based - // only on their host/device attributes. Specifically, if one - // candidate call is WrongSide and the other is SameSide, we ignore - // the WrongSide candidate. - // We only need to remove wrong-sided candidates here if - // -fgpu-exclude-wrong-side-overloads is off. When - // -fgpu-exclude-wrong-side-overloads is on, all candidates are compared - // uniformly in isBetterOverloadCandidate. - if (S.getLangOpts().CUDA && !S.getLangOpts().GPUExcludeWrongSideOverloads) { - const FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true); - bool ContainsSameSideCandidate = - llvm::any_of(Candidates, [&](OverloadCandidate *Cand) { - // Check viable function only. - return Cand->Viable && Cand->Function && - S.CUDA().IdentifyPreference(Caller, Cand->Function) == - SemaCUDA::CFP_SameSide; - }); - if (ContainsSameSideCandidate) { - auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) { - // Check viable function only to avoid unnecessary data copying/moving. - return Cand->Viable && Cand->Function && - S.CUDA().IdentifyPreference(Caller, Cand->Function) == - SemaCUDA::CFP_WrongSide; - }; - llvm::erase_if(Candidates, IsWrongSideCandidate); - } - } - Best = end(); for (auto *Cand : Candidates) { Cand->Best = false; @@ -11198,23 +11243,16 @@ OverloadingResult OverloadCandidateSet::BestViableFunctionImpl( } } } + if (Best == end()) return OR_Ambiguous; - // Best is the best viable function. - if (Best->Function && Best->Function->isDeleted()) - return OR_Deleted; + OverloadingResult R = ResultForBestCandidate(Best); - if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function); - Kind == CSK_AddressOfOverloadSet && M && - M->isImplicitObjectMemberFunction()) { - return OR_No_Viable_Function; - } - - if (NonDeducedCandidates.empty() && !EquivalentCands.empty()) + if (DeferredCandidates.empty() && !EquivalentCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); - return OR_Success; + return R; } namespace { @@ -14888,23 +14926,24 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, // rewritten candidates using these functions if necessary. AddNonMemberOperatorCandidates(Fns, Args, CandidateSet); - auto ReversedArgs = [&, Arr = ArrayRef<Expr *>{}]() mutable { - if (Arr.empty()) - Arr = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); - return Arr; - }; + // As template candidates are not deduced immediately, + // persist the arry in the overload set. + ArrayRef<Expr *> ReversedArgs; + if (CandidateSet.getRewriteInfo().allowsReversed(Op) || + CandidateSet.getRewriteInfo().allowsReversed(ExtraOp)) + ReversedArgs = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); // Add operator candidates that are member functions. AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); if (CandidateSet.getRewriteInfo().allowsReversed(Op)) - AddMemberOperatorCandidates(Op, OpLoc, ReversedArgs(), CandidateSet, + AddMemberOperatorCandidates(Op, OpLoc, ReversedArgs, CandidateSet, OverloadCandidateParamOrder::Reversed); // In C++20, also add any rewritten member candidates. if (ExtraOp) { AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet); if (CandidateSet.getRewriteInfo().allowsReversed(ExtraOp)) - AddMemberOperatorCandidates(ExtraOp, OpLoc, ReversedArgs(), CandidateSet, + AddMemberOperatorCandidates(ExtraOp, OpLoc, ReversedArgs, CandidateSet, OverloadCandidateParamOrder::Reversed); } diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp index ba8e2dc372e98..083e743818121 100644 --- a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp +++ b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp @@ -14,7 +14,7 @@ template<typename T> struct S { // expected-note@#FINST{{in instantiation of function template specialization}} template<typename T> requires (S<T>{}) void f(T); -void f(int); +void f(long); // Ensure this applies to operator && as well. // expected-error@+3{{atomic constraint must be of type 'bool' (found 'S<int>')}} @@ -22,7 +22,7 @@ void f(int); // expected-note@#F2INST{{in instantiation of function template specialization}} template<typename T> requires (S<T>{} && true) void f2(T); -void f2(int); +void f2(long); template<typename T> requires requires { requires S<T>{}; @@ -36,12 +36,12 @@ template<typename T> requires requires { // } void f3(T); -void f3(int); +void f3(long); // Doesn't diagnose, since this is no longer a compound requirement. template<typename T> requires (bool(1 && 2)) void f4(T); -void f4(int); +void f4(long); void g() { f(0); // #FINST diff --git a/clang/test/SemaCXX/implicit-member-functions.cpp b/clang/test/SemaCXX/implicit-member-functions.cpp index 1554b1af5d59a..8350eac5b88a0 100644 --- a/clang/test/SemaCXX/implicit-member-functions.cpp +++ b/clang/test/SemaCXX/implicit-member-functions.cpp @@ -54,31 +54,24 @@ namespace PR7594 { namespace Recursion { template<typename T> struct InvokeCopyConstructor { static const T &get(); - typedef decltype(T(get())) type; // expected-error {{no matching conver}} + typedef decltype(T(get())) type; }; struct B; struct A { - // expected-note@-1 {{while substituting deduced template arguments}} typedef B type; template<typename T, typename = typename InvokeCopyConstructor<typename T::type>::type> - // expected-note@-1 {{in instantiation of template class}} A(const T &); - // expected-note@-1 {{in instantiation of default argument}} }; - struct B { // expected-note {{while declaring the implicit copy constructor for 'B'}} - // expected-note@-1 {{candidate constructor (the implicit move }} - B(); // expected-note {{candidate constructor not viable}} + struct B { + B(); A a; }; // Triggering the declaration of B's copy constructor causes overload - // resolution to occur for A's copying constructor, which instantiates - // InvokeCopyConstructor<B>, which triggers the declaration of B's copy - // constructor. Notionally, this happens when we get to the end of the - // definition of 'struct B', so there is no declared copy constructor yet. - // - // This behavior is g++-compatible, but isn't exactly right; the class is - // supposed to be incomplete when we implicitly declare its special members. + // resolution to occur for A's copying constructor, which picks + // the implicit copy constructor of A. + // Because that copy constructor is always a perfect match the template + // candidate is not instantiated. B b = B(); diff --git a/clang/test/SemaTemplate/instantiate-function-params.cpp b/clang/test/SemaTemplate/instantiate-function-params.cpp index 7dd5595de58a3..eb2a7c5d4e8d6 100644 --- a/clang/test/SemaTemplate/instantiate-function-params.cpp +++ b/clang/test/SemaTemplate/instantiate-function-params.cpp @@ -6,13 +6,12 @@ template<typename T1> struct if_ { typedef if_c< static_cast<bool>(T1::value)> almost_type_; // expected-note 7{{in instantiation}} }; template <class Model, void (Model::*)()> struct wrap_constraints { }; -template <class Model> +template <class Model> inline char has_constraints_(Model* , // expected-note 3{{candidate template ignored}} - wrap_constraints<Model,&Model::constraints>* = 0); // expected-note 4{{in instantiation}} - + wrap_constraints<Model,&Model::constraints>* = 0); template <class Model> struct not_satisfied { static const bool value = sizeof( has_constraints_((Model*)0) == 1); // expected-error 3{{no matching function}} \ - // expected-note 4{{while substituting deduced template arguments into function template 'has_constraints_' [with }} + // expected-note 4{{in instantiation}} }; template <class ModelFn> struct requirement_; template <void(*)()> struct instantiate { diff --git a/clang/test/Templight/templight-empty-entries-fix.cpp b/clang/test/Templight/templight-empty-entries-fix.cpp index d13b748068efe..9f4590cec2333 100644 --- a/clang/test/Templight/templight-empty-entries-fix.cpp +++ b/clang/test/Templight/templight-empty-entries-fix.cpp @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -templight-dump -Wno-unused-value %s 2>&1 | FileCheck %s -void a() { +void a(long) { [] {}; } @@ -17,14 +17,14 @@ void a() { // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:4:3'$}} // CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:4:3'$}} -template <int = 0> void a() { a(); } +template <int = 0> void a(long) { a(0); } // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:31'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:35'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template non-type parameter 0 of a$}} // CHECK: {{^kind:[ ]+DefaultTemplateArgumentInstantiation$}} @@ -42,29 +42,29 @@ template <int = 0> void a() { a(); } // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:31'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:35'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'a<0>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:31'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:35'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'a<0>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:31'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:20:35'$}} template <int> struct b { typedef int c; }; -template <bool d = true, class = typename b<d>::c> void a() { a(); } +template <bool d = true, class = typename b<d>::c> void a(long) { a(0); } // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+DefaultTemplateArgumentInstantiation$}} @@ -130,25 +130,25 @@ template <bool d = true, class = typename b<d>::c> void a() { a(); } // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'a<true, int>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'a<true, int>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template non-type parameter 0 of a$}} // CHECK: {{^kind:[ ]+DefaultTemplateArgumentInstantiation$}} @@ -166,7 +166,7 @@ template <bool d = true, class = typename b<d>::c> void a() { a(); } // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} template <bool = true> void d(int = 0) { d(); } @@ -175,25 +175,25 @@ template <bool = true> void d(int = 0) { d(); } // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:60:57'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+a$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:20:25'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:63'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:60:67'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits