https://github.com/HoBoIs updated https://github.com/llvm/llvm-project/pull/83279
From 9ec2e0184be423223f6e5b5ba58c3a7224ae1b93 Mon Sep 17 00:00:00 2001 From: Botond Istvan Horvath <horvath.botond.ist...@gmail.com> Date: Wed, 28 Feb 2024 13:09:15 +0100 Subject: [PATCH 1/2] Bugfix for choosing the more specialized overload There was a bug in clang where it couldn't choose which overload candidate is more specialized if it was comparing a member-function to a non-member function. Previously, this was detected as an ambigouity, now clang chooses correctly. This patch fixes the bug by fully implementing CWG2445 and moving the template transformation described in [temp.func.order] paragraph 3 from isAtLeastAsSpecializedAs to Sema::getMoreSpecializedTemplate so we have the transformed parameter list during the whole comperrassion. Also, to be able to add the correct type for the implicit object parameter Sema::getMoreSpecializedTemplate has new parameters for the object type. --- clang/docs/ReleaseNotes.rst | 6 + clang/include/clang/Sema/Sema.h | 3 +- clang/lib/Sema/SemaOverload.cpp | 13 +- clang/lib/Sema/SemaTemplateDeduction.cpp | 237 +++++++++++---------- clang/test/CXX/drs/dr24xx.cpp | 61 ++++++ clang/test/SemaCXX/overload-template.cpp | 25 +++ clang/test/SemaCXX/overloaded-operator.cpp | 37 ++++ clang/www/cxx_dr_status.html | 2 +- 8 files changed, 273 insertions(+), 111 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0ff4a93b15ea8f..942820a5268576 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -319,6 +319,12 @@ Bug Fixes to C++ Support Fixes (#GH80630) - Fix a crash when an explicit template argument list is used with a name for which lookup finds a non-template function and a dependent using declarator. +- Fix a bug where overload resolution falsely reported an ambiguity when it was comparing + a member-function against a non member function or a member-function with an + explicit object parameter against a member function with no explicit object parameter + when one of the function had more specialized templates. + Fixes (`#82509 <https://github.com/llvm/llvm-project/issues/82509>`_) + and (`#74494 <https://github.com/llvm/llvm-project/issues/74494>`_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f3d3a57104ee07..2d949f3fc9a718 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9952,7 +9952,8 @@ class Sema final { FunctionTemplateDecl *getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, - unsigned NumCallArguments2, bool Reversed = false); + QualType RawObj1Ty = {}, QualType RawObj2Ty = {}, bool Reversed = false); + UnresolvedSetIterator getMostSpecialized(UnresolvedSetIterator SBegin, UnresolvedSetIterator SEnd, TemplateSpecCandidateSet &FailedCandidates, diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index a03f3eae5478eb..b0c693f078efe2 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10571,14 +10571,23 @@ bool clang::isBetterOverloadCandidate( // according to the partial ordering rules described in 14.5.5.2, or, // if not that, if (Cand1IsSpecialization && Cand2IsSpecialization) { + const auto *Obj1Context = + dyn_cast<CXXRecordDecl>(Cand1.FoundDecl->getDeclContext()); + const auto *Obj2Context = + dyn_cast<CXXRecordDecl>(Cand2.FoundDecl->getDeclContext()); 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.isReversed() ^ Cand2.isReversed())) + Cand1.ExplicitCallArguments, + Obj1Context ? QualType(Obj1Context->getTypeForDecl(), 0) + : QualType{}, + Obj2Context ? QualType(Obj2Context->getTypeForDecl(), 0) + : QualType{}, + Cand1.isReversed() ^ Cand2.isReversed())) { return BetterTemplate == Cand1.Function->getPrimaryTemplate(); + } } // -— F1 and F2 are non-template functions with the same diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 563491f76f5478..f14861640f549a 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5333,38 +5333,37 @@ bool Sema::CheckIfFunctionSpecializationIsImmediate(FunctionDecl *FD, return false; } -/// If this is a non-static member function, -static void -AddImplicitObjectParameterType(ASTContext &Context, - CXXMethodDecl *Method, - SmallVectorImpl<QualType> &ArgTypes) { - // C++11 [temp.func.order]p3: - // [...] The new parameter is of type "reference to cv A," where cv are - // the cv-qualifiers of the function template (if any) and A is - // the class of which the function template is a member. - // - // The standard doesn't say explicitly, but we pick the appropriate kind of - // reference type based on [over.match.funcs]p4. - assert(Method && Method->isImplicitObjectMemberFunction() && - "expected an implicit objet function"); - QualType ArgTy = Context.getTypeDeclType(Method->getParent()); - ArgTy = Context.getQualifiedType(ArgTy, Method->getMethodQualifiers()); - if (Method->getRefQualifier() == RQ_RValue) - ArgTy = Context.getRValueReferenceType(ArgTy); - else - ArgTy = Context.getLValueReferenceType(ArgTy); - ArgTypes.push_back(ArgTy); +static QualType GetImplicitObjectParameterType(ASTContext &Context, + const CXXMethodDecl *Method, + QualType RawType, + bool IsOtherRvr) { + // C++20 [temp.func.order]p3.1, p3.2: + //- The type X(M ) is “rvalue reference to cv A” if the optional ref-qualifier + // of M is && or if M has no ref-qualifier and the positionally-corresponding + // parameter of the other transformed template has rvalue reference type; + // if this determination depends recursively upon whether X(M ) is an rvalue + // reference type, it is not considered to have rvalue reference type. + //- Otherwise, X(M ) is “lvalue reference to cv A”. + + assert(Method && !Method->isExplicitObjectMemberFunction() && + "expected a member function with no explicit object parameter"); + + RawType = Context.getQualifiedType(RawType, Method->getMethodQualifiers()); + if (Method->getRefQualifier() == RQ_RValue || + (IsOtherRvr && Method->getRefQualifier() == RQ_None)) + return Context.getRValueReferenceType(RawType); + return Context.getLValueReferenceType(RawType); } /// Determine whether the function template \p FT1 is at least as /// specialized as \p FT2. -static bool isAtLeastAsSpecializedAs(Sema &S, - SourceLocation Loc, - FunctionTemplateDecl *FT1, - FunctionTemplateDecl *FT2, +static bool isAtLeastAsSpecializedAs(Sema &S, SourceLocation Loc, + const FunctionTemplateDecl *FT1, + const FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, - unsigned NumCallArguments1, - bool Reversed) { + bool Reversed, + const SmallVector<QualType> &Args1, + const SmallVector<QualType> &Args2) { assert(!Reversed || TPOC == TPOC_Call); FunctionDecl *FD1 = FT1->getTemplatedDecl(); @@ -5381,66 +5380,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // The types used to determine the ordering depend on the context in which // the partial ordering is done: TemplateDeductionInfo Info(Loc); - SmallVector<QualType, 4> Args2; switch (TPOC) { - case TPOC_Call: { - // - In the context of a function call, the function parameter types are - // used. - CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1); - CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2); - - // C++11 [temp.func.order]p3: - // [...] If only one of the function templates is a non-static - // member, that function template is considered to have a new - // first parameter inserted in its function parameter list. The - // new parameter is of type "reference to cv A," where cv are - // the cv-qualifiers of the function template (if any) and A is - // the class of which the function template is a member. - // - // Note that we interpret this to mean "if one of the function - // templates is a non-static member and the other is a non-member"; - // otherwise, the ordering rules for static functions against non-static - // functions don't make any sense. - // - // C++98/03 doesn't have this provision but we've extended DR532 to cover - // it as wording was broken prior to it. - SmallVector<QualType, 4> Args1; - - unsigned NumComparedArguments = NumCallArguments1; - - if (!Method2 && Method1 && Method1->isImplicitObjectMemberFunction()) { - // Compare 'this' from Method1 against first parameter from Method2. - AddImplicitObjectParameterType(S.Context, Method1, Args1); - ++NumComparedArguments; - } else if (!Method1 && Method2 && - Method2->isImplicitObjectMemberFunction()) { - // Compare 'this' from Method2 against first parameter from Method1. - AddImplicitObjectParameterType(S.Context, Method2, Args2); - } else if (Method1 && Method2 && Reversed && - Method1->isImplicitObjectMemberFunction() && - Method2->isImplicitObjectMemberFunction()) { - // 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(), - Proto1->param_type_end()); - Args2.insert(Args2.end(), Proto2->param_type_begin(), - Proto2->param_type_end()); - - // C++ [temp.func.order]p5: - // The presence of unused ellipsis and default arguments has no effect on - // the partial ordering of function templates. - if (Args1.size() > NumComparedArguments) - Args1.resize(NumComparedArguments); - if (Args2.size() > NumComparedArguments) - Args2.resize(NumComparedArguments); - if (Reversed) - std::reverse(Args2.begin(), Args2.end()); - + case TPOC_Call: if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true) != @@ -5448,7 +5389,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, return false; break; - } case TPOC_Conversion: // - In the context of a call to a conversion operator, the return types @@ -5536,8 +5476,13 @@ static bool isAtLeastAsSpecializedAs(Sema &S, /// \param NumCallArguments1 The number of arguments in the call to FT1, used /// only when \c TPOC is \c TPOC_Call. /// -/// \param NumCallArguments2 The number of arguments in the call to FT2, used -/// only when \c TPOC is \c TPOC_Call. +/// \param RawObj1Ty The type of the object parameter of FT1 if a member +/// function only used if \c TPOC is \c TPOC_Call and FT1 is a Function +/// template from a member function +/// +/// \param RawObj2Ty The type of the object parameter of FT2 if a member +/// function only used if \c TPOC is \c TPOC_Call and FT2 is a Function +/// template from a member function /// /// \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 @@ -5548,13 +5493,76 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, - unsigned NumCallArguments2, bool Reversed) { + QualType RawObj1Ty, QualType RawObj2Ty, bool Reversed) { + SmallVector<QualType> Args1; + SmallVector<QualType> Args2; + const FunctionDecl *FD1 = FT1->getTemplatedDecl(); + const FunctionDecl *FD2 = FT2->getTemplatedDecl(); + bool shouldConvert1 = false; + bool shouldConvert2 = false; + QualType Obj1Ty; + QualType Obj2Ty; + if (TPOC == TPOC_Call) { + const FunctionProtoType *Proto1 = + FD1->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto2 = + FD2->getType()->getAs<FunctionProtoType>(); - bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, - NumCallArguments1, Reversed); - bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, - NumCallArguments2, Reversed); + // - In the context of a function call, the function parameter types are + // used. + const CXXMethodDecl *Method1 = dyn_cast<CXXMethodDecl>(FD1); + const CXXMethodDecl *Method2 = dyn_cast<CXXMethodDecl>(FD2); + // C++20 [temp.func.order]p3 + // [...] Each function template M that is a member function is + // considered to have a new first parameter of type + // X(M), described below, inserted in its function parameter list. + // + // Note that we interpret "that is a member function" as + // "that is a member function with no expicit object argument". + // Otherwise the ordering rules for methods with expicit objet arguments + // against anything else make no sense. + shouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction(); + shouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction(); + if (shouldConvert1) { + bool isRValRef2 = + shouldConvert2 + ? Method2->getRefQualifier() == RQ_RValue + : Proto2->param_type_begin()[0]->isRValueReferenceType(); + // Compare 'this' from Method1 against first parameter from Method2. + Obj1Ty = GetImplicitObjectParameterType(this->Context, Method1, RawObj1Ty, + isRValRef2); + Args1.push_back(Obj1Ty); + } + if (shouldConvert2) { + bool isRValRef1 = + shouldConvert1 + ? Method1->getRefQualifier() == RQ_RValue + : Proto1->param_type_begin()[0]->isRValueReferenceType(); + // Compare 'this' from Method2 against first parameter from Method1. + Obj2Ty = GetImplicitObjectParameterType(this->Context, Method2, RawObj2Ty, + isRValRef1); + Args2.push_back(Obj2Ty); + } + size_t NumComparedArguments = NumCallArguments1 + shouldConvert1; + Args1.insert(Args1.end(), Proto1->param_type_begin(), + Proto1->param_type_end()); + Args2.insert(Args2.end(), Proto2->param_type_begin(), + Proto2->param_type_end()); + + // C++ [temp.func.order]p5: + // The presence of unused ellipsis and default arguments has no effect on + // the partial ordering of function templates. + Args1.resize(std::min(Args1.size(), NumComparedArguments)); + Args2.resize(std::min(Args2.size(), NumComparedArguments)); + + if (Reversed) + std::reverse(Args2.begin(), Args2.end()); + } + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, Reversed, + Args1, Args2); + bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, Reversed, + Args2, Args1); // C++ [temp.deduct.partial]p10: // F is more specialized than G if F is at least as specialized as G and G // is not at least as specialized as F. @@ -5568,12 +5576,28 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // ... and if G has a trailing function parameter pack for which F does not // have a corresponding parameter, and if F does not have a trailing // function parameter pack, then F is more specialized than G. - FunctionDecl *FD1 = FT1->getTemplatedDecl(); - FunctionDecl *FD2 = FT2->getTemplatedDecl(); - unsigned NumParams1 = FD1->getNumParams(); - unsigned NumParams2 = FD2->getNumParams(); - bool Variadic1 = NumParams1 && FD1->parameters().back()->isParameterPack(); - bool Variadic2 = NumParams2 && FD2->parameters().back()->isParameterPack(); + + SmallVector<QualType> param1; + param1.reserve(FD1->param_size() + shouldConvert1); + if (shouldConvert1) + param1.push_back(Obj1Ty); + for (const auto &x : FD1->parameters()) + param1.push_back(x->getType()); + + SmallVector<QualType> param2; + param2.reserve(FD2->param_size() + shouldConvert2); + if (shouldConvert2) + param2.push_back(Obj2Ty); + for (const auto &x : FD2->parameters()) + param2.push_back(x->getType()); + + unsigned NumParams1 = param1.size(); + unsigned NumParams2 = param2.size(); + + bool Variadic1 = + FD1->param_size() && FD1->parameters().back()->isParameterPack(); + bool Variadic2 = + FD2->param_size() && FD2->parameters().back()->isParameterPack(); if (Variadic1 != Variadic2) { if (Variadic1 && NumParams1 > NumParams2) return FT2; @@ -5584,8 +5608,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that // there is no wording or even resolution for this issue. for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) { - QualType T1 = FD1->getParamDecl(i)->getType().getCanonicalType(); - QualType T2 = FD2->getParamDecl(i)->getType().getCanonicalType(); + QualType T1 = param1[i].getCanonicalType(); + QualType T2 = param2[i].getCanonicalType(); auto *TST1 = dyn_cast<TemplateSpecializationType>(T1); auto *TST2 = dyn_cast<TemplateSpecializationType>(T2); if (!TST1 || !TST2) @@ -5644,8 +5668,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // Any top-level cv-qualifiers modifying a parameter type are deleted when // forming the function type. for (unsigned i = 0; i < NumParams1; ++i) - if (!Context.hasSameUnqualifiedType(FD1->getParamDecl(i)->getType(), - FD2->getParamDecl(i)->getType())) + if (!Context.hasSameUnqualifiedType(param1[i], param2[i])) return nullptr; // C++20 [temp.func.order]p6.3: @@ -5733,8 +5756,8 @@ UnresolvedSetIterator Sema::getMostSpecialized( FunctionTemplateDecl *Challenger = cast<FunctionDecl>(*I)->getPrimaryTemplate(); assert(Challenger && "Not a function template specialization?"); - if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC_Other, 0, 0), + if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, Loc, + TPOC_Other, 0), Challenger)) { Best = I; BestTemplate = Challenger; @@ -5749,7 +5772,7 @@ UnresolvedSetIterator Sema::getMostSpecialized( = cast<FunctionDecl>(*I)->getPrimaryTemplate(); if (I != Best && !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, - Loc, TPOC_Other, 0, 0), + Loc, TPOC_Other, 0), BestTemplate)) { Ambiguous = true; break; diff --git a/clang/test/CXX/drs/dr24xx.cpp b/clang/test/CXX/drs/dr24xx.cpp index ae8dda3351f48e..4534ed26e56d07 100644 --- a/clang/test/CXX/drs/dr24xx.cpp +++ b/clang/test/CXX/drs/dr24xx.cpp @@ -68,3 +68,64 @@ template<A> struct X {}; X<1> x; #endif } + +namespace dr2445 { // dr2445: 19 +#if __cplusplus >= 202002L + template <typename> constexpr bool F = false; + template <typename T> struct A { }; + + template <typename T, typename U> + bool operator==(T, A<U *>); + + template <typename T, typename U> + bool operator!=(A<T>, U) { + static_assert(F<T>, "Isn't this less specialized?"); + return false; + } + + bool f(A<int> ax, A<int *> ay) { return ay != ax; } + + template<class T> concept AlwaysTrue=true; + template <class T> struct B { + template <AlwaysTrue U> + bool operator==(const B<U>&)const; + }; + + + template <typename U> + bool operator==(const B<int>&,const B<U>&) { + static_assert(F<int>, "Isn't this less specialized?"); + return false; + } + + bool g(B<int> bx, B<int *> by) { return bx == by; } + + struct C{ + template<AlwaysTrue T> + int operator+(T){return 0;} + template<class T> + void operator-(T){} + }; + template<class T> + void operator+(C&&,T){} + template<AlwaysTrue T> + int operator-(C&&,T){return 0;} + + void t(int* iptr){ + int x1 = C{} + iptr; + int x2 = C{} - iptr; + } + + struct D{ + template<AlwaysTrue T> + int operator+(T) volatile {return 1;} + }; + + template<class T> + void operator+(volatile D&,T) {} + + int foo(volatile D& d){ + return d + 1; + } +#endif +} diff --git a/clang/test/SemaCXX/overload-template.cpp b/clang/test/SemaCXX/overload-template.cpp index 0a23788ef3da6a..0fe13c479cce22 100644 --- a/clang/test/SemaCXX/overload-template.cpp +++ b/clang/test/SemaCXX/overload-template.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++23 -verify -fsyntax-only %s enum copy_traits { movable = 1 }; @@ -33,3 +34,27 @@ void ReproducesBugSimply() { InsertRow(3, B{}); // expected-error {{no matching function for call to 'InsertRow'}} } +#if __cplusplus >= 202302L +namespace overloadCheck{ + template<typename T> + concept AlwaysTrue = true; + + struct S { + int f(AlwaysTrue auto) { return 1; } + void f(this S&&, auto) {} + + void g(auto) {} + int g(this S&&,AlwaysTrue auto) {return 1;} + + int h(AlwaysTrue auto) { return 1; } //expected-note {{previous definition is here}} + int h(this S&&,AlwaysTrue auto) { // expected-error {{class member cannot be redeclared}} + return 1; + } + }; + + int main() { + int x = S{}.f(0); + int y = S{}.g(0); + } +} +#endif diff --git a/clang/test/SemaCXX/overloaded-operator.cpp b/clang/test/SemaCXX/overloaded-operator.cpp index 887848c29b83c5..49311625d7ab2d 100644 --- a/clang/test/SemaCXX/overloaded-operator.cpp +++ b/clang/test/SemaCXX/overloaded-operator.cpp @@ -645,3 +645,40 @@ class b { } + +#if __cplusplus >= 202002L +namespace nw{ + template<class T> + concept AlwaysTrue=true; + + struct S{ + template<class T> + void operator+(const T&)const{} + + template<AlwaysTrue T> + int operator-(const T&)const{return 0;} + + template<AlwaysTrue T> + int operator*(const T&)const{ // expected-note {{candidate function}} + return 0; + } + }; + + template<AlwaysTrue T> + int operator+(const S&, const T&){return 0;} + + template<class T> + void operator-(const S&, const T&){} + + template<AlwaysTrue T> + int operator*(const S&, const T&){ // expected-note {{candidate function}} + return 0; + } + + void foo(){ + int a = S{} + 1; + int b = S{} - 1; + int c = S{} * 1; // expected-error {{use of overloaded operator '*' is ambiguous (with operand types 'S' and 'int')}} + } +} +#endif diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index b13401625a6fb5..44afeceea5414d 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -14478,7 +14478,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2445.html">2445</a></td> <td>C++20</td> <td>Partial ordering with rewritten candidates</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 19</td> </tr> <tr id="2446"> <td><a href="https://cplusplus.github.io/CWG/issues/2446.html">2446</a></td> From a11aaa25097852b057cd20f365a80404da62cbfb Mon Sep 17 00:00:00 2001 From: Botond Istvan Horvath <horvath.botond.ist...@gmail.com> Date: Wed, 6 Mar 2024 14:59:20 +0100 Subject: [PATCH 2/2] Format fixes --- clang/lib/Sema/SemaTemplateDeduction.cpp | 75 ++++++++++++------------ 1 file changed, 38 insertions(+), 37 deletions(-) diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index f14861640f549a..65f7fa15b20dd7 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -5338,13 +5338,14 @@ static QualType GetImplicitObjectParameterType(ASTContext &Context, QualType RawType, bool IsOtherRvr) { // C++20 [temp.func.order]p3.1, p3.2: - //- The type X(M ) is “rvalue reference to cv A” if the optional ref-qualifier - // of M is && or if M has no ref-qualifier and the positionally-corresponding - // parameter of the other transformed template has rvalue reference type; - // if this determination depends recursively upon whether X(M ) is an rvalue - // reference type, it is not considered to have rvalue reference type. - //- Otherwise, X(M ) is “lvalue reference to cv A”. - + // - The type X(M) is "rvalue reference to cv A" if the optional + // ref-qualifier of M is && or if M has no ref-qualifier and the + // positionally-corresponding parameter of the other transformed template + // has rvalue reference type; if this determination depends recursively + // upon whether X(M) is an rvalue reference type, it is not considered to + // have rvalue reference type. + // + // - Otherwise, X(M) is "lvalue reference to cv A". assert(Method && !Method->isExplicitObjectMemberFunction() && "expected a member function with no explicit object parameter"); @@ -5498,8 +5499,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( SmallVector<QualType> Args2; const FunctionDecl *FD1 = FT1->getTemplatedDecl(); const FunctionDecl *FD2 = FT2->getTemplatedDecl(); - bool shouldConvert1 = false; - bool shouldConvert2 = false; + bool ShouldConvert1 = false; + bool ShouldConvert2 = false; QualType Obj1Ty; QualType Obj2Ty; if (TPOC == TPOC_Call) { @@ -5521,29 +5522,29 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // "that is a member function with no expicit object argument". // Otherwise the ordering rules for methods with expicit objet arguments // against anything else make no sense. - shouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction(); - shouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction(); - if (shouldConvert1) { - bool isRValRef2 = - shouldConvert2 + ShouldConvert1 = Method1 && !Method1->isExplicitObjectMemberFunction(); + ShouldConvert2 = Method2 && !Method2->isExplicitObjectMemberFunction(); + if (ShouldConvert1) { + bool IsRValRef2 = + ShouldConvert2 ? Method2->getRefQualifier() == RQ_RValue : Proto2->param_type_begin()[0]->isRValueReferenceType(); // Compare 'this' from Method1 against first parameter from Method2. Obj1Ty = GetImplicitObjectParameterType(this->Context, Method1, RawObj1Ty, - isRValRef2); + IsRValRef2); Args1.push_back(Obj1Ty); } - if (shouldConvert2) { - bool isRValRef1 = - shouldConvert1 + if (ShouldConvert2) { + bool IsRValRef1 = + ShouldConvert1 ? Method1->getRefQualifier() == RQ_RValue : Proto1->param_type_begin()[0]->isRValueReferenceType(); // Compare 'this' from Method2 against first parameter from Method1. Obj2Ty = GetImplicitObjectParameterType(this->Context, Method2, RawObj2Ty, - isRValRef1); + IsRValRef1); Args2.push_back(Obj2Ty); } - size_t NumComparedArguments = NumCallArguments1 + shouldConvert1; + size_t NumComparedArguments = NumCallArguments1 + ShouldConvert1; Args1.insert(Args1.end(), Proto1->param_type_begin(), Proto1->param_type_end()); @@ -5577,22 +5578,22 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // have a corresponding parameter, and if F does not have a trailing // function parameter pack, then F is more specialized than G. - SmallVector<QualType> param1; - param1.reserve(FD1->param_size() + shouldConvert1); - if (shouldConvert1) - param1.push_back(Obj1Ty); - for (const auto &x : FD1->parameters()) - param1.push_back(x->getType()); + SmallVector<QualType> Param1; + Param1.reserve(FD1->param_size() + ShouldConvert1); + if (ShouldConvert1) + Param1.push_back(Obj1Ty); + for (const auto &P : FD1->parameters()) + Param1.push_back(P->getType()); - SmallVector<QualType> param2; - param2.reserve(FD2->param_size() + shouldConvert2); - if (shouldConvert2) - param2.push_back(Obj2Ty); - for (const auto &x : FD2->parameters()) - param2.push_back(x->getType()); + SmallVector<QualType> Param2; + Param2.reserve(FD2->param_size() + ShouldConvert2); + if (ShouldConvert2) + Param2.push_back(Obj2Ty); + for (const auto &P : FD2->parameters()) + Param2.push_back(P->getType()); - unsigned NumParams1 = param1.size(); - unsigned NumParams2 = param2.size(); + unsigned NumParams1 = Param1.size(); + unsigned NumParams2 = Param2.size(); bool Variadic1 = FD1->param_size() && FD1->parameters().back()->isParameterPack(); @@ -5608,8 +5609,8 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // This a speculative fix for CWG1432 (Similar to the fix for CWG1395) that // there is no wording or even resolution for this issue. for (int i = 0, e = std::min(NumParams1, NumParams2); i < e; ++i) { - QualType T1 = param1[i].getCanonicalType(); - QualType T2 = param2[i].getCanonicalType(); + QualType T1 = Param1[i].getCanonicalType(); + QualType T2 = Param2[i].getCanonicalType(); auto *TST1 = dyn_cast<TemplateSpecializationType>(T1); auto *TST2 = dyn_cast<TemplateSpecializationType>(T2); if (!TST1 || !TST2) @@ -5668,7 +5669,7 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate( // Any top-level cv-qualifiers modifying a parameter type are deleted when // forming the function type. for (unsigned i = 0; i < NumParams1; ++i) - if (!Context.hasSameUnqualifiedType(param1[i], param2[i])) + if (!Context.hasSameUnqualifiedType(Param1[i], Param2[i])) return nullptr; // C++20 [temp.func.order]p6.3: _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits