diff options
| author | John Schmidt <john.schmidt.h@gmail.com> | 2024-02-19 13:46:52 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2024-02-26 16:51:37 -0800 |
| commit | 00ff123b1eb237f72f918ffd413c8d9c8936c46d (patch) | |
| tree | 7a42500140004999e5d8c28aa06fbf531a8de804 | |
| parent | 8bd94759bf48c3247d4de14806ff2f510cb36591 (diff) | |
| download | zig-00ff123b1eb237f72f918ffd413c8d9c8936c46d.tar.gz zig-00ff123b1eb237f72f918ffd413c8d9c8936c46d.zip | |
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.
| -rw-r--r-- | src/Sema.zig | 7 | ||||
| -rw-r--r-- | test/cases/compile_errors/switch_on_undefined_union.zig | 12 |
2 files changed, 17 insertions, 2 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index e0a8d1fe00..2736abbd2a 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11658,7 +11658,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r // Validate for duplicate items, missing else prong, and invalid range. switch (operand_ty.zigTypeTag(mod)) { - .Union => unreachable, // handled in zirSwitchCond + .Union => unreachable, // handled in `switchCond` .Enum => { seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod)); empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod); @@ -33747,7 +33747,10 @@ fn unionToTag( return Air.internedToRef(opv.toIntern()); } if (try sema.resolveValue(un)) |un_val| { - return Air.internedToRef(un_val.unionTag(mod).?.toIntern()); + const tag_val = un_val.unionTag(mod).?; + if (tag_val.isUndef(mod)) + return try mod.undefRef(enum_ty); + return Air.internedToRef(tag_val.toIntern()); } try sema.requireRuntimeBlock(block, un_src, null); return block.addTyOp(.get_union_tag, enum_ty, un); diff --git a/test/cases/compile_errors/switch_on_undefined_union.zig b/test/cases/compile_errors/switch_on_undefined_union.zig new file mode 100644 index 0000000000..762363dd08 --- /dev/null +++ b/test/cases/compile_errors/switch_on_undefined_union.zig @@ -0,0 +1,12 @@ +export fn entry() void { + const U = union(enum) { a: bool, b: bool }; + switch (@as(U, undefined)) { + .a, .b => {}, + } +} + +// error +// backend=stage2 +// target=native +// +// :3:5: error: use of undefined value here causes undefined behavior |
