authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2024-02-19 13:46:52+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-02-26 16:51:37-08:00
log00ff123b1eb237f72f918ffd413c8d9c8936c46d
tree7a42500140004999e5d8c28aa06fbf531a8de804
parent8bd94759bf48c3247d4de14806ff2f510cb36591

Sema: fix compile error for switching on undefined union

Before this fix, passing an undefined union value to `Sema.switchCond` returned an undefined value of the union type, not the tag type, since `Value.unionTag` forwards undefined values unchanged. This leads us into the `.Union` branch in `Sema.zirSwitchBlock` which is unreachable, now we take the `.Enum` branch instead.

2 files changed, 17 insertions(+), 2 deletions(-)

src/Sema.zig+5-2
......@@ -11658,7 +11658,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
1165811658
1165911659 // Validate for duplicate items, missing else prong, and invalid range.
1166011660 switch (operand_ty.zigTypeTag(mod)) {
11661 .Union => unreachable, // handled in zirSwitchCond
11661 .Union => unreachable, // handled in `switchCond`
1166211662 .Enum => {
1166311663 seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod));
1166411664 empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod);
......@@ -33747,7 +33747,10 @@ fn unionToTag(
3374733747 return Air.internedToRef(opv.toIntern());
3374833748 }
3374933749 if (try sema.resolveValue(un)) |un_val| {
33750 return Air.internedToRef(un_val.unionTag(mod).?.toIntern());
33750 const tag_val = un_val.unionTag(mod).?;
33751 if (tag_val.isUndef(mod))
33752 return try mod.undefRef(enum_ty);
33753 return Air.internedToRef(tag_val.toIntern());
3375133754 }
3375233755 try sema.requireRuntimeBlock(block, un_src, null);
3375333756 return block.addTyOp(.get_union_tag, enum_ty, un);
test/cases/compile_errors/switch_on_undefined_union.zig created+12
......@@ -0,0 +1,12 @@
1export fn entry() void {
2 const U = union(enum) { a: bool, b: bool };
3 switch (@as(U, undefined)) {
4 .a, .b => {},
5 }
6}
7
8// error
9// backend=stage2
10// target=native
11//
12// :3:5: error: use of undefined value here causes undefined behavior