]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: cand_parms_match and reversed candidates
authorJason Merrill <jason@redhat.com>
Thu, 11 Jan 2024 04:18:23 +0000 (23:18 -0500)
committerJason Merrill <jason@redhat.com>
Fri, 12 Jan 2024 14:11:24 +0000 (09:11 -0500)
When considering whether the candidate parameters match, according to the
language we're considering the synthesized reversed candidate, so we should
compare the parameters in swapped order.  In this situation it doesn't make
sense to consider whether object parameters correspond, since we're
comparing an object parameter to a non-object parameter, so I generalized
xobj_iobj_parameters_correspond accordingly.

As I refine cand_parms_match, more behaviors need to differ between its
original use to compare the original templates for two candidates, and the
later use to decide whether to compare constraints.  So now there's a
parameter to select between the semantics.

gcc/cp/ChangeLog:

* call.cc (reversed_match): New.
(enum class pmatch): New enum.
(cand_parms_match): Add match_kind parm.
(object_parms_correspond): Add fn parms.
(joust): Adjust.
* class.cc (xobj_iobj_parameters_correspond): Rename to...
(iobj_parm_corresponds_to): ...this.  Take the other
type instead of a second function.
(object_parms_correspond): Adjust.
* cp-tree.h (iobj_parm_corresponds_to): Declare.

gcc/testsuite/ChangeLog:

* g++.dg/cpp2a/concepts-memfun4.C: Change expected
reversed handling.

gcc/cp/call.cc
gcc/cp/class.cc
gcc/cp/cp-tree.h
gcc/testsuite/g++.dg/cpp2a/concepts-memfun4.C

index 6f024b8abc395e315bfece1f2727771ceb19c65a..1f5ff417c8110e460c931dff571b65afdeed7974 100644 (file)
@@ -12713,7 +12713,7 @@ class_of_implicit_object (z_candidate *cand)
    [basic.scope.scope].  */
 
 static bool
-object_parms_correspond (z_candidate *c1, z_candidate *c2)
+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);
@@ -12727,43 +12727,80 @@ object_parms_correspond (z_candidate *c1, z_candidate *c2)
        but it can occur with reversed operators.  */
     return false;
 
-  return object_parms_correspond (c1->fn, c2->fn, context);
+  return object_parms_correspond (fn1, fn2, context);
+}
+
+/* Return whether the first parameter of C1 matches the second parameter
+   of C2.  */
+
+static bool
+reversed_match (z_candidate *c1, z_candidate *c2)
+{
+  tree fn1 = c1->fn;
+  tree parms2 = TYPE_ARG_TYPES (TREE_TYPE (c2->fn));
+  tree parm2 = TREE_VALUE (TREE_CHAIN (parms2));
+  if (DECL_IOBJ_MEMBER_FUNCTION_P (fn1))
+    {
+      tree ctx = class_of_implicit_object (c1);
+      return iobj_parm_corresponds_to (fn1, parm2, ctx);
+    }
+  else
+    {
+      tree parms1 = TYPE_ARG_TYPES (TREE_TYPE (fn1));
+      tree parm1 = TREE_VALUE (parms1);
+      return same_type_p (parm1, parm2);
+    }
 }
 
 /* True if the defining declarations of the two candidates have equivalent
-   parameters.  */
+   parameters.  MATCH_KIND controls whether we're trying to compare the
+   original declarations (for a warning) or the actual candidates.  */
+
+enum class pmatch { original, current };
 
 static bool
-cand_parms_match (z_candidate *c1, z_candidate *c2)
+cand_parms_match (z_candidate *c1, z_candidate *c2, pmatch match_kind)
 {
   tree fn1 = c1->fn;
   tree fn2 = c2->fn;
-  if (fn1 == fn2)
+  bool reversed = (match_kind == pmatch::current
+                  && c1->reversed () != c2->reversed ());
+  if (fn1 == fn2 && !reversed)
     return true;
   if (identifier_p (fn1) || identifier_p (fn2))
     return false;
-  /* We don't look at c1->template_decl because that's only set for primary
-     templates, not e.g. non-template member functions of class templates.  */
-  tree t1 = most_general_template (fn1);
-  tree t2 = most_general_template (fn2);
-  if (t1 || t2)
+  if (match_kind == pmatch::original)
     {
-      if (!t1 || !t2)
-       return false;
-      if (t1 == t2)
-       return true;
-      fn1 = DECL_TEMPLATE_RESULT (t1);
-      fn2 = DECL_TEMPLATE_RESULT (t2);
+      /* We don't look at c1->template_decl because that's only set for
+        primary templates, not e.g. non-template member functions of
+        class templates.  */
+      tree t1 = most_general_template (fn1);
+      tree t2 = most_general_template (fn2);
+      if (t1 || t2)
+       {
+         if (!t1 || !t2)
+           return false;
+         if (t1 == t2)
+           return true;
+         fn1 = DECL_TEMPLATE_RESULT (t1);
+         fn2 = DECL_TEMPLATE_RESULT (t2);
+       }
     }
+
+  else if (reversed)
+    return (reversed_match (c1, c2)
+           && reversed_match (c2, c1));
+
   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, c2))
+  else if (!object_parms_correspond (c1, fn1, c2, fn2))
     return false;
   else
     {
@@ -12938,7 +12975,7 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
                 this approach to resolving the ambiguity, so pedwarn.  */
              if ((complain & tf_warning_or_error)
                  && (cand1->reversed () != cand2->reversed ())
-                 && cand_parms_match (cand1, cand2))
+                 && cand_parms_match (cand1, cand2, pmatch::original))
                {
                  struct z_candidate *w, *l;
                  if (cand2->reversed ())
@@ -13139,8 +13176,7 @@ joust (struct z_candidate *cand1, struct z_candidate *cand2, bool warn,
 
   if (flag_concepts && DECL_P (cand1->fn) && DECL_P (cand2->fn)
       && !cand1->template_decl && !cand2->template_decl
-      && cand1->reversed () == cand2->reversed ()
-      && cand_parms_match (cand1, cand2))
+      && cand_parms_match (cand1, cand2, pmatch::current))
     {
       winner = more_constrained (cand1->fn, cand2->fn);
       if (winner)
index 3374756fb9ab90e1e788b0fd9f5994af963b21dc..556943c3e55122fd0af78bdece61232bce0f9524 100644 (file)
@@ -1019,24 +1019,13 @@ modify_vtable_entry (tree t,
 }
 
 \f
-/* Check if the object parameters of an xobj and iobj member function
-   correspond.  CONTEXT is the class that an implicit object parameter
-   refers to.  */
+/* Check if the object parameter of an iobj member function corresponds to
+   another parameter type.  CONTEXT is the class that the implicit object
+   parameter is considered to refer to.  */
 
-static bool
-xobj_iobj_parameters_correspond (tree fn1, tree fn2, tree context)
+bool
+iobj_parm_corresponds_to (tree iobj_fn, tree xobj_param, tree context)
 {
-  gcc_assert (DECL_IOBJ_MEMBER_FUNCTION_P (fn1)
-             || DECL_IOBJ_MEMBER_FUNCTION_P (fn2));
-  gcc_assert (DECL_XOBJ_MEMBER_FUNCTION_P (fn1)
-             || DECL_XOBJ_MEMBER_FUNCTION_P (fn2));
-  gcc_assert (fn1 != fn2);
-
-  tree xobj_fn = DECL_XOBJ_MEMBER_FUNCTION_P (fn1) ? fn1 : fn2;
-  /* A reference, pointer, or something else.  */
-  tree xobj_param = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (xobj_fn)));
-
-  tree iobj_fn = DECL_IOBJ_MEMBER_FUNCTION_P (fn1) ? fn1 : fn2;
   tree iobj_fn_type = TREE_TYPE (iobj_fn);
 
   /* If the iobj member function was introduced with a using declaration, the
@@ -1253,11 +1242,14 @@ object_parms_correspond (tree fn, tree method, tree context)
       if (!same_type_p (fn_param, method_param))
        return false;
     }
-  else if (DECL_XOBJ_MEMBER_FUNCTION_P (fn)
-          || DECL_XOBJ_MEMBER_FUNCTION_P (method))
-    return xobj_iobj_parameters_correspond (fn, method, context);
   else
-    gcc_unreachable ();
+    {
+      tree xobj_fn = DECL_XOBJ_MEMBER_FUNCTION_P (fn) ? fn : method;
+      tree iobj_fn = xobj_fn != fn ? fn : method;
+      tree xobj_param = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (xobj_fn)));
+
+      return iobj_parm_corresponds_to (iobj_fn, xobj_param, context);
+    }
 
   return true;
 }
index 83009fc837c06ec6330960a77e693cde8077813a..d9b14d7c4f5e6dff64d17425ff5247e6976ab6d5 100644 (file)
@@ -6854,6 +6854,7 @@ extern tree build_vtbl_ref                        (tree, tree);
 extern tree build_vfn_ref                      (tree, tree);
 extern tree get_vtable_decl                    (tree, int);
 extern bool object_parms_correspond            (tree, tree, tree);
+extern bool iobj_parm_corresponds_to           (tree, tree, tree);
 extern bool add_method                         (tree, tree, bool);
 extern tree declared_access                    (tree);
 extern bool maybe_push_used_methods            (tree);
index 2fa661dbe9663cb12e7cb4c5dc22439ad828bedd..91e34f1cd7aef8845d50b53b71bc22772efa37f9 100644 (file)
@@ -79,19 +79,17 @@ namespace N1 {
 
   template <class = void>
   struct A {
-    constexpr bool operator==(B<>&) { return true; }
+    constexpr bool operator==(B<>&) { return false; }
   };
 
   template <class>
   struct B {
-    constexpr bool operator==(A<>&) requires true { return false; }
+    constexpr bool operator==(A<>&) requires true { return true; }
   };
 
   A<> a;
   B<> b;
-  // when comparing the A op== to the reversed B op==, we don't compare
-  // constraints and so fall through to the tiebreaker that chooses the
-  // non-reversed candidate.
-  // ??? shouldn't we compare constraints?
+  // when comparing the A op== to the reversed B op==, we compare them in
+  // reverse order, so they match, and we choose the more constrained.
   static_assert (a == b);
 }