authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2024-01-30 11:20:23+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-30 12:20:23+02:00
loga2ad8517eea597eb9d7215aef831a86ffd16d1b3
tree5a0de2351f282dee4c5dbc6eca412c593f454fce
parent1b5cbf0d08d9d2fac1f17e4bcff916e4a179f080
signaturebadge-check Signed by PGP key B5690EEEBB952194

Sema: fix union init with zero size field


2 files changed, 31 insertions(+), 1 deletions(-)

src/Sema.zig+11-1
...@@ -4624,6 +4624,8 @@ fn validateUnionInit(...@@ -4624,6 +4624,8 @@ fn validateUnionInit(
4624 // If the union is comptime, we want `first_block_index`4624 // If the union is comptime, we want `first_block_index`
4625 // to point at %c so that the bitcast becomes the last instruction in the block.4625 // to point at %c so that the bitcast becomes the last instruction in the block.
4626 //4626 //
4627 // Store instruction may be missing; if field type has only one possible value, this case is handled below.
4628 //
4627 // In the case of a comptime-known pointer to a union, the4629 // In the case of a comptime-known pointer to a union, the
4628 // the field_ptr instruction is missing, so we have to pattern-match4630 // the field_ptr instruction is missing, so we have to pattern-match
4629 // based only on the store instructions.4631 // based only on the store instructions.
...@@ -4634,7 +4636,10 @@ fn validateUnionInit(...@@ -4634,7 +4636,10 @@ fn validateUnionInit(
4634 var init_val: ?Value = null;4636 var init_val: ?Value = null;
4635 while (block_index > 0) : (block_index -= 1) {4637 while (block_index > 0) : (block_index -= 1) {
4636 const store_inst = block.instructions.items[block_index];4638 const store_inst = block.instructions.items[block_index];
4637 if (store_inst.toRef() == field_ptr_ref) break;4639 if (store_inst.toRef() == field_ptr_ref) {
4640 first_block_index = block_index;
4641 break;
4642 }
4638 switch (air_tags[@intFromEnum(store_inst)]) {4643 switch (air_tags[@intFromEnum(store_inst)]) {
4639 .store, .store_safe => {},4644 .store, .store_safe => {},
4640 else => continue,4645 else => continue,
...@@ -4659,6 +4664,11 @@ fn validateUnionInit(...@@ -4659,6 +4664,11 @@ fn validateUnionInit(
46594664
4660 const tag_ty = union_ty.unionTagTypeHypothetical(mod);4665 const tag_ty = union_ty.unionTagTypeHypothetical(mod);
4661 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);4666 const tag_val = try mod.enumValueFieldIndex(tag_ty, field_index);
4667 const field_type = union_ty.unionFieldType(tag_val, mod).?;
4668
4669 if (try sema.typeHasOnePossibleValue(field_type)) |field_only_value| {
4670 init_val = field_only_value;
4671 }
46624672
4663 if (init_val) |val| {4673 if (init_val) |val| {
4664 // Our task is to delete all the `field_ptr` and `store` instructions, and insert4674 // Our task is to delete all the `field_ptr` and `store` instructions, and insert
test/behavior/union.zig+20
...@@ -381,6 +381,26 @@ test "union with only 1 field which is void should be zero bits" {...@@ -381,6 +381,26 @@ test "union with only 1 field which is void should be zero bits" {
381 comptime assert(@sizeOf(ZeroBits) == 0);381 comptime assert(@sizeOf(ZeroBits) == 0);
382}382}
383383
384test "assigning to union with zero size field" {
385 const U = union {
386 a: u32,
387 b: void,
388 c: f32,
389 };
390
391 const u: U = .{ .b = {} };
392 _ = u;
393
394 const UE = union(enum) {
395 a: f32,
396 b: u32,
397 c: u0,
398 };
399
400 const ue: UE = .{ .c = 0 };
401 _ = ue;
402}
403
384test "tagged union initialization with runtime void" {404test "tagged union initialization with runtime void" {
385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;405 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
386 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;406 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;