[clang] 205f530 - [Clang] CWG2789 Overload resolution with implicit and explicit object… (#73493)

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 28 04:30:22 PST 2023


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
+


        


More information about the cfe-commits mailing list