From 29ac68b2537b9a9c67f92cc2a5dd4c35bf1c2b31 Mon Sep 17 00:00:00 2001 From: Justus Klausecker Date: Sun, 13 Jul 2025 16:53:39 +0200 Subject: [PATCH 1/2] Sema: Fix invalid AIR generation for switch loop with comptime discarded tag Add an additional check before emitting `.loop_switch_br` instead of `.switch_br` in a tagged switch statement for whether any of the continues referencing its tag are actually runtime reachable. This fixes triggering an assertion in Liveness caused by the invalid assumption that every tagged switch must be a loop if its tag is referenced in any way even if this reference is not runtime reachable. --- src/Sema.zig | 4 +++- test/cases/discard_labeled_switch_tag.zig | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/cases/discard_labeled_switch_tag.zig diff --git a/src/Sema.zig b/src/Sema.zig index 81331f3ccc..6672ba5b36 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -13041,8 +13041,10 @@ fn analyzeSwitchRuntimeBlock( sema.air_extra.appendSliceAssumeCapacity(@ptrCast(cases_extra.items)); sema.air_extra.appendSliceAssumeCapacity(@ptrCast(else_body)); + const has_any_continues = spa.operand == .loop and child_block.label.?.merges.extra_insts.items.len > 0; + return try child_block.addInst(.{ - .tag = if (spa.operand == .loop) .loop_switch_br else .switch_br, + .tag = if (has_any_continues) .loop_switch_br else .switch_br, .data = .{ .pl_op = .{ .operand = operand, .payload = payload_index, diff --git a/test/cases/discard_labeled_switch_tag.zig b/test/cases/discard_labeled_switch_tag.zig new file mode 100644 index 0000000000..63aa304b40 --- /dev/null +++ b/test/cases/discard_labeled_switch_tag.zig @@ -0,0 +1,12 @@ +// https://github.com/ziglang/zig/issues/24323 + +export fn f() void { + const x: u32 = 0; + sw: switch (x) { + else => if (false) continue :sw undefined, + } +} + +// compile +// backend=stage2,llvm +// target=native From b993728f10c213b679def931c2f59c8e64b14660 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 14 Jul 2025 10:02:37 -0700 Subject: [PATCH 2/2] make it a behavior test instead It's important to check for correct runtime behavior, rather than only checking that the compiler does not crash. --- test/behavior/switch_loop.zig | 10 ++++++++++ test/cases/discard_labeled_switch_tag.zig | 12 ------------ 2 files changed, 10 insertions(+), 12 deletions(-) delete mode 100644 test/cases/discard_labeled_switch_tag.zig diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 687ed466d9..98605692be 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -216,3 +216,13 @@ test "switch loop with pointer capture" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "unanalyzed continue with operand" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + + @setRuntimeSafety(false); + label: switch (false) { + false => if (false) continue :label true, + true => {}, + } +} diff --git a/test/cases/discard_labeled_switch_tag.zig b/test/cases/discard_labeled_switch_tag.zig deleted file mode 100644 index 63aa304b40..0000000000 --- a/test/cases/discard_labeled_switch_tag.zig +++ /dev/null @@ -1,12 +0,0 @@ -// https://github.com/ziglang/zig/issues/24323 - -export fn f() void { - const x: u32 = 0; - sw: switch (x) { - else => if (false) continue :sw undefined, - } -} - -// compile -// backend=stage2,llvm -// target=native