diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2023-09-21 02:00:52 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-09-21 14:48:41 -0700 |
| commit | 1b672e41c528b0aa225cbe07c61203d04b2d9034 (patch) | |
| tree | 080cac4fbde495c9b216fac1cd67e84799740059 /test | |
| parent | cd242b7440e11d9997c33296b3974dfb1fbd5d95 (diff) | |
| download | zig-1b672e41c528b0aa225cbe07c61203d04b2d9034.tar.gz zig-1b672e41c528b0aa225cbe07c61203d04b2d9034.zip | |
InternPool,Sema,type,llvm: alignment fixes
This changeset fixes the handling of alignment in several places. The
new rules are:
* `@alignOf(T)` where `T` is a runtime zero-bit type is at least 1,
maybe greater.
* Zero-bit fields in `extern` structs *do* force alignment, potentially
offsetting following fields.
* Zero-bit fields *do* have addresses within structs which can be
observed and are consistent with `@offsetOf`.
These are not necessarily all implemented correctly yet (see disabled
test), but this commit fixes all regressions compared to master, and
makes one new test pass.
Diffstat (limited to 'test')
| -rw-r--r-- | test/behavior/align.zig | 55 | ||||
| -rw-r--r-- | test/behavior/alignof.zig | 25 | ||||
| -rw-r--r-- | test/behavior/empty_union.zig | 2 |
3 files changed, 63 insertions, 19 deletions
diff --git a/test/behavior/align.zig b/test/behavior/align.zig index e1a8fb8e98..c33f685325 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -619,3 +619,58 @@ test "sub-aligned pointer field access" { .Little => try expect(x == 0x09080706), } } + +test "alignment of zero-bit types is respected" { + if (true) return error.SkipZigTest; // TODO + + const S = struct { arr: [0]usize = .{} }; + + comptime assert(@alignOf(void) == 1); + comptime assert(@alignOf(u0) == 1); + comptime assert(@alignOf([0]usize) == @alignOf(usize)); + comptime assert(@alignOf(S) == @alignOf(usize)); + + var s: S = .{}; + var v32: void align(32) = {}; + var x32: u0 align(32) = 0; + var s32: S align(32) = .{}; + + var zero: usize = 0; + + try expect(@intFromPtr(&s) % @alignOf(usize) == 0); + try expect(@intFromPtr(&s.arr) % @alignOf(usize) == 0); + try expect(@intFromPtr(s.arr[zero..zero].ptr) % @alignOf(usize) == 0); + try expect(@intFromPtr(&v32) % 32 == 0); + try expect(@intFromPtr(&x32) % 32 == 0); + try expect(@intFromPtr(&s32) % 32 == 0); + try expect(@intFromPtr(&s32.arr) % 32 == 0); + try expect(@intFromPtr(s32.arr[zero..zero].ptr) % 32 == 0); +} + +test "zero-bit fields in extern struct pad fields appropriately" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + + const S = extern struct { + x: u8, + a: [0]u16 = .{}, + y: u8, + }; + + // `a` should give `S` alignment 2, and pad the `arr` field. + comptime assert(@alignOf(S) == 2); + comptime assert(@sizeOf(S) == 4); + comptime assert(@offsetOf(S, "x") == 0); + comptime assert(@offsetOf(S, "a") == 2); + comptime assert(@offsetOf(S, "y") == 2); + + var s: S = .{ .x = 100, .y = 200 }; + + try expect(@intFromPtr(&s) % 2 == 0); + try expect(@intFromPtr(&s.y) - @intFromPtr(&s.x) == 2); + try expect(@intFromPtr(&s.y) == @intFromPtr(&s.a)); + try expect(@fieldParentPtr(S, "a", &s.a) == &s); +} diff --git a/test/behavior/alignof.zig b/test/behavior/alignof.zig index b414b7e056..0443b2d6b3 100644 --- a/test/behavior/alignof.zig +++ b/test/behavior/alignof.zig @@ -18,24 +18,13 @@ test "@alignOf(T) before referencing T" { } test "comparison of @alignOf(T) against zero" { - { - const T = struct { x: u32 }; - try expect(!(@alignOf(T) == 0)); - try expect(@alignOf(T) != 0); - try expect(!(@alignOf(T) < 0)); - try expect(!(@alignOf(T) <= 0)); - try expect(@alignOf(T) > 0); - try expect(@alignOf(T) >= 0); - } - { - const T = struct {}; - try expect(@alignOf(T) == 0); - try expect(!(@alignOf(T) != 0)); - try expect(!(@alignOf(T) < 0)); - try expect(@alignOf(T) <= 0); - try expect(!(@alignOf(T) > 0)); - try expect(@alignOf(T) >= 0); - } + const T = struct { x: u32 }; + try expect(!(@alignOf(T) == 0)); + try expect(@alignOf(T) != 0); + try expect(!(@alignOf(T) < 0)); + try expect(!(@alignOf(T) <= 0)); + try expect(@alignOf(T) > 0); + try expect(@alignOf(T) >= 0); } test "correct alignment for elements and slices of aligned array" { diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index 1bdbf8e54b..16606b5785 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -37,7 +37,7 @@ test "switch on empty tagged union" { test "empty union" { const U = union {}; try expect(@sizeOf(U) == 0); - try expect(@alignOf(U) == 0); + try expect(@alignOf(U) == 1); } test "empty extern union" { |
