Bootstrapped and regtested on x86_64-pc-linux-gnu, does this
look OK for trunk?  I'm not sure this is worth backporting
without the previous CWG 2273 tweak since it'll mean inconsistent
behavior between implict vs explicit object members in GCC 14: the call
to S<>{}.f() in concepts-memfun4.C would now return 10 (due to the CWG
2273 tiebreaker incorrectly triggering), while the g() and h() calls
would be ambiguous (since that tiebreaker doesn't consider object
correspondence).

Also I'm not 100% sure if I'm interpreting "both are direct members of
the same class" correctly here to mean ruling out using'd vs non-using'd
members, since https://eel.is/c++draft/namespace.udecl#note-5 says
using'd members are "treated as though they were direct members of the
derived class"...?

-- >8 --

After CWG 2789, the "more constrained" tiebreaker for non-template
functions should exclude members that come from different classes
via using.  This patch implements this missing refinement.  In turn
we can get rid of four-parameter overload of object_parms_correspond
and call the main overload directly since we know correspondence is now
only checked for members from the same class.

        PR c++/116492
        DR 2789

gcc/cp/ChangeLog:

        * call.cc (object_parms_correspond): Remove.
        (cand_parms_match): Return false for member functions
        that come from different classes.  Adjust call to
        object_parms_correspond.
        (joust): Update comment for the non-template "more
        constrained" case.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/concepts-memfun4.C: Expect ambiguity when
        candidates come from different classes.
        * g++.dg/cpp2a/concepts-inherit-ctor12.C: New test.
---
 gcc/cp/call.cc                                | 54 +++++++------------
 .../g++.dg/cpp2a/concepts-inherit-ctor12.C    | 16 ++++++
 gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C | 24 +++++----
 3 files changed, 49 insertions(+), 45 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 87b54291b51..de742da6927 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -12808,27 +12808,6 @@ class_of_implicit_object (z_candidate *cand)
   return BINFO_TYPE (cand->conversion_path);
 }
 
-/* True if candidates C1 and C2 have corresponding object parameters per
-   [basic.scope.scope].  */
-
-static bool
-object_parms_correspond (z_candidate *c1, tree fn1, z_candidate *c2, tree fn2)
-{
-  tree context = class_of_implicit_object (c1);
-  tree ctx2 = class_of_implicit_object (c2);
-  if (!ctx2)
-    /* Leave context as is. */;
-  else if (!context)
-    context = ctx2;
-  else if (context != ctx2)
-    /* This can't happen for normal function calls, since it means finding
-       functions in multiple bases which would fail with an ambiguous lookup,
-       but it can occur with reversed operators.  */
-    return false;
-
-  return object_parms_correspond (fn1, fn2, context);
-}
-
 /* Return whether the first parameter of C1 matches the second parameter
    of C2.  */
 
@@ -12893,16 +12872,19 @@ cand_parms_match (z_candidate *c1, z_candidate *c2, 
pmatch match_kind)
   tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1));
   tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (fn2));
 
-  if (!(DECL_FUNCTION_MEMBER_P (fn1)
-       && DECL_FUNCTION_MEMBER_P (fn2)))
-    /* Early escape.  */;
-
-  /* CWG2789 is not adequate, it should specify corresponding object
-     parameters, not same typed object parameters.  */
-  else if (!object_parms_correspond (c1, fn1, c2, fn2))
-    return false;
-  else
+  if (DECL_FUNCTION_MEMBER_P (fn1)
+      && DECL_FUNCTION_MEMBER_P (fn2))
     {
+      tree base1 = DECL_CONTEXT (strip_inheriting_ctors (fn1));
+      tree base2 = DECL_CONTEXT (strip_inheriting_ctors (fn2));
+      if (base1 != base2)
+       return false;
+
+      /* CWG2789 is not adequate, it should specify corresponding object
+        parameters, not same typed object parameters.  */
+      if (!object_parms_correspond (fn1, fn2, base1))
+       return false;
+
       /* We just compared the object parameters, if they don't correspond
         we already returned false.  */
       auto skip_parms = [] (tree fn, tree parms)
@@ -13269,10 +13251,14 @@ joust (struct z_candidate *cand1, struct z_candidate 
*cand2, bool warn,
        return winner;
     }
 
-  /* Concepts: F1 and F2 are non-template functions with the same
-     parameter-type-lists, and F1 is more constrained than F2 according to the
-     partial ordering of constraints described in 13.5.4.  */
-
+  /* F1 and F2 are non-template functions and
+     - they have the same non-object-parameter-type-lists ([dcl.fct]), and
+     - if they are member functions, both are direct members of the same
+       class, and
+     - if both are non-static member functions, they have the same types for
+       their object parameters, and
+     - F1 is more constrained than F2 according to the partial ordering of
+       constraints described in [temp.constr.order].  */
   if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn)
       && !cand1->template_decl && !cand2->template_decl
       && cand_parms_match (cand1, cand2, pmatch::current))
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C
new file mode 100644
index 00000000000..3e5dbfc37ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-inherit-ctor12.C
@@ -0,0 +1,16 @@
+// PR c++/116492
+// CWG 2789
+// { dg-do compile { target c++20 } }
+
+template<class T>
+struct A {
+  A() requires true = delete;
+};
+
+struct B : A<int> {
+  B();
+  using A<int>::A;
+};
+
+B b; // OK, selects the non-inherited constructor over the more constrained
+     // inherited constructor.
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C 
b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C
index 91e34f1cd7a..62e304b5322 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C
@@ -1,5 +1,7 @@
 // PR c++/113191
-// { dg-do compile { target c++23 } }
+// CWG 2789
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-Wno-error=c++23-extensions" { target c++20_only } 
}
 
 template<typename> struct S;
 
@@ -8,6 +10,7 @@ struct B {
   constexpr int f() const requires true { return 5; }
   constexpr operator int () const requires true { return 5; }
   constexpr int g(this S<T>&&) requires true { return 5; }
+  // { dg-warning "explicit object" "" { target c++20_only } .-1 }
   constexpr int h() requires true { return 5; }
 };
 
@@ -20,12 +23,14 @@ struct S : B<> {
   constexpr operator int () const { return 10; }
   constexpr int g() { return 10; }
   constexpr int h(this S&&) { return 10; }
+  // { dg-warning "explicit object" "" { target c++20_only } .-1 }
 };
 
-// implicit object parms match, B::f is more constrained
-static_assert(S<>{}.f() == 5);
-static_assert(S<>{}.g() == 5);
-static_assert(S<>{}.h() == 5);
+// ambiguous, constraints aren't considered since the candidates
+// are defined from different classes
+static_assert(S<>{}.f() == 5); // { dg-error "ambiguous" }
+static_assert(S<>{}.g() == 5); // { dg-error "ambiguous" }
+static_assert(S<>{}.h() == 5); // { dg-error "ambiguous" }
 
 template <typename = void>
 struct C {
@@ -36,9 +41,8 @@ struct C {
 template <typename = void>
 struct S2: B<>, C<> { };
 
-// implicit object parms for conversion functions are all considered to be from
-// the class of the object argument
-static_assert(S2<>{} == 5);
+// ambiguous as above
+static_assert(S2<>{} == 5); // { dg-error "ambiguous" }
 
 // ambiguous lookup, so we never actually compare the candidates
 // if we did, implicit object parms don't match due to different classes
@@ -51,7 +55,6 @@ struct S3 : B<> {
   constexpr int f() volatile { return 10; }
 };
 
-// implicit object parms don't match due to different cv-quals
 static_assert(S3<>{}.f() == 5);        // { dg-error "ambiguous" }
 
 template <typename = void>
@@ -60,8 +63,7 @@ struct S4 : B<> {
   constexpr int f() const & { return 10; }
 };
 
-// no ref-qual matches any ref-qual
-static_assert(S4<>{}.f() == 5);
+static_assert(S4<>{}.f() == 5); // { dg-error "ambiguous" }
 
 template <typename = void>
 struct C2 {
-- 
2.46.1.544.g3fb745257b

Reply via email to