zig
zig copied to clipboard
Proposal: don't allow unused bits in packed unions
Currently it is valid to do:
const U = packed union {
x: u8,
y: u16,
};
However, there is not plainly one possible way of mapping this representation to bits, a feature of other packed types that seems desirable. For example, enum (u5) { ... }
plainly represents 5 bits in an obvious manner and is allowed in packed contexts, but ?u8
has two reasonable ways of mapping to 9 bits and is not allowed in packed contexts.
My proposal for resolving this ambiguity is to require all fields of a packed union to have the same @bitSizeOf
as a required backing integer type. The above type is still representable as:
const U = packed union(u16) {
x: packed struct(u16) {
used: u8,
unused: u8 = undefined,
},
y: u16,
};
But this type now has the benefit of being explicit about the order of the unused bits and therefore only has one reasonable bitwise representation. Also, depending on how #19634 is resolved, this explicitness could be very important as having an undefined
field in a packed container may become much less useful in the future, and it may be necessary to initialize to 0
instead for many use cases. To that end, this proposal encourages that explicit thought is put into how the padding bits should be defined.
Related:
- #19660
A small change I propose is to instead of requiring them to have the same @bitSizeOf
, which could lead to some weird behaviour and error messages like in cases such as:
const U = packed union {
a: u7,
b: u8,
c: u8,
d: u9,
}
What would the error here be? Either
- it would resolve to being
u8
as the majority, andu7
andu9
are wrong - it'll coerce to the largest size which might not be desired
Instead I think it makes more sense to unify the current semantics, and have packed struct(u8)
and packed union(u8)
, and the "same @bitSizeOf
" must match the provided backing int.
and have packed struct(u8) and packed union(u8)
Actually, thinking about it some more, this should definitely be a requirement for many different reasons. The most obvious is that an 8-bit packed union
should be allowed in callconv(.C)
function parameters, but the C abi of u8
and i8
differ, so the user needs to specify which one to use!
Can multiple unused fields use _
as their field name provided that they have a default initialization value?
#19395 seems relevant here