Sema: fix union init with zero size field

This commit is contained in:
Pavel Verigo 2024-01-30 11:20:23 +01:00 committed by GitHub
parent 1b5cbf0d08
commit a2ad8517ee
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 31 additions and 1 deletions

View File

@ -4624,6 +4624,8 @@ fn validateUnionInit(
// If the union is comptime, we want `first_block_index`
// to point at %c so that the bitcast becomes the last instruction in the block.
//
// Store instruction may be missing; if field type has only one possible value, this case is handled below.
//
// In the case of a comptime-known pointer to a union, the
// the field_ptr instruction is missing, so we have to pattern-match
// based only on the store instructions.
@ -4634,7 +4636,10 @@ fn validateUnionInit(
var init_val: ?Value = null;
while (block_index > 0) : (block_index -= 1) {
const store_inst = block.instructions.items[block_index];
if (store_inst.toRef() == field_ptr_ref) break;
if (store_inst.toRef() == field_ptr_ref) {
first_block_index = block_index;
break;
}
switch (air_tags[@intFromEnum(store_inst)]) {
.store, .store_safe => {},
else => continue,
@ -4659,6 +4664,11 @@ fn validateUnionInit(
const tag_ty = union_ty.unionTagTypeHypothetical(mod);
const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
const field_type = union_ty.unionFieldType(tag_val, mod).?;
if (try sema.typeHasOnePossibleValue(field_type)) |field_only_value| {
init_val = field_only_value;
}
if (init_val) |val| {
// Our task is to delete all the `field_ptr` and `store` instructions, and insert

View File

@ -381,6 +381,26 @@ test "union with only 1 field which is void should be zero bits" {
comptime assert(@sizeOf(ZeroBits) == 0);
}
test "assigning to union with zero size field" {
const U = union {
a: u32,
b: void,
c: f32,
};
const u: U = .{ .b = {} };
_ = u;
const UE = union(enum) {
a: f32,
b: u32,
c: u0,
};
const ue: UE = .{ .c = 0 };
_ = ue;
}
test "tagged union initialization with runtime void" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;