diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0891fd058bb57..b376f8851d129 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 `_. 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 differ 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 Args; + CallExpr::ADLCallKind IsADLCandidate; + OverloadCandidateParamOrder PO; + }; + static_assert(std::is_trivially_destructible_v< + DeferredFunctionTemplateOverloadCandidate>); + + struct DeferredMethodTemplateOverloadCandidate + : public DeferredTemplateOverloadCandidate { + FunctionTemplateDecl *FunctionTemplate; + DeclAccessPair FoundDecl; + ArrayRef 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 Candidates; llvm::SmallPtrSet 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 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::value || - std::is_same::value, + static_assert(std::is_trivially_destructible_v || + (std::is_same_v), "Add destruction logic to OverloadCandidateSet::clear()."); unsigned NBytes = sizeof(T) * N; @@ -1159,12 +1276,34 @@ class Sema; return reinterpret_cast(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 T *allocateDeferredCandidate() { + T *C = slabAllocate(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 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 getPersistentArgsArray(unsigned N) { + Expr **Exprs = slabAllocate(N); + return llvm::MutableArrayRef(Exprs, N); + } + + template + llvm::MutableArrayRef getPersistentArgsArray(T *...Exprs) { + llvm::MutableArrayRef Arr = + getPersistentArgsArray(sizeof...(Exprs)); + llvm::copy(std::initializer_list{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 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 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 &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 different + // 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 1e4e6fdc78351..ed10730ef986b 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -6354,7 +6354,8 @@ SemaCodeCompletion::ProduceCallSignatureHelp(Expr *Fn, ArrayRef 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(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(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 a1e4bb4321d53..ff439ca30d22b 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(Function) && + assert(Best->HasFinalConversion && !isa(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 TmpInits; - for (Expr *E : Inits) + + // As template candidates are not deduced immediately, + // persist the array in the overload set. + MutableArrayRef TmpInits = + Candidates.getPersistentArgsArray(Inits.size()); + + for (auto [I, E] : llvm::enumerate(Inits)) { if (auto *DI = dyn_cast(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(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 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 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(Specialization) && "Specialization is not a member function?"); - AddMethodCandidate(cast(Specialization), FoundDecl, - ActingContext, ObjectType, ObjectClassification, Args, - CandidateSet, SuppressUserConversions, PartialOverloading, - Conversions, PO, Info.hasStrictPackMatch()); + S.AddMethodCandidate( + cast(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 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 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 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 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(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 ParamTypes, ArrayRef 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(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(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 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 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(Cand1.Function) && isa(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 Args, bool SuppressUserConversions, + bool PartialOverloading, bool AllowExplicit, + CallExpr::ADLCallKind IsADLCandidate, OverloadCandidateParamOrder PO, + bool AggregateCandidateDeduction) { + + auto *C = + allocateDeferredCandidate(); + + C = new (C) DeferredFunctionTemplateOverloadCandidate{ + {nullptr, DeferredFunctionTemplateOverloadCandidate::Function, + /*AllowObjCConversionOnExplicit=*/false, + /*AllowResultConversion=*/false, AllowExplicit, SuppressUserConversions, + PartialOverloading, AggregateCandidateDeduction}, + FunctionTemplate, + FoundDecl, + Args, + IsADLCandidate, + PO}; + + HasDeferredTemplateConstructors |= + isa(FunctionTemplate->getTemplatedDecl()); +} + +void OverloadCandidateSet::AddDeferredMethodTemplateCandidate( + FunctionTemplateDecl *MethodTmpl, DeclAccessPair FoundDecl, + CXXRecordDecl *ActingContext, QualType ObjectType, + Expr::Classification ObjectClassification, ArrayRef Args, + bool SuppressUserConversions, bool PartialOverloading, + OverloadCandidateParamOrder PO) { + + assert(!isa(MethodTmpl->getTemplatedDecl())); + + auto *C = + allocateDeferredCandidate(); + + 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(); + + 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(Cand)); + break; + case DeferredTemplateOverloadCandidate::Method: + AddTemplateOverloadCandidate( + S, *this, + *static_cast(Cand)); + break; + case DeferredTemplateOverloadCandidate::Conversion: + AddTemplateOverloadCandidate( + S, *this, + *static_cast(Cand)); + break; + } + Cand = Cand->Next; + } + FirstDeferredCandidate = nullptr; + DeferredCandidatesCount = 0; +} + OverloadingResult -OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, - iterator &Best) { - llvm::SmallVector 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 &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(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 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 PendingBest; llvm::SmallVector EquivalentCands; - - llvm::SmallVector 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(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 OverloadCandidateSet::CompleteCandidates( Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef Args, SourceLocation OpLoc, llvm::function_ref 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 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(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 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(FD1)); + (isa(FD1))); assert(!FD2->isFunctionTemplateSpecialization() || - isa(FD2)); + (isa(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 struct S { // expected-note@#FINST{{in instantiation of function template specialization}} template requires (S{}) 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')}} @@ -22,7 +22,7 @@ void f(int); // expected-note@#F2INST{{in instantiation of function template specialization}} template requires (S{} && true) void f2(T); -void f2(int); +void f2(long); template requires requires { requires S{}; @@ -36,12 +36,12 @@ template requires requires { // } void f3(T); -void f3(int); +void f3(long); // Doesn't diagnose, since this is no longer a compound requirement. template 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 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::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, 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 +struct Invalid { static_assert(false, "instantiated Invalid"); }; // #err-invalid + +template +int f(T a, Invalid = {}); // #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' required here}} +//expected-note@#note-f {{in instantiation of template class 'Invalid' 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' required here}} +//expected-note@#note-f {{in instantiation of template class 'Invalid' requested here}} +//expected-note@#note-f {{passing argument to parameter here}} + +int f(long); +int ok3 = f(0L); + +template +struct Invalid2 { static_assert(false, "instantiated Invalid2"); }; // #err-qualifiers + +template +int ref(T a, Invalid2 = {}); // 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 +int f_alias(T a, Invalid = {}); +using Alias = int; +int f_alias(Alias); +int ok4 = f_alias(0); + +#if __cplusplus >= 202002 + +struct Copyable { + template + 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 + requires __is_constructible(ImplicitlyCopyable, T) + explicit ImplicitlyCopyable(T op) = delete; // #1 +}; +static_assert(__is_constructible(ImplicitlyCopyable, const ImplicitlyCopyable&)); + + +struct Movable { + template + 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 +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{}.f(0) == 2); +static_assert(Members{}.g(0) == 0); +// expected-error@#err-qualified-member {{static assertion failed: instantiated member}} \ +// expected-note@-1{{in instantiation of function template specialization 'Members::g' }} +Members m1; +static_assert(m1.g(0) == 1); +static_assert(Members{}.s(0) == 2); + + +namespace ConstructorInit{ +struct S { + template + S(T&&) {} +}; +struct Test { + operator S() = delete; +}; + +static_assert(__is_constructible(S, Test)); +} + +namespace RefBinding { + +template struct remove_reference; +template struct remove_reference<_Tp &> { + using type = _Tp; +}; +template remove_reference<_Tp>::type move(_Tp &&); +template struct _Head_base { + _Head_base(_Head &__h) : _M_head_impl(__h) {} + template _Head_base(_UHead &&); + _Head _M_head_impl; +}; + +template void forward_as_tuple(_Elements &&) { + _Head_base<_Elements &&>(_Elements{}); +} +struct StringRef { + void operator[](const StringRef __k) { forward_as_tuple((move)(__k)); } +}; + +} + +template struct tuple {}; +struct BonkersBananas { + template operator T(); + template explicit operator tuple() = delete; +}; +static_assert(!__is_constructible(tuple, BonkersBananas)); + +namespace GH62096 { +template +struct Oops { + static_assert(sizeof(T) == 0); // #GH62096-err + static constexpr bool value = true; +}; + +template +concept Operator = Oops::value; // #GH62096-note1 + +template 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 +struct t1 { +}; +struct t6 { + template + operator t1() { + return {}; + } +}; + +int main() { + t6 v6; + v6.operator t1(); +} 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 struct if_ { typedef if_c< static_cast(T1::value)> almost_type_; // expected-note 7{{in instantiation}} }; template struct wrap_constraints { }; -template +template inline char has_constraints_(Model* , // expected-note 3{{candidate template ignored}} - wrap_constraints* = 0); // expected-note 4{{in instantiation}} - + wrap_constraints* = 0); template 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 struct requirement_; template 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 void a() { a(); } +template 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 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 struct b { typedef int c; }; -template ::c> void a() { a(); } +template ::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 ::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'$}} // 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'$}} // 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 ::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 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 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'$}} // 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'$}} // 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'$}}