-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Preamble
After some internal discussion, this proposal has been extracted from the accepted #19754, which previously included the part of this proposal pertaining to packed unions. Unlike #19754, this proposal is not yet accepted, and is a more contentious change. Personally, I'm not actually sure whether I think this is a good idea -- the more I think about it, the more I lean towards "no" -- but this issue is opened for discussion and consideration.
Background
When defining packed structs and (after #19754 is implemented) packed unions, you can provide a "backing integer type": a fixed-width integer type which the type has identical layout and ABI representation to. For a packed struct, the compiler checks that the total size of the fields matches the size of the specified backing integer type. For a packed union, the compiler checks that the size of every field matches the size of the specified backing integer type.
If the backing integer type is not specified, the Zig compiler infers it based on the sizes of the fields. Under the accepted #24714, those types are not allowed in extern contexts, because their ABI representation (in particular, their function parameter calling convention) is quite implicit, which is not safe.
An argument could be made that these types not being extern compatible is one particular case of a more general problem: packed aggregates exist to lay out bits in a well-defined way, and yet we are determining a crucial part of the representation implicitly, in a way which can cause footguns like ABI differences. That gives rise to this proposal:
Proposal
Always require an explicit backing integer type to be specified for packed structs and packed unions. packed struct { ... } and packed union { ... } become syntax errors; you must write packed struct(T) { ... } and packed union(T) { ... } respectively. Likewise, require the backing_integer to be non-null when reifying such types with @Type .
Notably, this proposal would effectively supersede most of #24714, because packed structs/unions could not have implicit backing types to begin with.
The logic here could also be applied to enums, so that enum { ... } is disallowed in favour of enum(T) { ... }. That might also imply disallowing union(enum) { ... }in favour of union(enum(T)) { ... }. This proposal does not propose these changes -- I personally think they would definitely be going too far, so if we do want to consider that change, it should be a separate proposal.