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

commit r16-3727-gf2fddc4b84a843d32399fe457acabb73fca9869b
Author: Patrick Palka <[email protected]>
Date:   Tue Sep 9 14:39:57 2025 -0400

    c++: non-dep cmp op rewritten from <=> returning int [PR121779]
    
    Apparently an explicitly defined operator<=> isn't required to return
    std::foo_ordering, so build_min_non_dep_op_overload needs to be able
    to rebuild forms of (x <=> y) @ 0 where the @ resolved to a built-in and
    in turn isn't expressed as a function call.
    
            PR c++/121779
    
    gcc/cp/ChangeLog:
    
            * tree.cc (build_min_non_dep_op_overload): Handle comparison
            operator expressions rewritten from a <=> that returns a
            non-class type.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/lookup/operator-8.C: Remove outdated comment about
            this test failing.
            * g++.dg/lookup/operator-8a.C: New test.
    
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/tree.cc                            | 17 +++++++++++--
 gcc/testsuite/g++.dg/lookup/operator-8.C  |  3 ---
 gcc/testsuite/g++.dg/lookup/operator-8a.C | 40 +++++++++++++++++++++++++++++++
 3 files changed, 55 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index e354da0f0185..03b58ff60059 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3730,7 +3730,9 @@ build_min_non_dep_op_overload (enum tree_code op,
             rebuild the <=>.  Note that both OVERLOAD and the provided 
arguments
             in this case already correspond to the selected operator<=>.  */
 
-         tree spaceship_non_dep = CALL_EXPR_ARG (non_dep, reversed ? 1 : 0);
+         tree spaceship_non_dep = (TREE_CODE (non_dep) == CALL_EXPR
+                                   ? CALL_EXPR_ARG (non_dep, reversed ? 1 : 0)
+                                   : TREE_OPERAND (non_dep, reversed ? 1 : 0));
          gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR);
          tree spaceship_op0 = va_arg (p, tree);
          tree spaceship_op1 = va_arg (p, tree);
@@ -3744,8 +3746,19 @@ build_min_non_dep_op_overload (enum tree_code op,
                                                    TREE_VALUE (overload),
                                                    spaceship_op0,
                                                    spaceship_op1);
-         tree op1 = CALL_EXPR_ARG (non_dep, reversed ? 0 : 1);
+         tree op1 = (TREE_CODE (non_dep) == CALL_EXPR
+                     ? CALL_EXPR_ARG (non_dep, reversed ? 0 : 1)
+                     : TREE_OPERAND (non_dep, reversed ? 0 : 1));
          gcc_checking_assert (integer_zerop (op1));
+
+         if (TREE_CODE (non_dep) != CALL_EXPR)
+           {
+             gcc_checking_assert (COMPARISON_CLASS_P (non_dep));
+             if (reversed)
+               std::swap (op0, op1);
+             return build_min_non_dep (TREE_CODE (non_dep), non_dep, op0, op1);
+           }
+
          vec_safe_push (args, op0);
          vec_safe_push (args, op1);
          overload = CALL_EXPR_FN (non_dep);
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8.C 
b/gcc/testsuite/g++.dg/lookup/operator-8.C
index 32d432dd8432..4646a6f1303e 100644
--- a/gcc/testsuite/g++.dg/lookup/operator-8.C
+++ b/gcc/testsuite/g++.dg/lookup/operator-8.C
@@ -1,9 +1,6 @@
 // Verify phase 1 lookup works properly for rewritten non-dependent conditional
 // operator expressions.
 
-// This test currently fails due to build_min_non_dep_op_overload not knowing
-// how to handle rewritten operator expressions; see the FIXME in build_new_op.
-
 // { dg-do compile { target c++20 } }
 
 #include <compare>
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8a.C 
b/gcc/testsuite/g++.dg/lookup/operator-8a.C
new file mode 100644
index 000000000000..48df7838520c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-8a.C
@@ -0,0 +1,40 @@
+// PR c++/121779
+// A version of operator-8.C where the operator<=> return type is int.
+
+// { dg-do compile { target c++20 } }
+
+struct A {
+  bool operator==(int);
+  int operator<=>(int);
+};
+
+template<class T>
+void f() {
+  A a;
+  (void)(a != 0);
+  (void)(0 != a);
+  (void)(a < 0);
+  (void)(0 < a);
+  (void)(a <= 0);
+  (void)(0 <= a);
+  (void)(a > 0);
+  (void)(0 > a);
+  (void)(a >= 0);
+  (void)(0 >= a);
+}
+
+// These later-declared namespace-scope overloads shouldn't be considered
+// when instantiating f<int>.
+bool operator!=(A, int) = delete;
+bool operator<(A, int) = delete;
+bool operator<=(A, int) = delete;
+bool operator>(A, int) = delete;
+bool operator>=(A, int) = delete;
+
+bool operator!=(int, A) = delete;
+bool operator<(int, A) = delete;
+bool operator<=(int, A) = delete;
+bool operator>(int, A) = delete;
+bool operator>=(int, A) = delete;
+
+template void f<int>();

Reply via email to