Bootstrapped and regttested on x86_64-pc-linux-gnu, does this look
OK for trunk?
-- >8 --
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 handle a (x <=> y) @ 0 expression where the @ resolved to a built-in
operator rather than an overload.
PR c++/121779
gcc/cp/ChangeLog:
* tree.cc (build_min_non_dep_op_overload): Handle comparison
operators rewritten from a <=> that returns a non-class type.
gcc/testsuite/ChangeLog:
* g++.dg/lookup/operator-8.C: Remove obsolete comment about
this test failing.
* g++.dg/lookup/operator-8a.C: New test.
---
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(-)
create mode 100644 gcc/testsuite/g++.dg/lookup/operator-8a.C
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index e354da0f0185..e8e0799396e2 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)
+ {
+ if (reversed)
+ std::swap (op0, op1);
+ gcc_checking_assert (COMPARISON_CLASS_P (non_dep));
+ 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>();
--
2.51.0.167.g6ad8021821