On 9/9/25 4:36 AM, Patrick Palka wrote:
Bootstrapped and regttested on x86_64-pc-linux-gnu, does this look OK for trunk?
OK.
-- >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>();
