[clang] [Clang] Fix oversized bit-field layout on big-endian targets (PR #225494)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Sep 30 00:10:48 PDT 2026
================
@@ -15917,12 +15917,15 @@ struct PaddingCalculator {
const uint64_t DeclaredSizeInBits = Field->getBitWidthValue();
- // Handle over-sized bitfields:
- // unsigned char a : 12;
- // In this case, DeclaredSizeInBits is 12, but the actually occupied bit
- // size is 8, while the remaining 4 bits are padding.
+ // Oversized bit-fields (declared width larger than the field type) keep
+ // only the type's width as the value container. The extra declared bits
+ // are padding and follow that container (Itanium C++ ABI ยง2.4, II.1(b)).
+ // getIntWidth may be narrower still (bool, _BitInt); those occupied bits
+ // are the low-order bits of the value container.
+ const uint64_t ValueFieldBits =
+ std::min(DeclaredSizeInBits, Ctx.getTypeSize(Field->getType()));
const uint64_t OccupiedSizeInBits =
- std::min(DeclaredSizeInBits,
+ std::min(ValueFieldBits,
static_cast<uint64_t>(Ctx.getIntWidth(Field->getType())));
----------------
xiongzile wrote:
> The code is wrong in the case of oversized bitfield of the `_BitInt` type. See this example:
>
> ```c
> struct S {
> _BitInt(5) a : 6;
> };
>
> void foo(struct S *arg) {
> __builtin_clear_padding(arg);
> }
> ```
>
> The clearing is lowered like this:
>
> ```assembly
> ldrb r1, [r0]
> and r1, r1, #124
> strb r1, [r0]
> ```
>
> which still assumes that the padding is allocated before the occupied bits. Remember that in BE the allocation is from MSB to LSB. I'd expect the and to be done with `#248` (`1111 1000`).
But CodeGen currently stores the value in the low 5 bits of the 6-bit field, i.e. `01111100`, not `11111000`
Also GCC doesn't support `_BitInt(5) a: 6`, so I'm not sure which we should prefer...?
https://github.com/llvm/llvm-project/pull/225494
More information about the cfe-commits
mailing list