diff options
| author | Techcable <Techcable@techcable.net> | 2022-09-04 17:16:26 -0700 |
|---|---|---|
| committer | Techcable <Techcable@techcable.net> | 2022-10-01 15:22:10 -0700 |
| commit | 5b689d389fa50070c08520cdb6296dda3ad78a62 (patch) | |
| tree | 284c79f96a6ed88db8c68825bed2a4152412a0c4 /lib/std/build | |
| parent | 34835bbbcfe81cc87e823d14dc9b25e698ad5edc (diff) | |
| download | zig-5b689d389fa50070c08520cdb6296dda3ad78a62.tar.gz zig-5b689d389fa50070c08520cdb6296dda3ad78a62.zip | |
translate-c: packed struct implies align(1) on every field
Superceeds PR #12735 (now supporting all packed structs in GNU C)
Fixes issue #12733
This stops translating C packed struct as a Zig packed struct.
Instead use a regular `extern struct` with `align(1)`.
This is because (as @Vexu explained) Zig packed structs are really just integers (not structs).
Alignment issue is more complicated. I think @ifreund was the
first to notice it in his comment on PR #12735
Justification of my interpretion of the C(lang) behavior
comes from a careful reading of the GCC docs for type & variable attributes:
(clang emulates gnu's packed attribute here)
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], states:
> 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 (wierdly under "variables" section)]:
> 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.
Furthermore, alignment is the only effect of the packed attribute mentioned in the GCC docs (for "common" architecture).
Based on this, it seems safe to completely substitute C 'packed' with Zig 'align(1)'.
Target-specific or undocumented behavior potentially changes this.
Unfortunately, the current implementation of `translate-c` translates as
`packed struct` without alignment info.
Because Zig packed structs are really integers (as mentioned above),
they are the wrong interpretation and we should be using 'extern struct'.
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));
```
Previously used a 'packed struct' (which was not FFI-safe on stage1).
After applying this change, the translated structures have align(1)
explicitly applied to all of their fields AS EXPECTED (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 = extern struct {
a: u8 align(1),
b: c_int align(1),
};
pub const struct_bar = extern struct {
a: u8 align(1),
b: c_int align(1),
c: c_short align(1),
d: c_long align(8),
};
```
Also note for reference: 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
Suggsestive both to the change to an integer-backed representation
which is incompatible with C's notation.
Diffstat (limited to 'lib/std/build')
0 files changed, 0 insertions, 0 deletions
