https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127383
Jakub Jelinek <jakub at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jsm28 at gcc dot gnu.org
--- Comment #4 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
This is a mess.
I've tried:
--- a/gcc/c/c-convert.cc 2026-03-27 10:17:13.726337397 +0100
+++ b/gcc/c/c-convert.cc 2026-09-14 15:20:29.220977603 +0200
@@ -86,7 +86,21 @@ c_convert (tree type, tree expr, bool in
}
if (type == TREE_TYPE (expr))
- return expr;
+ {
+ /* Don't optimize away cast of a bit-precise integer bit-field to
+ its unpromoted type, because we could then try to perform
+ integer promotions on it again. */
+ if (TREE_CODE (expr) == COMPONENT_REF
+ && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1))
+ && BITINT_TYPE_P (type)
+ && BITINT_TYPE_P (DECL_BIT_FIELD_TYPE (TREE_OPERAND (expr, 1))))
+ {
+ tree btype = DECL_BIT_FIELD_TYPE (TREE_OPERAND (expr, 1));
+ if (btype != type)
+ return non_lvalue_loc (loc, expr);
+ }
+ return expr;
+ }
ret = targetm.convert_to_type (type, expr);
if (ret)
return ret;
--- a/gcc/c/c-typeck.cc 2026-08-17 10:00:21.658857069 +0200
+++ b/gcc/c/c-typeck.cc 2026-09-14 17:02:03.305443443 +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;
}
--- a/gcc/testsuite/gcc.dg/torture/bitint-108.c 2026-09-14 15:36:50.839136669
+0200
+++ b/gcc/testsuite/gcc.dg/torture/bitint-108.c 2026-09-14 15:36:35.910331972
+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
+}
but that breaks
FAIL: gcc.dg/bitint-136.c (test for excess errors)
FAIL: gcc.dg/bitint-17.c (test for excess errors)
FAIL: gcc.dg/torture/bitint-68.c -O0 execution test
FAIL: gcc.dg/torture/bitint-68.c -O2 execution test
Apparently there is a difference between an explicit cast like what happens in
the new bitint-108.c and an implicitly added cast like what happens e.g. on the
bitint-17.c testcase (convert_lvalue_to_rvalue -> convert -> c_convert).
The explicit cast case also calls convert_lvalue_to_rvalue -> convert ->
c_convert and then c_cast_expr.
Joseph, any thoughts of this?
Perhaps I should completely remove the c-convert.cc part and in c-typeck.cc
look through casts as long as there is no NON_LVALUE_EXPR among them?