Commit 00ff123b1e

John Schmidt <john.schmidt.h@gmail.com>
2024-02-19 13:46:52
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.
1 parent 8bd9475
Changed files (2)
src
test
cases
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);
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