Loading clang/include/clang/Sema/Overload.h +2 −0 Original line number Diff line number Diff line Loading @@ -850,6 +850,8 @@ class Sema; return static_cast<OverloadCandidateRewriteKind>(RewriteKind); } bool isReversed() const { return getRewriteKind() & CRK_Reversed; } /// hasAmbiguousConversion - Returns whether this overload /// candidate requires an ambiguous conversion or not. bool hasAmbiguousConversion() const { Loading clang/include/clang/Sema/Sema.h +4 −6 Original line number Diff line number Diff line Loading @@ -7964,12 +7964,10 @@ public: SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); FunctionTemplateDecl *getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2, bool Reversed = false); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, Loading clang/lib/Sema/SemaOverload.cpp +12 −13 Original line number Diff line number Diff line Loading @@ -8392,7 +8392,7 @@ public: // We interpret "same parameter-type-list" as applying to the // "synthesized candidate, with the order of the two parameters // reversed", not to the original function. bool Reversed = C->RewriteKind & CRK_Reversed; bool Reversed = C->isReversed(); QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0) ->getType() .getUnqualifiedType(); Loading Loading @@ -9478,7 +9478,7 @@ bool clang::isBetterOverloadCandidate( case ImplicitConversionSequence::Worse: if (Cand1.Function && Cand1.Function == Cand2.Function && (Cand2.RewriteKind & CRK_Reversed) != 0) { Cand2.isReversed()) { // Work around large-scale breakage caused by considering reversed // forms of operator== in C++20: // Loading Loading @@ -9566,14 +9566,13 @@ bool clang::isBetterOverloadCandidate( // according to the partial ordering rules described in 14.5.5.2, or, // if not that, if (Cand1IsSpecialization && Cand2IsSpecialization) { if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate( Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion : TPOC_Call, Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments)) Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments, Cand1.isReversed() ^ Cand2.isReversed())) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } Loading Loading @@ -11298,7 +11297,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, unsigned ConvIdx = 0; unsigned ArgIdx = 0; ArrayRef<QualType> ParamTypes; bool Reversed = Cand->RewriteKind & CRK_Reversed; bool Reversed = Cand->isReversed(); if (Cand->IsSurrogate) { QualType ConvType Loading Loading @@ -13232,7 +13231,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; bool IsReversed = (Best->RewriteKind & CRK_Reversed); bool IsReversed = Best->isReversed(); if (IsReversed) std::swap(Args[0], Args[1]); Loading Loading @@ -13264,7 +13263,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // formally ambiguous, and allowing it is an extension. for (OverloadCandidate &Cand : CandidateSet) { if (Cand.Viable && Cand.Function == FnDecl && Cand.RewriteKind & CRK_Reversed) { Cand.isReversed()) { for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { if (CompareImplicitConversionSequences( *this, OpLoc, Cand.Conversions[ArgIdx], clang/lib/Sema/SemaTemplateDeduction.cpp +20 −4 Original line number Diff line number Diff line Loading @@ -4847,7 +4847,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1) { unsigned NumCallArguments1, bool Reversed) { assert(!Reversed || TPOC == TPOC_Call); FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); Loading Loading @@ -4896,6 +4899,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, } else if (!Method1 && Method2 && !Method2->isStatic()) { // Compare 'this' from Method2 against first parameter from Method1. AddImplicitObjectParameterType(S.Context, Method2, Args2); } else if (Method1 && Method2 && Reversed) { // Compare 'this' from Method1 against second parameter from Method2 // and 'this' from Method2 against second parameter from Method1. AddImplicitObjectParameterType(S.Context, Method1, Args1); AddImplicitObjectParameterType(S.Context, Method2, Args2); ++NumComparedArguments; } Args1.insert(Args1.end(), Proto1->param_type_begin(), Loading @@ -4910,6 +4919,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.resize(NumComparedArguments); if (Args2.size() > NumComparedArguments) Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) Loading Loading @@ -5028,6 +5039,10 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { /// \param NumCallArguments2 The number of arguments in the call to FT2, used /// only when \c TPOC is \c TPOC_Call. /// /// \param Reversed If \c true, exactly one of FT1 and FT2 is an overload /// candidate with a reversed parameter order. In this case, the corresponding /// P/A pairs between FT1 and FT2 are reversed. /// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl * Loading @@ -5036,7 +5051,8 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2) { unsigned NumCallArguments2, bool Reversed) { auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * { llvm::SmallVector<const Expr *, 3> AC1, AC2; Loading @@ -5053,9 +5069,9 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, }; bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1); NumCallArguments1, Reversed); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, NumCallArguments2); NumCallArguments2, Reversed); if (Better1 != Better2) // We have a clear winner return Better1 ? FT1 : FT2; Loading clang/test/SemaTemplate/operator-template.cpp +10 −1 Original line number Diff line number Diff line // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s // Make sure we accept this template<class X>struct A{typedef X Y;}; Loading @@ -15,3 +15,12 @@ template<class X>bool operator==(B<X>*,typename B<X>::Y); // \ // expected-note{{candidate template ignored: substitution failure [with X = int]}} int a(B<int> x) { return operator==(&x,1); } // expected-error{{no matching function for call to 'operator=='}} \ // expected-note{{in instantiation of function template specialization}} // Ensure we take parameter list reversal into account in partial oredring. namespace CompareOrdering { template<typename T> struct A {}; template<typename T> int operator<=>(A<T>, int) = delete; template<typename T> int operator<=>(int, A<T*>); // OK, selects the more-specialized reversed function. bool b = A<int*>() < 0; } Loading
clang/include/clang/Sema/Overload.h +2 −0 Original line number Diff line number Diff line Loading @@ -850,6 +850,8 @@ class Sema; return static_cast<OverloadCandidateRewriteKind>(RewriteKind); } bool isReversed() const { return getRewriteKind() & CRK_Reversed; } /// hasAmbiguousConversion - Returns whether this overload /// candidate requires an ambiguous conversion or not. bool hasAmbiguousConversion() const { Loading
clang/include/clang/Sema/Sema.h +4 −6 Original line number Diff line number Diff line Loading @@ -7964,12 +7964,10 @@ public: SourceLocation ReturnLoc, Expr *&RetExpr, AutoType *AT); FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2); FunctionTemplateDecl *getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2, bool Reversed = false); UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, Loading
clang/lib/Sema/SemaOverload.cpp +12 −13 Original line number Diff line number Diff line Loading @@ -8392,7 +8392,7 @@ public: // We interpret "same parameter-type-list" as applying to the // "synthesized candidate, with the order of the two parameters // reversed", not to the original function. bool Reversed = C->RewriteKind & CRK_Reversed; bool Reversed = C->isReversed(); QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0) ->getType() .getUnqualifiedType(); Loading Loading @@ -9478,7 +9478,7 @@ bool clang::isBetterOverloadCandidate( case ImplicitConversionSequence::Worse: if (Cand1.Function && Cand1.Function == Cand2.Function && (Cand2.RewriteKind & CRK_Reversed) != 0) { Cand2.isReversed()) { // Work around large-scale breakage caused by considering reversed // forms of operator== in C++20: // Loading Loading @@ -9566,14 +9566,13 @@ bool clang::isBetterOverloadCandidate( // according to the partial ordering rules described in 14.5.5.2, or, // if not that, if (Cand1IsSpecialization && Cand2IsSpecialization) { if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate( Cand1.Function->getPrimaryTemplate(), Cand2.Function->getPrimaryTemplate(), Loc, isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion : TPOC_Call, Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments)) Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments, Cand1.isReversed() ^ Cand2.isReversed())) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } Loading Loading @@ -11298,7 +11297,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, unsigned ConvIdx = 0; unsigned ArgIdx = 0; ArrayRef<QualType> ParamTypes; bool Reversed = Cand->RewriteKind & CRK_Reversed; bool Reversed = Cand->isReversed(); if (Cand->IsSurrogate) { QualType ConvType Loading Loading @@ -13232,7 +13231,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; bool IsReversed = (Best->RewriteKind & CRK_Reversed); bool IsReversed = Best->isReversed(); if (IsReversed) std::swap(Args[0], Args[1]); Loading Loading @@ -13264,7 +13263,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // formally ambiguous, and allowing it is an extension. for (OverloadCandidate &Cand : CandidateSet) { if (Cand.Viable && Cand.Function == FnDecl && Cand.RewriteKind & CRK_Reversed) { Cand.isReversed()) { for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { if (CompareImplicitConversionSequences( *this, OpLoc, Cand.Conversions[ArgIdx],
clang/lib/Sema/SemaTemplateDeduction.cpp +20 −4 Original line number Diff line number Diff line Loading @@ -4847,7 +4847,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1) { unsigned NumCallArguments1, bool Reversed) { assert(!Reversed || TPOC == TPOC_Call); FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); Loading Loading @@ -4896,6 +4899,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, } else if (!Method1 && Method2 && !Method2->isStatic()) { // Compare 'this' from Method2 against first parameter from Method1. AddImplicitObjectParameterType(S.Context, Method2, Args2); } else if (Method1 && Method2 && Reversed) { // Compare 'this' from Method1 against second parameter from Method2 // and 'this' from Method2 against second parameter from Method1. AddImplicitObjectParameterType(S.Context, Method1, Args1); AddImplicitObjectParameterType(S.Context, Method2, Args2); ++NumComparedArguments; } Args1.insert(Args1.end(), Proto1->param_type_begin(), Loading @@ -4910,6 +4919,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.resize(NumComparedArguments); if (Args2.size() > NumComparedArguments) Args2.resize(NumComparedArguments); if (Reversed) std::reverse(Args2.begin(), Args2.end()); if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) Loading Loading @@ -5028,6 +5039,10 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { /// \param NumCallArguments2 The number of arguments in the call to FT2, used /// only when \c TPOC is \c TPOC_Call. /// /// \param Reversed If \c true, exactly one of FT1 and FT2 is an overload /// candidate with a reversed parameter order. In this case, the corresponding /// P/A pairs between FT1 and FT2 are reversed. /// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl * Loading @@ -5036,7 +5051,8 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2) { unsigned NumCallArguments2, bool Reversed) { auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * { llvm::SmallVector<const Expr *, 3> AC1, AC2; Loading @@ -5053,9 +5069,9 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, }; bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1); NumCallArguments1, Reversed); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, NumCallArguments2); NumCallArguments2, Reversed); if (Better1 != Better2) // We have a clear winner return Better1 ? FT1 : FT2; Loading
clang/test/SemaTemplate/operator-template.cpp +10 −1 Original line number Diff line number Diff line // RUN: %clang_cc1 -fsyntax-only -verify %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s // Make sure we accept this template<class X>struct A{typedef X Y;}; Loading @@ -15,3 +15,12 @@ template<class X>bool operator==(B<X>*,typename B<X>::Y); // \ // expected-note{{candidate template ignored: substitution failure [with X = int]}} int a(B<int> x) { return operator==(&x,1); } // expected-error{{no matching function for call to 'operator=='}} \ // expected-note{{in instantiation of function template specialization}} // Ensure we take parameter list reversal into account in partial oredring. namespace CompareOrdering { template<typename T> struct A {}; template<typename T> int operator<=>(A<T>, int) = delete; template<typename T> int operator<=>(int, A<T*>); // OK, selects the more-specialized reversed function. bool b = A<int*>() < 0; }