Author: cor3ntin Date: 2023-11-28T13:30:18+01:00 New Revision: 205f53010d0da11a9c4ab7a4655edb4a2ded1b02
URL: https://github.com/llvm/llvm-project/commit/205f53010d0da11a9c4ab7a4655edb4a2ded1b02 DIFF: https://github.com/llvm/llvm-project/commit/205f53010d0da11a9c4ab7a4655edb4a2ded1b02.diff LOG: [Clang] CWG2789 Overload resolution with implicit and explicit object… (#73493) … 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. Added: Modified: clang/include/clang/Sema/Sema.h clang/lib/Sema/SemaOverload.cpp clang/test/CXX/drs/dr27xx.cpp Removed: ################################################################################ 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..3a3e9234469d393 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; + + FunctionDecl *Fn1 = Cand1.Function; + FunctionDecl *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..5c7ce98f878da6b 100644 --- a/clang/test/CXX/drs/dr27xx.cpp +++ b/clang/test/CXX/drs/dr27xx.cpp @@ -1,5 +1,35 @@ // RUN: %clang_cc1 -std=c++2c -verify %s +namespace dr2789 { // dr2789: 18 open +template <typename T = int> +struct Base { + constexpr void g(); // #dr2789-g1 +}; + +template <typename T = int> +struct Base2 { + constexpr void g() requires true; // #dr2789-g2 +}; + +template <typename T = int> +struct S : Base<T>, Base2<T> { + constexpr void f(); + constexpr void f(this S&) requires true{}; + + 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}} + // expected-note@#dr2789-g1 {{candidate function}} + // expected-note@#dr2789-g2 {{candidate function}} +} + +} + namespace dr2798 { // dr2798: 17 drafting #if __cpp_static_assert >= 202306 struct string { @@ -22,3 +52,4 @@ consteval X f() { return {}; } static_assert(false, f().s); // expected-error {{static assertion failed: Hello}} #endif } // namespace dr2798 + _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits