| author | |
| committer | |
| log | fb523c6283be546369250b9172aad040d44f42dd |
| tree | cc0c2a6462ca1bcf91f5994f45e2e301e51318d1 |
| parent | 4d044ee7e0b1ca61b8f2205f318449780ae23bd2 |
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 | } |
| 695 | 695 | ||
| 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 | } |
| 701 | 701 | ||
| 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 order | 2965 | /// 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_layout | 2968 | /// Only valid after .have_layout |
| 2969 | size: u32, | 2969 | size: u32, |
| 2970 | // Only valid after .have_layout | 2970 | /// 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 | }; |
| 2990 | 2991 |
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 an | 34942 | // We'll guess "pointer-aligned", if the union has an |
| 34941 | // underaligned pointer field then some allocations | 34943 | // 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 | } |
| 34945 | 34950 | ||
| 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 | } |
| 35068 | 35085 | ||
| 35069 | /// Returns `error.AnalysisFail` if any of the types (recursively) failed to | 35086 | /// 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; // TODO | 1868 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO |
| 1869 | try S.doTheTest(); | 1869 | try S.doTheTest(); |
| 1870 | } | 1870 | } |
| 1871 | |||
| 1872 | test "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 | } |