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>();
