authorgravatar for kcbanner@gmail.comCasey Banner <kcbanner@gmail.com> 2023-10-24 01:44:44-04:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2023-10-31 01:35:58+00:00
logfb523c6283be546369250b9172aad040d44f42dd
treecc0c2a6462ca1bcf91f5994f45e2e301e51318d1
parent4d044ee7e0b1ca61b8f2205f318449780ae23bd2

sema: when guessing union alignment, save the result and check if the guess was correct


3 files changed, 37 insertions(+), 6 deletions(-)

src/InternPool.zig+6-5
......@@ -690,13 +690,13 @@ pub const Key = union(enum) {
690690 /// The returned pointer expires with any addition to the `InternPool`.
691691 pub fn size(self: @This(), ip: *InternPool) *u32 {
692692 const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;
693 return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]);
693 return &ip.extra.items[self.extra_index + size_field_index];
694694 }
695695
696696 /// The returned pointer expires with any addition to the `InternPool`.
697697 pub fn padding(self: @This(), ip: *InternPool) *u32 {
698698 const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;
699 return @ptrCast(&ip.extra.items[self.extra_index + padding_field_index]);
699 return &ip.extra.items[self.extra_index + padding_field_index];
700700 }
701701
702702 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {
......@@ -2965,9 +2965,9 @@ pub const Tag = enum(u8) {
29652965 /// 1. field align: Alignment for each field; declaration order
29662966 pub const TypeUnion = struct {
29672967 flags: Flags,
2968 // Only valid after .have_layout
2968 /// Only valid after .have_layout
29692969 size: u32,
2970 // Only valid after .have_layout
2970 /// Only valid after .have_layout
29712971 padding: u32,
29722972 decl: Module.Decl.Index,
29732973 namespace: Module.Namespace.Index,
......@@ -2983,8 +2983,9 @@ pub const Tag = enum(u8) {
29832983 status: UnionType.Status,
29842984 requires_comptime: RequiresComptime,
29852985 assumed_runtime_bits: bool,
2986 assumed_pointer_aligned: bool,
29862987 alignment: Alignment,
2987 _: u15 = 0,
2988 _: u14 = 0,
29882989 };
29892990 };
29902991
src/Sema.zig+18-1
......@@ -3200,6 +3200,7 @@ fn zirUnionDecl(
32003200 .any_aligned_fields = small.any_aligned_fields,
32013201 .requires_comptime = .unknown,
32023202 .assumed_runtime_bits = false,
3203 .assumed_pointer_aligned = false,
32033204 .alignment = .none,
32043205 },
32053206 .decl = new_decl_index,
......@@ -20989,6 +20990,7 @@ fn zirReify(
2098920990 .any_aligned_fields = any_aligned_fields,
2099020991 .requires_comptime = .unknown,
2099120992 .assumed_runtime_bits = false,
20993 .assumed_pointer_aligned = false,
2099220994 .alignment = .none,
2099320995 },
2099420996 .field_types = union_fields.items(.type),
......@@ -34940,7 +34942,10 @@ pub fn resolveUnionAlignment(
3494034942 // We'll guess "pointer-aligned", if the union has an
3494134943 // underaligned pointer field then some allocations
3494234944 // might require explicit alignment.
34943 return Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34945 union_type.flagsPtr(ip).assumed_pointer_aligned = true;
34946 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34947 union_type.flagsPtr(ip).alignment = result;
34948 return result;
3494434949 }
3494534950
3494634951 try sema.resolveTypeFieldsUnion(ty, union_type);
......@@ -35064,6 +35069,18 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3506435069 );
3506535070 return sema.failWithOwnedErrorMsg(null, msg);
3506635071 }
35072
35073 if (union_obj.flagsPtr(ip).assumed_pointer_aligned and
35074 alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8))))
35075 {
35076 const msg = try Module.ErrorMsg.create(
35077 sema.gpa,
35078 mod.declPtr(union_obj.decl).srcLoc(mod),
35079 "union layout depends on being pointer aligned",
35080 .{},
35081 );
35082 return sema.failWithOwnedErrorMsg(null, msg);
35083 }
3506735084}
3506835085
3506935086/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
test/behavior/union.zig+13
......@@ -1868,3 +1868,16 @@ test "reinterpret packed union inside packed struct" {
18681868 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
18691869 try S.doTheTest();
18701870}
1871
1872test "union field is a pointer to an aligned version of itself" {
1873 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1874 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1875
1876 const E = union {
1877 next: *align(1) @This(),
1878 };
1879 var e: E = undefined;
1880 e = .{ .next = &e };
1881
1882 try expect(&e == e.next);
1883}