From 6ec81be545eab6a23c164ca045608d9c41b63535 Mon Sep 17 00:00:00 2001 From: David Rubin Date: Thu, 8 Oct 2026 16:53:48 -0500 Subject: [PATCH] Sema: account for inlined blocks in comptime break --- src/Sema.zig | 41 +++++++++++++++++++++++++++++++---------- test/behavior/if.zig | 13 +++++++++++++ 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 8dda937f375e048096e7b345372c5ae42d2c0b8f..d9c196bb22a14fa1852a81bbf0808998768eaab8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -17952,19 +17952,40 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label /// break from an inline loop. In such case we must convert it to /// a runtime break. fn addRuntimeBreak(sema: *Sema, child_block: *Block, block_inst: Zir.Inst.Index, break_operand: Zir.Inst.Ref) !void { - const labeled_block = try sema.ensurePostHoc(child_block, block_inst); - const operand = sema.resolveInst(break_operand); - const br_ref = try child_block.addBr(labeled_block.label.merges.block_inst, operand); - try labeled_block.label.merges.results.append(sema.gpa, operand); - try labeled_block.label.merges.br_list.append(sema.gpa, br_ref.toIndex().?); - try labeled_block.label.merges.src_locs.append(sema.gpa, null); + var target_block: ?*Block = child_block; + while (target_block) |candidate| : (target_block = candidate.parent) { + const label = candidate.label orelse continue; + if (label.zir_block != block_inst) continue; + switch (sema.code.instructions.items(.tag)[@backingInt(label.zir_block)]) { + .block_inline, .block_comptime => continue, + else => {}, + } + return sema.addRuntimeBreakToBlock(child_block, candidate, label, operand); + } - labeled_block.block.runtime_index.increment(); - if (labeled_block.block.runtime_cond == null and labeled_block.block.runtime_loop == null) { - labeled_block.block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop; - labeled_block.block.runtime_loop = child_block.runtime_loop; + const labeled_block = try sema.ensurePostHoc(child_block, block_inst); + return sema.addRuntimeBreakToBlock(child_block, &labeled_block.block, &labeled_block.label, operand); +} + +fn addRuntimeBreakToBlock( + sema: *Sema, + child_block: *Block, + target_block: *Block, + label: *Block.Label, + operand: Air.Inst.Ref, +) !void { + const br_ref = try child_block.addBr(label.merges.block_inst, operand); + + try label.merges.results.append(sema.gpa, operand); + try label.merges.br_list.append(sema.gpa, br_ref.toIndex().?); + try label.merges.src_locs.append(sema.gpa, null); + + target_block.runtime_index.increment(); + if (target_block.runtime_cond == null and target_block.runtime_loop == null) { + target_block.runtime_cond = child_block.runtime_cond orelse child_block.runtime_loop; + target_block.runtime_loop = child_block.runtime_loop; } } diff --git a/test/behavior/if.zig b/test/behavior/if.zig index 449c6e4c5f4d73e5e1f8e84b4435df11d608da87..3d0d40a334f8b977a278ad68d9eecac9053a353c 100644 --- a/test/behavior/if.zig +++ b/test/behavior/if.zig @@ -71,6 +71,19 @@ test "labeled break inside comptime if inside runtime if" { try expect(answer == 42); } +test "labeled break from comptime block inside runtime if" { + var c = true; + _ = &c; + var reached = false; + blk: { + if (c) { + comptime break :blk; + } + reached = true; + } + try expect(!reached); +} + test "const result loc, runtime if cond, else unreachable" { const Num = enum { One, Two }; -- 2.54.0