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) {...@@ -690,13 +690,13 @@ pub const Key = union(enum) {
690 /// The returned pointer expires with any addition to the `InternPool`.690 /// The returned pointer expires with any addition to the `InternPool`.
691 pub fn size(self: @This(), ip: *InternPool) *u32 {691 pub fn size(self: @This(), ip: *InternPool) *u32 {
692 const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;692 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];
694 }694 }
695695
696 /// The returned pointer expires with any addition to the `InternPool`.696 /// The returned pointer expires with any addition to the `InternPool`.
697 pub fn padding(self: @This(), ip: *InternPool) *u32 {697 pub fn padding(self: @This(), ip: *InternPool) *u32 {
698 const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;698 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];
700 }700 }
701701
702 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {702 pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool {
...@@ -2965,9 +2965,9 @@ pub const Tag = enum(u8) {...@@ -2965,9 +2965,9 @@ pub const Tag = enum(u8) {
2965 /// 1. field align: Alignment for each field; declaration order2965 /// 1. field align: Alignment for each field; declaration order
2966 pub const TypeUnion = struct {2966 pub const TypeUnion = struct {
2967 flags: Flags,2967 flags: Flags,
2968 // Only valid after .have_layout2968 /// Only valid after .have_layout
2969 size: u32,2969 size: u32,
2970 // Only valid after .have_layout2970 /// Only valid after .have_layout
2971 padding: u32,2971 padding: u32,
2972 decl: Module.Decl.Index,2972 decl: Module.Decl.Index,
2973 namespace: Module.Namespace.Index,2973 namespace: Module.Namespace.Index,
...@@ -2983,8 +2983,9 @@ pub const Tag = enum(u8) {...@@ -2983,8 +2983,9 @@ pub const Tag = enum(u8) {
2983 status: UnionType.Status,2983 status: UnionType.Status,
2984 requires_comptime: RequiresComptime,2984 requires_comptime: RequiresComptime,
2985 assumed_runtime_bits: bool,2985 assumed_runtime_bits: bool,
2986 assumed_pointer_aligned: bool,
2986 alignment: Alignment,2987 alignment: Alignment,
2987 _: u15 = 0,2988 _: u14 = 0,
2988 };2989 };
2989 };2990 };
29902991
src/Sema.zig+18-1
...@@ -3200,6 +3200,7 @@ fn zirUnionDecl(...@@ -3200,6 +3200,7 @@ fn zirUnionDecl(
3200 .any_aligned_fields = small.any_aligned_fields,3200 .any_aligned_fields = small.any_aligned_fields,
3201 .requires_comptime = .unknown,3201 .requires_comptime = .unknown,
3202 .assumed_runtime_bits = false,3202 .assumed_runtime_bits = false,
3203 .assumed_pointer_aligned = false,
3203 .alignment = .none,3204 .alignment = .none,
3204 },3205 },
3205 .decl = new_decl_index,3206 .decl = new_decl_index,
...@@ -20989,6 +20990,7 @@ fn zirReify(...@@ -20989,6 +20990,7 @@ fn zirReify(
20989 .any_aligned_fields = any_aligned_fields,20990 .any_aligned_fields = any_aligned_fields,
20990 .requires_comptime = .unknown,20991 .requires_comptime = .unknown,
20991 .assumed_runtime_bits = false,20992 .assumed_runtime_bits = false,
20993 .assumed_pointer_aligned = false,
20992 .alignment = .none,20994 .alignment = .none,
20993 },20995 },
20994 .field_types = union_fields.items(.type),20996 .field_types = union_fields.items(.type),
...@@ -34940,7 +34942,10 @@ pub fn resolveUnionAlignment(...@@ -34940,7 +34942,10 @@ pub fn resolveUnionAlignment(
34940 // We'll guess "pointer-aligned", if the union has an34942 // We'll guess "pointer-aligned", if the union has an
34941 // underaligned pointer field then some allocations34943 // underaligned pointer field then some allocations
34942 // might require explicit alignment.34944 // 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;
34944 }34949 }
3494534950
34946 try sema.resolveTypeFieldsUnion(ty, union_type);34951 try sema.resolveTypeFieldsUnion(ty, union_type);
...@@ -35064,6 +35069,18 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {...@@ -35064,6 +35069,18 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35064 );35069 );
35065 return sema.failWithOwnedErrorMsg(null, msg);35070 return sema.failWithOwnedErrorMsg(null, msg);
35066 }35071 }
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 }
35067}35084}
3506835085
35069/// Returns `error.AnalysisFail` if any of the types (recursively) failed to35086/// 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" {...@@ -1868,3 +1868,16 @@ test "reinterpret packed union inside packed struct" {
1868 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1868 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1869 try S.doTheTest();1869 try S.doTheTest();
1870}1870}
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}