https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/73493
>From d3cb9b147c443762fc7d545100144e462bbe3b58 Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Mon, 27 Nov 2023 10:48:13 +0100 Subject: [PATCH 1/2] [Clang] CWG2789 Overload resolution with implicit and explicit object member functions Implement the resolution to CWG2789 from https://wiki.edg.com/pub/Wg21kona2023/StrawPolls/p3046r0.html The DR page is not updated because the issue has not made it to a published list yet. --- clang/include/clang/Sema/Sema.h | 6 +++ clang/lib/Sema/SemaOverload.cpp | 69 ++++++++++++++++++++++++++------- clang/test/CXX/drs/dr27xx.cpp | 29 ++++++++++++++ 3 files changed, 90 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f7c9d0e2e6412b7..7579a3256bc37aa 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -3849,6 +3849,12 @@ class Sema final { const FunctionProtoType *NewType, unsigned *ArgPos = nullptr, bool Reversed = false); + + bool FunctionNonObjectParamTypesAreEqual(const FunctionDecl *OldFunction, + const FunctionDecl *NewFunction, + unsigned *ArgPos = nullptr, + bool Reversed = false); + void HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, QualType FromType, QualType ToType); diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 9800d7f1c9cfee9..cc69cd1f2862aae 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -3239,6 +3239,28 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType, NewType->param_types(), ArgPos, Reversed); } +bool Sema::FunctionNonObjectParamTypesAreEqual(const FunctionDecl *OldFunction, + const FunctionDecl *NewFunction, + unsigned *ArgPos, + bool Reversed) { + + if (OldFunction->getNumNonObjectParams() != + NewFunction->getNumNonObjectParams()) + return false; + + unsigned OldIgnore = + unsigned(OldFunction->hasCXXExplicitFunctionObjectParameter()); + unsigned NewIgnore = + unsigned(NewFunction->hasCXXExplicitFunctionObjectParameter()); + + auto *OldPT = cast<FunctionProtoType>(OldFunction->getFunctionType()); + auto *NewPT = cast<FunctionProtoType>(NewFunction->getFunctionType()); + + return FunctionParamTypesAreEqual(OldPT->param_types().slice(OldIgnore), + NewPT->param_types().slice(NewIgnore), + ArgPos, Reversed); +} + /// CheckPointerConversion - Check the pointer conversion from the /// expression From to the type ToType. This routine checks for /// ambiguous or inaccessible derived-to-base pointer @@ -10121,22 +10143,41 @@ static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1, /// We're allowed to use constraints partial ordering only if the candidates /// have the same parameter types: -/// [over.match.best]p2.6 -/// F1 and F2 are non-template functions with the same parameter-type-lists, -/// and F1 is more constrained than F2 [...] +/// [over.match.best.general]p2.6 +/// F1 and F2 are non-template functions with the same +/// non-object-parameter-type-lists, and F1 is more constrained than F2 [...] static bool sameFunctionParameterTypeLists(Sema &S, - const OverloadCandidate &Cand1, - const OverloadCandidate &Cand2) { - if (Cand1.Function && Cand2.Function) { - auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType()); - auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType()); - if (PT1->getNumParams() == PT2->getNumParams() && - PT1->isVariadic() == PT2->isVariadic() && - S.FunctionParamTypesAreEqual(PT1, PT2, nullptr, - Cand1.isReversed() ^ Cand2.isReversed())) - return true; + const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2) { + if (!Cand1.Function || !Cand2.Function) + return false; + + auto *Fn1 = Cand1.Function; + auto *Fn2 = Cand2.Function; + + if (Fn1->isVariadic() != Fn1->isVariadic()) + return false; + + if (!S.FunctionNonObjectParamTypesAreEqual( + Fn1, Fn2, nullptr, Cand1.isReversed() ^ Cand2.isReversed())) + return false; + + auto *Mem1 = dyn_cast<CXXMethodDecl>(Fn1); + auto *Mem2 = dyn_cast<CXXMethodDecl>(Fn2); + if (Mem1 && Mem2) { + // if they are member functions, both are direct members of the same class, + // and + if (Mem1->getParent() != Mem2->getParent()) + return false; + // if both are non-static member functions, they have the same types for + // their object parameters + if (Mem1->isInstance() && Mem2->isInstance() && + !S.getASTContext().hasSameType( + Mem1->getFunctionObjectParameterReferenceType(), + Mem1->getFunctionObjectParameterReferenceType())) + return false; } - return false; + return true; } /// isBetterOverloadCandidate - Determines whether the first overload diff --git a/clang/test/CXX/drs/dr27xx.cpp b/clang/test/CXX/drs/dr27xx.cpp index a5998163da52493..f9899e6db6acc3b 100644 --- a/clang/test/CXX/drs/dr27xx.cpp +++ b/clang/test/CXX/drs/dr27xx.cpp @@ -1,5 +1,33 @@ // RUN: %clang_cc1 -std=c++2c -verify %s +namespace dr2789 { // dr2789: 18 open +template <typename T = int> +struct Base { + constexpr void g(); // expected-note {{candidate function}} +}; + +template <typename T = int> +struct Base2 { + constexpr void g() requires true; // expected-note {{candidate function}} +}; + +template <typename T = int> +struct S : Base<T>, Base2<T> { + constexpr void f(); // #1 + constexpr void f(this S&) requires true{}; // #2 + + using Base<T>::g; + using Base2<T>::g; +}; + +void test() { + S<> s; + s.f(); + s.g(); // expected-error {{call to member function 'g' is ambiguous}} +} + +} + namespace dr2798 { // dr2798: 17 drafting #if __cpp_static_assert >= 202306 struct string { @@ -22,3 +50,4 @@ consteval X f() { return {}; } static_assert(false, f().s); // expected-error {{static assertion failed: Hello}} #endif } // namespace dr2798 + >From 29d13a04a9207b0699885e2535e7a6eb0eb167bf Mon Sep 17 00:00:00 2001 From: Corentin Jabot <corentinja...@gmail.com> Date: Mon, 27 Nov 2023 20:56:04 +0100 Subject: [PATCH 2/2] Address review comments --- clang/lib/Sema/SemaOverload.cpp | 4 ++-- clang/test/CXX/drs/dr27xx.cpp | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index cc69cd1f2862aae..3a3e9234469d393 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10152,8 +10152,8 @@ static bool sameFunctionParameterTypeLists(Sema &S, if (!Cand1.Function || !Cand2.Function) return false; - auto *Fn1 = Cand1.Function; - auto *Fn2 = Cand2.Function; + FunctionDecl *Fn1 = Cand1.Function; + FunctionDecl *Fn2 = Cand2.Function; if (Fn1->isVariadic() != Fn1->isVariadic()) return false; diff --git a/clang/test/CXX/drs/dr27xx.cpp b/clang/test/CXX/drs/dr27xx.cpp index f9899e6db6acc3b..5c7ce98f878da6b 100644 --- a/clang/test/CXX/drs/dr27xx.cpp +++ b/clang/test/CXX/drs/dr27xx.cpp @@ -3,18 +3,18 @@ namespace dr2789 { // dr2789: 18 open template <typename T = int> struct Base { - constexpr void g(); // expected-note {{candidate function}} + constexpr void g(); // #dr2789-g1 }; template <typename T = int> struct Base2 { - constexpr void g() requires true; // expected-note {{candidate function}} + constexpr void g() requires true; // #dr2789-g2 }; template <typename T = int> struct S : Base<T>, Base2<T> { - constexpr void f(); // #1 - constexpr void f(this S&) requires true{}; // #2 + constexpr void f(); + constexpr void f(this S&) requires true{}; using Base<T>::g; using Base2<T>::g; @@ -24,6 +24,8 @@ void test() { S<> s; s.f(); s.g(); // expected-error {{call to member function 'g' is ambiguous}} + // expected-note@#dr2789-g1 {{candidate function}} + // expected-note@#dr2789-g2 {{candidate function}} } } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits