Author: cor3ntin Date: 2025-04-17T08:09:55+02:00 New Revision: 377ec36b323ea99ca316cb5cf79c0a0c93eebc37
URL: https://github.com/llvm/llvm-project/commit/377ec36b323ea99ca316cb5cf79c0a0c93eebc37 DIFF: https://github.com/llvm/llvm-project/commit/377ec36b323ea99ca316cb5cf79c0a0c93eebc37.diff LOG: [Clang] Bypass TAD during overload resolution if a perfect match exists (#136018) 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 https://github.com/llvm/llvm-project/pull/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 https://github.com/llvm/llvm-project/issues/62096 Fixes https://github.com/llvm/llvm-project/issues/74581 Reapplies #133426 Added: clang/test/SemaCXX/overload-resolution-deferred-templates.cpp Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Sema/Overload.h clang/lib/Sema/SemaCodeComplete.cpp clang/lib/Sema/SemaInit.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaTemplateDeduction.cpp clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp clang/test/SemaCUDA/function-overload.cu clang/test/SemaCXX/implicit-member-functions.cpp clang/test/SemaTemplate/instantiate-function-params.cpp clang/test/Templight/templight-empty-entries-fix.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0bf5e07ec5dfd..2bc7054e3c794 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -96,6 +96,12 @@ C++ Language Changes asm((std::string_view("nop")) ::: (std::string_view("memory"))); } +- Clang now implements the changes to overload resolution proposed by section 1 and 2 of + `P3606 <https://wg21.link/P3606R0>`_. If a non-template candidate exists in an overload set that is + a perfect match (all conversion sequences are identity conversions) template candidates are not instantiated. + Diagnostics that would have resulted from the instantiation of these template candidates are no longer + produced. This aligns Clang closer to the behavior of GCC, and fixes (#GH62096), (#GH74581), and (#GH74581). + C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 6e08762dcc6d7..e667147bfac7e 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -407,6 +407,26 @@ class Sema; Third == ICK_Identity; } + /// A conversion sequence is perfect if it is an identity conversion and + /// the type of the source is the same as the type of the target. + bool isPerfect(const ASTContext &C) const { + if (!isIdentityConversion()) + return false; + // If we are not performing a reference binding, we can skip comparing + // the types, which has a noticeable performance impact. + if (!ReferenceBinding) { + // The types might diff er if there is an array-to-pointer conversion + // or lvalue-to-rvalue conversion. + assert(First || C.hasSameUnqualifiedType(getFromType(), getToType(2))); + return true; + } + if (!C.hasSameType(getFromType(), getToType(2))) + return false; + if (BindsToRvalue && IsLvalueReference) + return false; + return true; + } + ImplicitConversionRank getRank() const; NarrowingKind getNarrowingKind(ASTContext &Context, const Expr *Converted, @@ -743,6 +763,12 @@ class Sema; Standard.setAllToTypes(T); } + /// A conversion sequence is perfect if it is an identity conversion and + /// the type of the source is the same as the type of the target. + bool isPerfect(const ASTContext &C) const { + return isStandard() && Standard.isPerfect(C); + } + // True iff this is a conversion sequence from an initializer list to an // array or std::initializer. bool hasInitializerListContainerType() const { @@ -939,6 +965,10 @@ class Sema; LLVM_PREFERRED_TYPE(CallExpr::ADLCallKind) unsigned IsADLCandidate : 1; + /// Whether FinalConversion has been set. + LLVM_PREFERRED_TYPE(bool) + unsigned HasFinalConversion : 1; + /// Whether this is a rewritten candidate, and if so, of what kind? LLVM_PREFERRED_TYPE(OverloadCandidateRewriteKind) unsigned RewriteKind : 2; @@ -979,6 +1009,20 @@ class Sema; return false; } + // An overload is a perfect match if the conversion + // sequences for each argument are perfect. + bool isPerfectMatch(const ASTContext &Ctx) const { + if (!Viable) + return false; + for (const auto &C : Conversions) { + if (!C.isInitialized() || !C.isPerfect(Ctx)) + return false; + } + if (HasFinalConversion) + return FinalConversion.isPerfect(Ctx); + return true; + } + bool TryToFixBadConversion(unsigned Idx, Sema &S) { bool CanFix = Fix.tryToFixConversion( Conversions[Idx].Bad.FromExpr, @@ -1012,8 +1056,67 @@ class Sema; : IsSurrogate(false), IgnoreObjectArgument(false), TookAddressOfOverload(false), StrictPackMatch(false), IsADLCandidate(llvm::to_underlying(CallExpr::NotADL)), - RewriteKind(CRK_None) {} + HasFinalConversion(false), RewriteKind(CRK_None) {} + }; + + struct DeferredTemplateOverloadCandidate { + + // intrusive linked list support for allocateDeferredCandidate + DeferredTemplateOverloadCandidate *Next = nullptr; + + enum Kind { Function, Method, Conversion }; + + LLVM_PREFERRED_TYPE(Kind) + unsigned Kind : 2; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowObjCConversionOnExplicit : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowResultConversion : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AllowExplicit : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned SuppressUserConversions : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned PartialOverloading : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned AggregateCandidateDeduction : 1; + }; + + struct DeferredFunctionTemplateOverloadCandidate + : public DeferredTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + ArrayRef<Expr *> Args; + CallExpr::ADLCallKind IsADLCandidate; + OverloadCandidateParamOrder PO; + }; + static_assert(std::is_trivially_destructible_v< + DeferredFunctionTemplateOverloadCandidate>); + + struct DeferredMethodTemplateOverloadCandidate + : public DeferredTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + ArrayRef<Expr *> Args; + CXXRecordDecl *ActingContext; + Expr::Classification ObjectClassification; + QualType ObjectType; + OverloadCandidateParamOrder PO; }; + static_assert(std::is_trivially_destructible_v< + DeferredMethodTemplateOverloadCandidate>); + + struct DeferredConversionTemplateOverloadCandidate + : public DeferredTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + CXXRecordDecl *ActingContext; + Expr *From; + QualType ToType; + }; + + static_assert(std::is_trivially_destructible_v< + DeferredConversionTemplateOverloadCandidate>); /// OverloadCandidateSet - A set of overload candidates, used in C++ /// overload resolution (C++ 13.3). @@ -1043,6 +1146,11 @@ class Sema; /// C++ [over.match.call.general] /// Resolve a call through the address of an overload set. CSK_AddressOfOverloadSet, + + /// When doing overload resolution during code completion, + /// we want to show all viable candidates, including otherwise + /// deferred template candidates. + CSK_CodeCompletion, }; /// Information about operator rewrites to consider when adding operator @@ -1117,7 +1225,15 @@ class Sema; SmallVector<OverloadCandidate, 16> Candidates; llvm::SmallPtrSet<uintptr_t, 16> Functions; - // Allocator for ConversionSequenceLists. We store the first few of these + DeferredTemplateOverloadCandidate *FirstDeferredCandidate = nullptr; + unsigned DeferredCandidatesCount : 8 * sizeof(unsigned) - 2; + LLVM_PREFERRED_TYPE(bool) + unsigned HasDeferredTemplateConstructors : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned ResolutionByPerfectCandidateIsDisabled : 1; + + // Allocator for ConversionSequenceLists and deferred candidate args. + // We store the first few of these // inline to avoid allocation for small sets. llvm::BumpPtrAllocator SlabAllocator; @@ -1125,8 +1241,11 @@ class Sema; CandidateSetKind Kind; OperatorRewriteInfo RewriteInfo; + /// Small storage size for ImplicitConversionSequences + /// and the persisted arguments of deferred candidates. constexpr static unsigned NumInlineBytes = - 24 * sizeof(ImplicitConversionSequence); + 32 * sizeof(ImplicitConversionSequence); + unsigned NumInlineBytesUsed = 0; alignas(void *) char InlineSpace[NumInlineBytes]; @@ -1137,15 +1256,13 @@ 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. 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; @@ -1159,12 +1276,34 @@ class Sema; return reinterpret_cast<T *>(FreeSpaceStart); } + // Because the size of OverloadCandidateSet has a noticeable impact on + // performance, we store each deferred template candidate in the slab + // allocator such that deferred candidates are ultimately a singly-linked + // intrusive linked list. This ends up being much more efficient than a + // SmallVector that is empty in the common case. + template <typename T> T *allocateDeferredCandidate() { + T *C = slabAllocate<T>(1); + if (!FirstDeferredCandidate) + FirstDeferredCandidate = C; + else { + auto *F = FirstDeferredCandidate; + while (F->Next) + F = F->Next; + F->Next = C; + } + DeferredCandidatesCount++; + return C; + } + void destroyCandidates(); public: OverloadCandidateSet(SourceLocation Loc, CandidateSetKind CSK, OperatorRewriteInfo RewriteInfo = {}) - : Loc(Loc), Kind(CSK), RewriteInfo(RewriteInfo) {} + : FirstDeferredCandidate(nullptr), DeferredCandidatesCount(0), + HasDeferredTemplateConstructors(false), + ResolutionByPerfectCandidateIsDisabled(false), Loc(Loc), Kind(CSK), + RewriteInfo(RewriteInfo) {} OverloadCandidateSet(const OverloadCandidateSet &) = delete; OverloadCandidateSet &operator=(const OverloadCandidateSet &) = delete; ~OverloadCandidateSet() { destroyCandidates(); } @@ -1176,6 +1315,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 deferred + bool shouldDeferTemplateArgumentDeduction(const LangOptions &Opts) const; + /// Determine when this overload candidate will be new to the /// overload set. bool isNewCandidate(Decl *F, OverloadCandidateParamOrder PO = @@ -1199,8 +1341,10 @@ 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() + DeferredCandidatesCount; } + bool empty() const { + return Candidates.empty() && DeferredCandidatesCount == 0; + } /// Allocate storage for conversion sequences for NumConversions /// conversions. @@ -1216,6 +1360,24 @@ class Sema; return ConversionSequenceList(Conversions, NumConversions); } + /// Provide storage for any Expr* arg that must be preserved + /// until deferred template candidates are deduced. + /// Typically this should be used for reversed operator arguments + /// and any time the argument array is transformed while adding + /// a template candidate. + 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,6 +1393,32 @@ class Sema; return C; } + void AddDeferredTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + ArrayRef<Expr *> Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction); + + void AddDeferredMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO); + + void AddDeferredConversionTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion); + + void InjectNonDeducedTemplateCandidates(Sema &S); + + void DisableResolutionByPerfectCandidate() { + ResolutionByPerfectCandidateIsDisabled = true; + } + /// Find the best viable function on this overload set, if it exists. OverloadingResult BestViableFunction(Sema &S, SourceLocation Loc, OverloadCandidateSet::iterator& Best); @@ -1263,6 +1451,15 @@ class Sema; DestAS = AS; } + private: + OverloadingResult ResultForBestCandidate(const iterator &Best); + void CudaExcludeWrongSideCandidates( + Sema &S, SmallVectorImpl<OverloadCandidate *> &Candidates); + 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, @@ -1311,6 +1508,21 @@ 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 diff erent + // combination of CV qualifiers and look at any explicit specifier, so + // always deduce template candidates. + Kind != CSK_InitByUserDefinedConversion + // When doing code completion, we want to see all the + // viable candidates. + && Kind != CSK_CodeCompletion + // CUDA may prefer template candidates even when a non-candidate + // is a perfect match + && !Opts.CUDA; + } + } // namespace clang #endif // LLVM_CLANG_SEMA_OVERLOAD_H diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index f6ec4cb0f069e..45405d4709e14 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -6354,7 +6354,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, @@ -6557,7 +6558,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 77d7f821f2011..9e802a175bb05 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -5231,7 +5231,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // Add the final conversion sequence, if necessary. if (NewRefRelationship == Sema::Ref_Incompatible) { - assert(!isa<CXXConstructorDecl>(Function) && + assert(Best->HasFinalConversion && !isa<CXXConstructorDecl>(Function) && "should not have conversion after constructor"); ImplicitConversionSequence ICS; @@ -6200,6 +6200,7 @@ static void TryUserDefinedConversion(Sema &S, // If the conversion following the call to the conversion function // is interesting, add it as a separate step. + assert(Best->HasFinalConversion); if (Best->FinalConversion.First || Best->FinalConversion.Second || Best->FinalConversion.Third) { ImplicitConversionSequence ICS; @@ -10029,12 +10030,19 @@ 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) + + // As template candidates are not deduced immediately, + // persist the array 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.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 55634aa75ae25..b7a981e08ead9 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -1123,6 +1123,10 @@ void OverloadCandidateSet::clear(CandidateSetKind CSK) { Candidates.clear(); Functions.clear(); Kind = CSK; + FirstDeferredCandidate = nullptr; + DeferredCandidatesCount = 0; + HasDeferredTemplateConstructors = false; + ResolutionByPerfectCandidateIsDisabled = false; } namespace { @@ -4075,6 +4079,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Best->Function)) { + + assert(Best->HasFinalConversion); + // C++ [over.ics.user]p1: // // [...] If the user-defined conversion is specified by a @@ -5158,6 +5165,9 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, OverloadCandidateSet::iterator Best; switch (CandidateSet.BestViableFunction(S, DeclLoc, Best)) { case OR_Success: + + assert(Best->HasFinalConversion); + // C++ [over.ics.ref]p1: // // [...] If the parameter binds directly to the result of @@ -7795,15 +7805,14 @@ 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; + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO) { // C++ [over.match.funcs]p7: // In each case where a candidate is a function template, candidate @@ -7817,12 +7826,12 @@ void Sema::AddMethodTemplateCandidate( 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); @@ -7844,8 +7853,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(S.Context, Result, Info); } return; } @@ -7855,10 +7864,34 @@ void Sema::AddMethodTemplateCandidate( 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()); +} + +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, OverloadCandidateParamOrder PO) { + if (!CandidateSet.isNewCandidate(MethodTmpl, PO)) + return; + + if (ExplicitTemplateArgs || + !CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts())) { + AddMethodTemplateCandidateImmediately( + *this, CandidateSet, MethodTmpl, FoundDecl, ActingContext, + ExplicitTemplateArgs, ObjectType, ObjectClassification, Args, + SuppressUserConversions, PartialOverloading, PO); + return; + } + + CandidateSet.AddDeferredMethodTemplateCandidate( + MethodTmpl, FoundDecl, ActingContext, ObjectType, ObjectClassification, + Args, SuppressUserConversions, PartialOverloading, PO); } /// Determine whether a given function template has a simple explicit specifier @@ -7867,14 +7900,18 @@ static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) { return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit(); } -void Sema::AddTemplateOverloadCandidate( +static bool hasDependentExplicit(FunctionTemplateDecl *FTD) { + return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).getKind() == + ExplicitSpecKind::Unresolved; +} + +static void AddTemplateOverloadCandidateImmediately( + Sema &S, OverloadCandidateSet &CandidateSet, 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; + 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 @@ -7901,14 +7938,14 @@ void Sema::AddTemplateOverloadCandidate( 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); }); @@ -7932,8 +7969,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(S.Context, Result, Info); } return; } @@ -7941,7 +7978,7 @@ void Sema::AddTemplateOverloadCandidate( // 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, @@ -7949,6 +7986,38 @@ void Sema::AddTemplateOverloadCandidate( 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; + + bool DependentExplicitSpecifier = hasDependentExplicit(FunctionTemplate); + + if (ExplicitTemplateArgs || + !CandidateSet.shouldDeferTemplateArgumentDeduction(getLangOpts()) || + (isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()) && + DependentExplicitSpecifier)) { + + AddTemplateOverloadCandidateImmediately( + *this, CandidateSet, FunctionTemplate, FoundDecl, ExplicitTemplateArgs, + Args, SuppressUserConversions, PartialOverloading, AllowExplicit, + IsADLCandidate, PO, AggregateCandidateDeduction); + + if (DependentExplicitSpecifier) + CandidateSet.DisableResolutionByPerfectCandidate(); + 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, @@ -8111,6 +8180,7 @@ void Sema::AddConversionCandidate( Candidate.FinalConversion.setAsIdentityConversion(); Candidate.FinalConversion.setFromType(ConvType); Candidate.FinalConversion.setAllToTypes(ToType); + Candidate.HasFinalConversion = true; Candidate.Viable = true; Candidate.ExplicitCallArguments = 1; Candidate.StrictPackMatch = StrictPackMatch; @@ -8215,6 +8285,7 @@ void Sema::AddConversionCandidate( switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: Candidate.FinalConversion = ICS.Standard; + Candidate.HasFinalConversion = true; // C++ [over.ics.user]p3: // If the user-defined conversion is specified by a specialization of a @@ -8264,16 +8335,12 @@ 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; + 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 @@ -8288,11 +8355,11 @@ void Sema::AddTemplateConversionCandidate( } 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) { @@ -8302,18 +8369,47 @@ void Sema::AddTemplateConversionCandidate( Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_deduction; Candidate.ExplicitCallArguments = 1; - Candidate.DeductionFailure = MakeDeductionFailureInfo(Context, Result, - Info); + Candidate.DeductionFailure = + 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, ActingDC, 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()) || + CandidateSet.getKind() == + OverloadCandidateSet::CSK_InitByUserDefinedConversion || + CandidateSet.getKind() == OverloadCandidateSet::CSK_InitByConstructor) { + AddTemplateConversionCandidateImmediately( + *this, CandidateSet, FunctionTemplate, FoundDecl, ActingDC, From, + ToType, AllowObjCConversionOnExplicit, AllowExplicit, + AllowResultConversion); + + CandidateSet.DisableResolutionByPerfectCandidate(); + return; + } + + CandidateSet.AddDeferredConversionTemplateCandidate( + FunctionTemplate, FoundDecl, ActingDC, From, ToType, + AllowObjCConversionOnExplicit, AllowExplicit, AllowResultConversion); } void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, @@ -8463,11 +8559,17 @@ 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)) { + + // As template candidates are not deduced immediately, + // persist the array 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, + OverloadCandidateParamOrder::Reversed); + } } else { if (ExplicitTemplateArgs) continue; @@ -10199,6 +10301,8 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // FIXME: Pass in the explicit template arguments? ArgumentDependentLookup(Name, Loc, Args, Fns); + ArrayRef<Expr *> ReversedArgs; + // Erase all of the candidates we already knew about. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), CandEnd = CandidateSet.end(); @@ -10238,9 +10342,15 @@ 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 array in the overload set. + if (ReversedArgs.empty()) + ReversedArgs = CandidateSet.getPersistentArgsArray(Args[1], Args[0]); + 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); } @@ -10654,6 +10764,8 @@ bool clang::isBetterOverloadCandidate( Cand1.Function && Cand2.Function && isa<CXXConversionDecl>(Cand1.Function) && isa<CXXConversionDecl>(Cand2.Function)) { + + assert(Cand1.HasFinalConversion && Cand2.HasFinalConversion); // First check whether we prefer one of the conversion functions over the // other. This only distinguishes the results in non-standard, extension // cases such as the conversion from a lambda closure type to a function @@ -10913,23 +11025,147 @@ bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { ->Satisfaction.ContainsErrors; } -/// Computes the best viable function (C++ 13.3.3) -/// within an overload candidate set. -/// -/// \param Loc The location of the function name (or operator symbol) for -/// which overload resolution occurs. -/// -/// \param Best If overload resolution was successful or found a deleted -/// function, \p Best points to the candidate function found. -/// -/// \returns The result of overload resolution. +void OverloadCandidateSet::AddDeferredTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + ArrayRef<Expr *> Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction) { + + auto *C = + allocateDeferredCandidate<DeferredFunctionTemplateOverloadCandidate>(); + + C = new (C) DeferredFunctionTemplateOverloadCandidate{ + {nullptr, DeferredFunctionTemplateOverloadCandidate::Function, + /*AllowObjCConversionOnExplicit=*/false, + /*AllowResultConversion=*/false, AllowExplicit, SuppressUserConversions, + PartialOverloading, AggregateCandidateDeduction}, + FunctionTemplate, + FoundDecl, + Args, + IsADLCandidate, + PO}; + + HasDeferredTemplateConstructors |= + isa<CXXConstructorDecl>(FunctionTemplate->getTemplatedDecl()); +} + +void OverloadCandidateSet::AddDeferredMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef<Expr *> Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO) { + + assert(!isa<CXXConstructorDecl>(MethodTmpl->getTemplatedDecl())); + + auto *C = + allocateDeferredCandidate<DeferredMethodTemplateOverloadCandidate>(); + + C = new (C) DeferredMethodTemplateOverloadCandidate{ + {nullptr, DeferredFunctionTemplateOverloadCandidate::Method, + /*AllowObjCConversionOnExplicit=*/false, + /*AllowResultConversion=*/false, + /*AllowExplicit=*/false, SuppressUserConversions, PartialOverloading, + /*AggregateCandidateDeduction=*/false}, + MethodTmpl, + FoundDecl, + Args, + ActingContext, + ObjectClassification, + ObjectType, + PO}; +} + +void OverloadCandidateSet::AddDeferredConversionTemplateCandidate( + FunctionTemplateDecl *FunctionTemplate, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, Expr *From, QualType ToType, + bool AllowObjCConversionOnExplicit, bool AllowExplicit, + bool AllowResultConversion) { + + auto *C = + allocateDeferredCandidate<DeferredConversionTemplateOverloadCandidate>(); + + C = new (C) DeferredConversionTemplateOverloadCandidate{ + {nullptr, DeferredFunctionTemplateOverloadCandidate::Conversion, + AllowObjCConversionOnExplicit, AllowResultConversion, + /*AllowExplicit=*/false, + /*SuppressUserConversions=*/false, + /*PartialOverloading*/ false, + /*AggregateCandidateDeduction=*/false}, + FunctionTemplate, + FoundDecl, + ActingContext, + From, + ToType}; +} + +static void +AddTemplateOverloadCandidate(Sema &S, OverloadCandidateSet &CandidateSet, + DeferredMethodTemplateOverloadCandidate &C) { + + 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, + 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, + 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() + DeferredCandidatesCount); + DeferredTemplateOverloadCandidate *Cand = FirstDeferredCandidate; + while (Cand) { + switch (Cand->Kind) { + case DeferredTemplateOverloadCandidate::Function: + AddTemplateOverloadCandidate( + S, *this, + *static_cast<DeferredFunctionTemplateOverloadCandidate *>(Cand)); + break; + case DeferredTemplateOverloadCandidate::Method: + AddTemplateOverloadCandidate( + S, *this, + *static_cast<DeferredMethodTemplateOverloadCandidate *>(Cand)); + break; + case DeferredTemplateOverloadCandidate::Conversion: + AddTemplateOverloadCandidate( + S, *this, + *static_cast<DeferredConversionTemplateOverloadCandidate *>(Cand)); + break; + } + Cand = Cand->Next; + } + FirstDeferredCandidate = nullptr; + DeferredCandidatesCount = 0; +} + OverloadingResult -OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best) { - llvm::SmallVector<OverloadCandidate *, 16> Candidates; - std::transform(begin(), end(), std::back_inserter(Candidates), - [](OverloadCandidate &Cand) { return &Cand; }); +OverloadCandidateSet::ResultForBestCandidate(const iterator &Best) { + Best->Best = true; + if (Best->Function && Best->Function->isDeleted()) + return OR_Deleted; + return OR_Success; +} +void OverloadCandidateSet::CudaExcludeWrongSideCandidates( + Sema &S, SmallVectorImpl<OverloadCandidate *> &Candidates) { // [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 @@ -10941,27 +11177,112 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // -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. + 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_WrongSide; - }; - llvm::erase_if(Candidates, IsWrongSideCandidate); + 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; + }; + llvm::erase_if(Candidates, IsWrongSideCandidate); +} + +/// Computes the best viable function (C++ 13.3.3) +/// within an overload candidate set. +/// +/// \param Loc The location of the function name (or operator symbol) for +/// which overload resolution occurs. +/// +/// \param Best If overload resolution was successful or found a deleted +/// function, \p Best points to the candidate function found. +/// +/// \returns The result of overload resolution. +OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, + SourceLocation Loc, + iterator &Best) { + + assert(shouldDeferTemplateArgumentDeduction(S.getLangOpts()) || + DeferredCandidatesCount == 0 && + "Unexpected deferred template candidates"); + + bool TwoPhaseResolution = + DeferredCandidatesCount != 0 && !ResolutionByPerfectCandidateIsDisabled; + + if (TwoPhaseResolution) { + + PerfectViableFunction(S, Loc, Best); + if (Best != end()) + return ResultForBestCandidate(Best); + } + + InjectNonDeducedTemplateCandidates(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())) + continue; + + // We found a suitable conversion function + // but if there is a template constructor in the target class + // we might prefer that instead. + if (HasDeferredTemplateConstructors && + isa_and_nonnull<CXXConversionDecl>(It->Function)) { + Best = end(); + break; } + + if (Best == end()) { + Best = It; + continue; + } + 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; + } + // ambiguous + Best = end(); + break; } +} + +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; }); + + if (S.getLangOpts().CUDA) + CudaExcludeWrongSideCandidates(S, Candidates); - // Find the best viable function. Best = end(); for (auto *Cand : Candidates) { Cand->Best = false; @@ -10983,9 +11304,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; @@ -11008,25 +11328,15 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, } } - // If we found more than one best candidate, this is ambiguous. if (Best == end()) return OR_Ambiguous; - // Best is the best viable function. - 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; - } + OverloadingResult R = ResultForBestCandidate(Best); if (!EquivalentCands.empty()) S.diagnoseEquivalentInternalLinkageDeclarations(Loc, Best->Function, EquivalentCands); - - return OR_Success; + return R; } namespace { @@ -12733,6 +13043,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; @@ -14354,10 +14667,12 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, Expr *ExecConfig, bool AllowTypoCorrection, bool CalleesAddressIsTaken) { - OverloadCandidateSet CandidateSet( - Fn->getExprLoc(), CalleesAddressIsTaken - ? OverloadCandidateSet::CSK_AddressOfOverloadSet - : OverloadCandidateSet::CSK_Normal); + + OverloadCandidateSet::CandidateSetKind CSK = + CalleesAddressIsTaken ? OverloadCandidateSet::CSK_AddressOfOverloadSet + : OverloadCandidateSet::CSK_Normal; + + OverloadCandidateSet CandidateSet(Fn->getExprLoc(), CSK); ExprResult result; if (buildOverloadedCallSet(S, Fn, ULE, Args, LParenLoc, &CandidateSet, @@ -14373,6 +14688,17 @@ ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, OverloadingResult OverloadResult = CandidateSet.BestViableFunction(*this, Fn->getBeginLoc(), Best); + // [C++23][over.call.func] + // if overload resolution selects a non-static member function, + // the call is ill-formed; + if (CSK == OverloadCandidateSet::CSK_AddressOfOverloadSet && + Best != CandidateSet.end()) { + if (auto *M = dyn_cast_or_null<CXXMethodDecl>(Best->Function); + M && M->isImplicitObjectMemberFunction()) { + OverloadResult = OR_No_Viable_Function; + } + } + // Model the case with a call to a templated function whose definition // encloses the call and whose return type contains a placeholder type as if // the UnresolvedLookupExpr was type-dependent. @@ -14708,18 +15034,24 @@ void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, // rewritten candidates using these functions if necessary. AddNonMemberOperatorCandidates(Fns, Args, CandidateSet); + // As template candidates are not deduced immediately, + // persist the array 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, {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); } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 772962ac653f7..0ecdbb3ffb89f 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -6142,9 +6142,9 @@ FunctionDecl *Sema::getMoreConstrainedFunction(FunctionDecl *FD1, assert(!FD1->getDescribedTemplate() && !FD2->getDescribedTemplate() && "not for function templates"); assert(!FD1->isFunctionTemplateSpecialization() || - isa<CXXConversionDecl>(FD1)); + (isa<CXXConversionDecl, CXXConstructorDecl>(FD1))); assert(!FD2->isFunctionTemplateSpecialization() || - isa<CXXConversionDecl>(FD2)); + (isa<CXXConversionDecl, CXXConstructorDecl>(FD2))); FunctionDecl *F1 = FD1; if (FunctionDecl *P = FD1->getTemplateInstantiationPattern(false)) 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/SemaCUDA/function-overload.cu b/clang/test/SemaCUDA/function-overload.cu index 4710c81763adf..3d05839af7528 100644 --- a/clang/test/SemaCUDA/function-overload.cu +++ b/clang/test/SemaCUDA/function-overload.cu @@ -1,6 +1,3 @@ -// REQUIRES: x86-registered-target -// REQUIRES: nvptx-registered-target - // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-linux-gnu -fsyntax-only \ // RUN: -verify=host,hostdefer,devdefer,expected %s // RUN: %clang_cc1 -std=c++14 -triple nvptx64-nvidia-cuda -fsyntax-only \ 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/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp new file mode 100644 index 0000000000000..9139fd2688790 --- /dev/null +++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp @@ -0,0 +1,200 @@ +// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -fsyntax-only -verify -std=c++20 %s +// RUN: %clang_cc1 -triple=x86_64-unknown-unknown -fsyntax-only -verify -std=c++2c %s + +template <typename T> +struct Invalid { static_assert(false, "instantiated Invalid"); }; // #err-invalid + +template <typename T> +int f(T a, Invalid<T> = {}); // #note-f + +// sanity check +int e1 = f(0); +//expected-error@#err-invalid {{static assertion failed: instantiated Invalid}} +//expected-note@-2 {{in instantiation of default function argument expression for 'f<int>' required here}} +//expected-note@#note-f {{in instantiation of template class 'Invalid<int>' requested here}} +//expected-note@#note-f {{passing argument to parameter here}} + +int f(int); +int ok1 = f(0); +int e4 = f((const int&)(ok1)); + +int f(int, int = 0); +int ok2 = f(0, 0); + +int e2 = f(0L); +//expected-error@#err-invalid {{static assertion failed: instantiated Invalid}} +//expected-note@-2 {{in instantiation of default function argument expression for 'f<long>' required here}} +//expected-note@#note-f {{in instantiation of template class 'Invalid<long>' requested here}} +//expected-note@#note-f {{passing argument to parameter here}} + +int f(long); +int ok3 = f(0L); + +template <typename T> +struct Invalid2 { static_assert(false, "instantiated Invalid2"); }; // #err-qualifiers + +template <typename T> +int ref(T a, Invalid2<T> = {}); // expected-note 2{{here}} +int ref(int&); +int ref1 = ref(ok3); +int ref2 = ref((const int&)ok3); // expected-note {{here}} +//expected-error@#err-qualifiers {{static assertion failed: instantiated Invalid2}} + + +template <typename T> +int f_alias(T a, Invalid<T> = {}); +using Alias = int; +int f_alias(Alias); +int ok4 = f_alias(0); + +#if __cplusplus >= 202002 + +struct Copyable { + template <typename T> + requires __is_constructible(Copyable, T) + explicit Copyable(T op) noexcept; // #1 + Copyable(const Copyable&) noexcept = default; // #2 +}; +static_assert(__is_constructible(Copyable, const Copyable&)); + +struct ImplicitlyCopyable { + template <typename T> + requires __is_constructible(ImplicitlyCopyable, T) + explicit ImplicitlyCopyable(T op) = delete; // #1 +}; +static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&)); + + +struct Movable { + template <typename T> + requires __is_constructible(Movable, T) // #err-self-constraint-1 + explicit Movable(T op) noexcept; // #1 + Movable(Movable&&) noexcept = default; // #2 +}; +static_assert(__is_constructible(Movable, Movable&&)); +static_assert(__is_constructible(Movable, const Movable&)); +// expected-error@-1 {{static assertion failed due to requirement '__is_constructible(Movable, const Movable &)'}} + +static_assert(__is_constructible(Movable, int)); +// expected-error@-1{{static assertion failed due to requirement '__is_constructible(Movable, int)'}} \ +// expected-note@-1 2{{}} +// expected-error@#err-self-constraint-1{{satisfaction of constraint '__is_constructible(Movable, T)' depends on itself}} +// expected-note@#err-self-constraint-1 4{{}} + +template <typename T> +struct Members { + constexpr auto f(auto) { + static_assert(false, ""); + } + constexpr auto f(int) { return 1; } + constexpr auto f(int) requires true { return 2; } + + constexpr auto g(auto) { + static_assert(false, "instantiated member"); //#err-qualified-member + return 0; + } + constexpr auto g(int) & { return 1; } + + static constexpr auto s(auto) { + static_assert(false, ""); + } + static constexpr auto s(int) { + return 1; + } + static constexpr auto s(int) requires true { + return 2; + } +}; + +static_assert(Members<int[1]>{}.f(0) == 2); +static_assert(Members<int[2]>{}.g(0) == 0); +// expected-error@#err-qualified-member {{static assertion failed: instantiated member}} \ +// expected-note@-1{{in instantiation of function template specialization 'Members<int[2]>::g<int>' }} +Members<int[3]> m1; +static_assert(m1.g(0) == 1); +static_assert(Members<int[3]>{}.s(0) == 2); + + +namespace ConstructorInit{ +struct S { + template <typename T> + S(T&&) {} +}; +struct Test { + operator S() = delete; +}; + +static_assert(__is_constructible(S, Test)); +} + +namespace RefBinding { + +template <typename> struct remove_reference; +template <typename _Tp> struct remove_reference<_Tp &> { + using type = _Tp; +}; +template <typename _Tp> remove_reference<_Tp>::type move(_Tp &&); +template <typename _Head> struct _Head_base { + _Head_base(_Head &__h) : _M_head_impl(__h) {} + template <typename _UHead> _Head_base(_UHead &&); + _Head _M_head_impl; +}; + +template <typename _Elements> void forward_as_tuple(_Elements &&) { + _Head_base<_Elements &&>(_Elements{}); +} +struct StringRef { + void operator[](const StringRef __k) { forward_as_tuple((move)(__k)); } +}; + +} + +template <class> struct tuple {}; +struct BonkersBananas { + template <class T> operator T(); + template <class = void> explicit operator tuple<int>() = delete; +}; +static_assert(!__is_constructible(tuple<int>, BonkersBananas)); + +namespace GH62096 { +template <typename T> +struct Oops { + static_assert(sizeof(T) == 0); // #GH62096-err + static constexpr bool value = true; +}; + +template <class OPERATOR> +concept Operator = Oops<OPERATOR>::value; // #GH62096-note1 + +template <Operator OP> void f(OP op); // // #GH62096-note2 +void f(int); + +void g(int n) { f(n); } // OK +void h(short n) { f(n); } +// expected-error@#GH62096-err {{static assertion failed due to requirement 'sizeof(short) == 0'}} \ +// expected-note@-1{{in instantiation of function template specialization}} \ +// expected-note@-1{{while checking constraint satisfaction for template}} +// expected-note@#GH62096-note1{{in instantiation}} +// expected-note@#GH62096-note1{{while substituting template arguments into constraint expression here}} +// expected-note@#GH62096-note2{{while substituting template arguments into constraint expression here}} +// expected-note@#GH62096-note2{{while checking the satisfaction of concept}} +// expected-note@#GH62096-err {{expression evaluates}} +} + +#endif + +template<typename ...Ts> +struct t1 { +}; +struct t6 { + template<typename T = int> + operator t1<float>() { + return {}; + } +}; + +int main() { + t6 v6; + v6.operator t1<float>(); +} 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..7f34b10134929 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,34 +166,10 @@ 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(); } -// 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-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-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-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-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} @@ -249,41 +225,41 @@ void e() { } // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}} // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}} // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}} // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:248:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:224:5'$}} // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} // CHECK-LABEL: {{^---$}} -// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:247:3\)'$}} +// CHECK: {{^name:[ ]+'\(unnamed struct at .*templight-empty-entries-fix.cpp:223:3\)'$}} // CHECK: {{^kind:[ ]+Memoization$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:247:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:223:3'$}} template <template<typename> class> @@ -299,71 +275,71 @@ void foo() { // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}} // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}} // CHECK: {{^poi:[ ]+''$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}} // CHECK: {{^kind:[ ]+PriorTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}} // CHECK: {{^poi:[ ]+''$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}} // CHECK: {{^kind:[ ]+PartialOrderingTTP$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+unnamed template template parameter 0 of d$}} // CHECK: {{^kind:[ ]+PartialOrderingTTP$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:289:35'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:5'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:265:35'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:5'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+DeducedTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'d<C>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+Begin$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+'d<C>'$}} // CHECK: {{^kind:[ ]+TemplateInstantiation$}} // CHECK: {{^event:[ ]+End$}} -// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:290:6'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:266:6'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+Begin$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} // CHECK-LABEL: {{^---$}} // CHECK: {{^name:[ ]+d$}} // CHECK: {{^kind:[ ]+ExplicitTemplateArgumentSubstitution$}} // CHECK: {{^event:[ ]+End$}} // CHECK: {{^orig:[ ]+'.*templight-empty-entries-fix.cpp:171:29'$}} -// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:295:3'$}} +// CHECK: {{^poi:[ ]+'.*templight-empty-entries-fix.cpp:271:3'$}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits