build_unary_op strips an EXCESS_PRECISION_EXPR from its operand and wraps
the result in one again, but the result of ! is int.  So with _Float16
(or float with x87 excess precision), !(x - y) kept the type of x - y:
sizeof and _Generic saw _Float16, ?: ICEd in build_conditional_expr,
and !(x - y) / 2 ICEd at expand.  Do not re-wrap the result of
TRUTH_NOT_EXPR; the operand is still tested at its excess precision, as
for (x - y) == 0.

Bootstrapped and regression tested on x86_64-pc-linux-gnu.  On
aarch64-linux-gnu (qemu, SVE VL128), regression tested dg.exp,
aarch64.exp and the SVE tests; the SVE tests also at VL2048.  Tested
together with the two PR121105 patches and an earlier version of the
tests; the final gcc.dg/pr123370.c was compiled and run on
aarch64-linux-gnu (qemu), gcc.target/i386/pr123370.c run on
x86_64-pc-linux-gnu with -m32.

Assisted-by: Claude Opus 5 (Anthropic)

        PR c/123370

gcc/c/ChangeLog:

        * c-typeck.cc (build_unary_op) <case TRUTH_NOT_EXPR>: Clear eptype.

gcc/testsuite/ChangeLog:

        * gcc.dg/pr123370.c: New test.
        * gcc.target/i386/pr123370.c: New test.

Signed-off-by: Dominic P <[email protected]>
---
The _Float16 ICE goes back to GCC 7 at least (per the PR); the float one
needs -m32 -mfpmath=387 -fexcess-precision=standard.

OK for trunk?

 gcc/c/c-typeck.cc                        |  1 +
 gcc/testsuite/gcc.dg/pr123370.c          | 36 ++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr123370.c | 25 ++++++++++++++++
 3 files changed, 62 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr123370.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr123370.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 9b01f3daec9..97456869101 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -5986,6 +5986,7 @@ build_unary_op (location_t location, enum tree_code code, 
tree xarg,
       else
        arg = c_objc_common_truthvalue_conversion (location, arg);
       ret = invert_truthvalue_loc (location, arg);
+      eptype = NULL_TREE;
       /* If the TRUTH_NOT_EXPR has been folded, reset the location.  */
       if (EXPR_P (ret) && EXPR_HAS_LOCATION (ret))
        location = EXPR_LOCATION (ret);
diff --git a/gcc/testsuite/gcc.dg/pr123370.c b/gcc/testsuite/gcc.dg/pr123370.c
new file mode 100644
index 00000000000..bd205e8d9a4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr123370.c
@@ -0,0 +1,36 @@
+/* PR c/123370 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fexcess-precision=standard" } */
+/* { dg-add-options float16 } */
+/* { dg-require-effective-target float16_runtime } */
+
+volatile _Float16 x = 3, y = 1;
+
+_Static_assert (_Generic (!(x - y), int: 1, default: 0), "");
+_Static_assert (sizeof (!(x - y)) == sizeof (int), "");
+
+__attribute__((noipa)) int
+f1 (void)
+{
+  return (y == x) ? (y + 1) : !(x - y);
+}
+
+__attribute__((noipa)) int
+f2 (int c)
+{
+  return c ? !(x - y) : !!(x - y);
+}
+
+__attribute__((noipa)) float
+f3 (void)
+{
+  return !(x - x) / 2;
+}
+
+int
+main (void)
+{
+  if (f1 () != 0 || f2 (1) != 0 || f2 (0) != 1 || f3 () != 0)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr123370.c 
b/gcc/testsuite/gcc.target/i386/pr123370.c
new file mode 100644
index 00000000000..21410c8c9fb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr123370.c
@@ -0,0 +1,25 @@
+/* PR c/123370 */
+/* { dg-do compile { target ia32 } } */
+/* { dg-options "-O2 -mfpmath=387 -fexcess-precision=standard" } */
+
+float x, y;
+
+_Static_assert (_Generic (!(x - y), int: 1, default: 0), "");
+
+int
+f1 (int c)
+{
+  return c ? (y + 1) : !(x - y);
+}
+
+int
+f2 (int c)
+{
+  return c ? !(x - y) : !!(x - y);
+}
+
+float
+f3 (void)
+{
+  return !(x - y) / 2;
+}
-- 
2.56.0

Reply via email to