Hi!

The following testcases are miscompiled when a bit-precise integer
bit-field is explicitly cast to a non-cv-qualified bit-precise integer
(of the same signedness) with precision of the bit-field width.
We can then incorrectly apply an integer promotion of the bit-field
to the corresponding bit-precise integer, even when it shouldn't be
applied (because it is a cast rather than the bit-field itself).
Regardless of the cv-qualifications, the TREE_TYPE of the FIELD_DECLs
(and COMPONENT_REFs) is a cv-unqualified BITINT_TYPE.  We first call
convert to that type in convert_lvalue_to_rvalue and that doesn't change
anything.
If there is an explicit cast to the same type as the TREE_TYPE of
the COMPONENT_REF has, we usually wrap it into a NON_LVALUE_EXPR, because
the COMPONENT_REF is usually an lvalue (but as can be seen in the testcases,
not always).  So the second hunk makes sure to add NON_LVALUE_EXPR around
the COMPONENT_REF even in the (cast) foo ().a cases to distinguish it
from foo ().a.
The second change is in default_conversion, for the promotion of bit-fields
of bit-precise integer type we don't promote them if they are wrapped in
some cast or NON_LVALUE_EXPR (the function normally uses STRIP_TYPE_NOPS).

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 

2026-09-16  Jakub Jelinek  <[email protected]>

        PR c/127383
        * c-typeck.cc (default_conversion): If orig_expr is different
        from exp and exp is a bit-field of bit-precise integer type, call
        perform_integral_promotions on orig_exp rather than exp.
        (build_c_cast): Wrap in NON_LVALUE_EXPR not just lvalues, but
        also non-lvalue bit-fields of bit-precise integer type.

        * gcc.dg/torture/bitint-108.c: New test.
        * gcc.dg/bitint-143.c: New test.
        * gcc.dg/bitint-144.c: New test.

--- a/gcc/c/c-typeck.cc 2026-09-14 18:09:11.662013474 +0200
+++ b/gcc/c/c-typeck.cc 2026-09-15 12:48:07.213853939 +0200
@@ -2907,7 +2907,17 @@ default_conversion (tree exp)
     return convert (promoted_type, exp);
 
   if (INTEGRAL_TYPE_P (type))
-    return perform_integral_promotions (exp);
+    {
+      /* Avoid performing integral promotion of bit-precise integer
+        type bit-field to its corresponding bit-precise integer if
+        orig_exp is a cast to it to its underlying type.  */
+      if (orig_exp != exp
+         && TREE_CODE (exp) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (exp, 1))
+         && BITINT_TYPE_P (DECL_BIT_FIELD_TYPE (TREE_OPERAND (exp, 1))))
+       return perform_integral_promotions (orig_exp);
+      return perform_integral_promotions (exp);
+    }
 
   return exp;
 }
@@ -7673,7 +7683,12 @@ build_c_cast (location_t loc, tree type,
     }
 
   /* Don't let a cast be an lvalue.  */
-  if (lvalue_p (value))
+  if (lvalue_p (value)
+      /* Also, don't let a cast be a bit-field of a bit-precise integer type,
+        otherwise it could be incorrectly subject of integer promotions.  */
+      || (TREE_CODE (value) == COMPONENT_REF
+         && DECL_C_BIT_FIELD (TREE_OPERAND (value, 1))
+         && BITINT_TYPE_P (DECL_BIT_FIELD_TYPE (TREE_OPERAND (value, 1)))))
     value = non_lvalue_loc (loc, value);
 
   /* Don't allow the results of casting to floating-point or complex
--- a/gcc/testsuite/gcc.dg/torture/bitint-108.c 2026-09-15 12:12:22.187326991 
+0200
+++ b/gcc/testsuite/gcc.dg/torture/bitint-108.c 2026-09-15 12:12:22.187326991 
+0200
@@ -0,0 +1,16 @@
+/* PR c/127383 */
+/* { dg-do run { target bitint } } */
+
+#if __BITINT_MAXWIDTH__ >= 65
+struct { unsigned _BitInt(65) f : 63; } s;
+#endif
+
+int
+main ()
+{
+#if __SIZEOF_LONG_LONG__ * __CHAR_BIT__ == 64 && __BITINT_MAXWIDTH__ >= 65
+  unsigned long long w = ~(unsigned _BitInt(63)) s.f;
+  if (w != (-1ULL >> 1))
+    __builtin_abort ();
+#endif
+}
--- a/gcc/testsuite/gcc.dg/bitint-143.c 2026-09-15 12:57:57.790919968 +0200
+++ b/gcc/testsuite/gcc.dg/bitint-143.c 2026-09-15 13:03:42.837299132 +0200
@@ -0,0 +1,45 @@
+/* PR c/127383 */
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-std=c23" } */
+
+#define expr_has_type(e, t) _Generic (e, default : 0, t : 1)
+
+struct S { _BitInt(195) a : 193; const unsigned _BitInt(195) b : 193; volatile 
_BitInt(195) c : 193; const volatile unsigned _BitInt(195) d : 193; };
+struct S s;
+struct S foo ();
+static_assert (expr_has_type (+s.a, _BitInt(195)));
+static_assert (expr_has_type (+s.b, unsigned _BitInt(195)));
+static_assert (expr_has_type (+s.c, _BitInt(195)));
+static_assert (expr_has_type (+s.d, unsigned _BitInt(195)));
+static_assert (expr_has_type ((_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const _BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type ((volatile unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const volatile _BitInt(193)) s.c, 
_BitInt(193)));
+static_assert (expr_has_type ((const unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+foo ().a, _BitInt(195)));
+static_assert (expr_has_type (+foo ().b, unsigned _BitInt(195)));
+static_assert (expr_has_type (+foo ().c, _BitInt(195)));
+static_assert (expr_has_type (+foo ().d, unsigned _BitInt(195)));
+static_assert (expr_has_type ((_BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) foo ().b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((_BitInt(193)) foo ().c, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) foo ().b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) foo ().c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const _BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type ((volatile unsigned _BitInt(193)) foo ().b, 
unsigned _BitInt(193)));
+static_assert (expr_has_type ((const volatile _BitInt(193)) foo ().c, 
_BitInt(193)));
+static_assert (expr_has_type ((const unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));
--- a/gcc/testsuite/gcc.dg/bitint-144.c 2026-09-15 12:58:08.192780255 +0200
+++ b/gcc/testsuite/gcc.dg/bitint-144.c 2026-09-15 13:03:49.732206830 +0200
@@ -0,0 +1,47 @@
+/* PR c/127383 */
+/* { dg-do compile { target bitint } } */
+/* { dg-options "-std=c2y" } */
+
+#define expr_has_type(e, t) _Generic (e, default : 0, t : 1)
+enum E : _BitInt(195) { E0 = 0, E1 = 1, EM1 = -1 };
+enum F : unsigned _BitInt(195) { F0 = 0, F1 = 1 };
+
+struct S { enum E a : 193; const enum F b : 193; volatile enum E c : 193; 
const volatile enum F d : 193; };
+struct S s;
+struct S foo ();
+static_assert (expr_has_type (+s.a, _BitInt(195)));
+static_assert (expr_has_type (+s.b, unsigned _BitInt(195)));
+static_assert (expr_has_type (+s.c, _BitInt(195)));
+static_assert (expr_has_type (+s.d, unsigned _BitInt(195)));
+static_assert (expr_has_type ((_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const _BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type ((volatile unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const volatile _BitInt(193)) s.c, 
_BitInt(193)));
+static_assert (expr_has_type ((const unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) s.c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) s.d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+foo ().a, _BitInt(195)));
+static_assert (expr_has_type (+foo ().b, unsigned _BitInt(195)));
+static_assert (expr_has_type (+foo ().c, _BitInt(195)));
+static_assert (expr_has_type (+foo ().d, unsigned _BitInt(195)));
+static_assert (expr_has_type ((_BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) foo ().b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((_BitInt(193)) foo ().c, _BitInt(193)));
+static_assert (expr_has_type ((unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) foo ().b, unsigned 
_BitInt(193)));
+static_assert (expr_has_type (+(_BitInt(193)) foo ().c, _BitInt(193)));
+static_assert (expr_has_type (+(unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));
+static_assert (expr_has_type ((const _BitInt(193)) foo ().a, _BitInt(193)));
+static_assert (expr_has_type ((volatile unsigned _BitInt(193)) foo ().b, 
unsigned _BitInt(193)));
+static_assert (expr_has_type ((const volatile _BitInt(193)) foo ().c, 
_BitInt(193)));
+static_assert (expr_has_type ((const unsigned _BitInt(193)) foo ().d, unsigned 
_BitInt(193)));

        Jakub

Reply via email to