mirror of
https://github.com/ziglang/zig.git
synced 2026-02-15 13:58:27 +00:00
sema: when guessing union alignment, save the result and check if the guess was correct
This commit is contained in:
parent
4d044ee7e0
commit
fb523c6283
@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
19
src/Sema.zig
19
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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user