Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
translate-c: packed struct implies align(1) on every field
This is relevant to the fix in #12735 , but also fixes stage1. This comes from a careful reading of the GCC docs for type & variable attributes. The final line of the documentation for __attribute__ ((aligned)) [on types] says: > When used on a struct, or struct member, *the aligned attribute can only increase the alignment*; in order to decrease it, the packed attribute must be specified as well. This implies that GCC uses the `packed` attribute for alignment purposes in addition to eliminating padding. The documentation for __attribute__((packed)) [on types], does not directly state this relationship with alignment. However, it *does* say that the 'packed' attribute is applied recursively to each member. > This attribute, attached to a struct, union, or C++ class type definition, specifies that each of its members (other than zero-width bit-fields) is placed to minimize the memory required. **This is equivalent to specifying the packed attribute on each of the members**. The key is resolving this indirection, and looking at the documentation for __attribute__((packed)) [on fields]: > The packed attribute specifies that a **structure member should have the smallest possible alignment** — one bit for a bit-field and one byte otherwise, unless a larger value is specified with the aligned attribute. The attribute does not apply to non-member objects. (NOTE: Somewhat confusingly, field attributes are documented under "variables") This means that a C structure with __attribute__((packed)) automatically implies align(1) on each of its member. Unfortunately, the current implementation of `translate-c` does not reflect this. Running `translate-c` on the following code: ```c struct foo { char a; int b; } __attribute__((packed)); struct bar { char a; int b; short c; __attribute__((aligned(8))) long d; } __attribute__((packed)); ``` does not apply any alignment attributes to any fields except d. Sometimes __attribute__((packed)) is used only for alignment purposes. It is a semi-portable way to do unaligned stores. In particular, the aarch64-macos.12 headers do this in stdlib.h This was noted by @ifreund in the discussion of PR #12735 The structures in the MacOS headers were being used chiefly for their alignment properties, not for padding purposes (they only had one field). After applying this change, the translated structures have align(1) explicitly applied to all of their fields (unless explicitly overriden). This makes Zig behavior for `tranlsate-c` consistent with clang/GCC. Here is the newly produced (correct) output for the above example: ```zig pub const struct_foo = packed struct { a: u8 align(1), b: c_int align(1), }; pub const struct_bar = packed struct { a: u8 align(1), b: c_int align(1), c: c_short align(1), d: c_long align(8), }; ``` This is closely related with PR #12735 Since the last stable release (0.9.1), there was a **change in the language spec** related to the alignment of packed structures. The docs for Zig 0.9.1 read: > Packed structs have 1-byte alignment. So the old behavior of translate-c (not specifying any alignment) was possibly correct back then. However the current docs read: > Packed structs have the same alignment as their backing integer So now `translate-c` definitely needs to specify align(1) for every field (unless the spec is overriden).
- Loading branch information