From fb523c6283be546369250b9172aad040d44f42dd Mon Sep 17 00:00:00 2001 From: kcbanner Date: Tue, 24 Oct 2023 01:44:44 -0400 Subject: [PATCH] sema: when guessing union alignment, save the result and check if the guess was correct --- src/InternPool.zig | 11 ++++++----- src/Sema.zig | 19 ++++++++++++++++++- test/behavior/union.zig | 13 +++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index a4fefaba29..700c5859b8 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -690,13 +690,13 @@ pub const Key = union(enum) { /// The returned pointer expires with any addition to the `InternPool`. pub fn size(self: @This(), ip: *InternPool) *u32 { const size_field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?; - return @ptrCast(&ip.extra.items[self.extra_index + size_field_index]); + return &ip.extra.items[self.extra_index + size_field_index]; } /// The returned pointer expires with any addition to the `InternPool`. pub fn padding(self: @This(), ip: *InternPool) *u32 { const padding_field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?; - return @ptrCast(&ip.extra.items[self.extra_index + padding_field_index]); + return &ip.extra.items[self.extra_index + padding_field_index]; } pub fn haveFieldTypes(self: @This(), ip: *const InternPool) bool { @@ -2965,9 +2965,9 @@ pub const Tag = enum(u8) { /// 1. field align: Alignment for each field; declaration order pub const TypeUnion = struct { flags: Flags, - // Only valid after .have_layout + /// Only valid after .have_layout size: u32, - // Only valid after .have_layout + /// Only valid after .have_layout padding: u32, decl: Module.Decl.Index, namespace: Module.Namespace.Index, @@ -2983,8 +2983,9 @@ pub const Tag = enum(u8) { status: UnionType.Status, requires_comptime: RequiresComptime, assumed_runtime_bits: bool, + assumed_pointer_aligned: bool, alignment: Alignment, - _: u15 = 0, + _: u14 = 0, }; }; diff --git a/src/Sema.zig b/src/Sema.zig index c83ef222c0..2956f6eaec 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -3200,6 +3200,7 @@ fn zirUnionDecl( .any_aligned_fields = small.any_aligned_fields, .requires_comptime = .unknown, .assumed_runtime_bits = false, + .assumed_pointer_aligned = false, .alignment = .none, }, .decl = new_decl_index, @@ -20989,6 +20990,7 @@ fn zirReify( .any_aligned_fields = any_aligned_fields, .requires_comptime = .unknown, .assumed_runtime_bits = false, + .assumed_pointer_aligned = false, .alignment = .none, }, .field_types = union_fields.items(.type), @@ -34940,7 +34942,10 @@ pub fn resolveUnionAlignment( // We'll guess "pointer-aligned", if the union has an // underaligned pointer field then some allocations // might require explicit alignment. - return Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); + union_type.flagsPtr(ip).assumed_pointer_aligned = true; + const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8)); + union_type.flagsPtr(ip).alignment = result; + return result; } try sema.resolveTypeFieldsUnion(ty, union_type); @@ -35064,6 +35069,18 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { ); return sema.failWithOwnedErrorMsg(null, msg); } + + if (union_obj.flagsPtr(ip).assumed_pointer_aligned and + alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8)))) + { + const msg = try Module.ErrorMsg.create( + sema.gpa, + mod.declPtr(union_obj.decl).srcLoc(mod), + "union layout depends on being pointer aligned", + .{}, + ); + return sema.failWithOwnedErrorMsg(null, msg); + } } /// Returns `error.AnalysisFail` if any of the types (recursively) failed to diff --git a/test/behavior/union.zig b/test/behavior/union.zig index ebfde8899e..5e89bca0a3 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1868,3 +1868,16 @@ test "reinterpret packed union inside packed struct" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO try S.doTheTest(); } + +test "union field is a pointer to an aligned version of itself" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + + const E = union { + next: *align(1) @This(), + }; + var e: E = undefined; + e = .{ .next = &e }; + + try expect(&e == e.next); +}