Tested on x86_64-pc-linux-gnu, does this look OK for trunk/16?

-- >8 --

When a user operator<=> returns an integral type smaller than int, the
rewritten form of x @ y contains an integer promotion: (int)(x <=> y) @ 0.

This patch teaches build_min_non_dep_op_overload to look through and
preserve this implicit cast.

        PR c++/125378

gcc/cp/ChangeLog:

        * tree.cc (build_min_non_dep_op_overload): Handle comparison
        operator expressions rewritten from a <=> that contain an
        integer promotion.

gcc/testsuite/ChangeLog:

        * g++.dg/lookup/operator-8b.C: New test.
        * g++.dg/lookup/operator-8c.C: New test.
        * g++.dg/lookup/operator-9a.C: New test.
        * g++.dg/lookup/operator-9b.C: New test.
---
 gcc/cp/tree.cc                            | 13 ++++++++
 gcc/testsuite/g++.dg/lookup/operator-8b.C | 40 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/operator-8c.C | 40 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/lookup/operator-9a.C | 19 +++++++++++
 gcc/testsuite/g++.dg/lookup/operator-9b.C | 19 +++++++++++
 5 files changed, 131 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/lookup/operator-8b.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/operator-8c.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/operator-9a.C
 create mode 100644 gcc/testsuite/g++.dg/lookup/operator-9b.C

diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 02a62f78511c..8af3bd6f4641 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -3855,6 +3855,17 @@ build_min_non_dep_op_overload (enum tree_code op,
          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));
+
+         bool int_promotion = false;
+         if (TREE_CODE (spaceship_non_dep) == NOP_EXPR)
+           {
+             gcc_checking_assert (TREE_CODE (non_dep) != CALL_EXPR);
+             gcc_checking_assert (TREE_TYPE (spaceship_non_dep)
+                                  == integer_type_node);
+             spaceship_non_dep = TREE_OPERAND (spaceship_non_dep, 0);
+             int_promotion = true;
+           }
+
          gcc_checking_assert (TREE_CODE (spaceship_non_dep) == CALL_EXPR);
          tree spaceship_op0 = va_arg (p, tree);
          tree spaceship_op1 = va_arg (p, tree);
@@ -3877,6 +3888,8 @@ build_min_non_dep_op_overload (enum tree_code op,
            {
              gcc_checking_assert (COMPARISON_CLASS_P (non_dep)
                                   || TREE_CODE (non_dep) == SPACESHIP_EXPR);
+             if (int_promotion)
+               op0 = build_nop (integer_type_node, op0);
              if (reversed)
                std::swap (op0, op1);
              return build_min_non_dep (TREE_CODE (non_dep), non_dep, op0, op1);
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8b.C 
b/gcc/testsuite/g++.dg/lookup/operator-8b.C
new file mode 100644
index 000000000000..e08e879b08b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-8b.C
@@ -0,0 +1,40 @@
+// PR c++/125378
+// A version of operator-8a.C where the operator<=> returns char instead of 
int.
+
+// { dg-do compile { target c++20 } }
+
+struct A {
+  bool operator==(int);
+  char 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>();
diff --git a/gcc/testsuite/g++.dg/lookup/operator-8c.C 
b/gcc/testsuite/g++.dg/lookup/operator-8c.C
new file mode 100644
index 000000000000..251c516cc348
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-8c.C
@@ -0,0 +1,40 @@
+// PR c++/125378
+// A version of operator-8a.C where the operator<=> returns long instead of 
int.
+
+// { dg-do compile { target c++20 } }
+
+struct A {
+  bool operator==(int);
+  long 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>();
diff --git a/gcc/testsuite/g++.dg/lookup/operator-9a.C 
b/gcc/testsuite/g++.dg/lookup/operator-9a.C
new file mode 100644
index 000000000000..ba49c8100e57
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-9a.C
@@ -0,0 +1,19 @@
+// PR c++/125378
+// A version of operator-9.C where the operator<=> returns char instead of int.
+
+// { dg-do compile { target c++20 } }
+
+#include <compare>
+
+struct A {
+  bool operator==(int);
+  char operator<=>(int);
+};
+
+template<class T>
+void f() {
+  A a;
+  (void)(0 <=> a);
+}
+
+template void f<int>();
diff --git a/gcc/testsuite/g++.dg/lookup/operator-9b.C 
b/gcc/testsuite/g++.dg/lookup/operator-9b.C
new file mode 100644
index 000000000000..2a46e49c9938
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/operator-9b.C
@@ -0,0 +1,19 @@
+// PR c++/125378
+// A version of operator-9.C where the operator<=> returns long instead of int.
+
+// { dg-do compile { target c++20 } }
+
+#include <compare>
+
+struct A {
+  bool operator==(int);
+  long operator<=>(int);
+};
+
+template<class T>
+void f() {
+  A a;
+  (void)(0 <=> a);
+}
+
+template void f<int>();
-- 
2.54.0.rc1.54.g60f07c4f5c

Reply via email to