https://gcc.gnu.org/g:ee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2

commit r15-3741-gee3efe06c9c49c04eaa4e195a7ae8774a1b3faa2
Author: Patrick Palka <ppa...@redhat.com>
Date:   Fri Sep 20 12:33:13 2024 -0400

    c++: CWG 2789 and usings [PR116492]
    
    After CWG 2789, the "more constrained" tiebreaker for non-template
    functions should exclude member functions that are defined in
    different classes.  This patch implements this missing refinement.
    
    In turn we can get rid of four-parameter version of object_parms_correspond
    and call the main overload directly since now correspondence is only
    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: Also compile in C++20 mode.
            Expect ambiguity when candidates come from different classes.
            * g++.dg/cpp2a/concepts-inherit-ctor12.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 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(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 6229dc452636..f2ce50857ece 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;
+
+      /* Use object_parms_correspond to simplify comparing iobj/xobj/static
+        member functions.  */
+      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 000000000000..3e5dbfc37ad0
--- /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 91e34f1cd7ae..cf7f13c007d1 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
+// come 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 {

Reply via email to