# 0061 — dead statements after `return` / `raise` emit into a closed block > **✅ RESOLVED (2026-06-01).** Root cause: `lowerBlock` / `lowerBlockValue` > ([src/ir/lower.zig](../src/ir/lower.zig)) broke their statement loop only on > the `block_terminated` flag, which `lowerReturn` deliberately does NOT set (it > would leak past an `if cond { return }` merge block — see the comment at > `lowerReturn`). So a bare `return X;` / `raise` mid-block closed the current > LLVM basic block while lowering kept emitting the trailing statements into it. > Fix: after each `lowerStmt`, also stop the loop when > `currentBlockHasTerminator()` is true (CFG-level termination of the *current* > block — correctly false at an `if`/`inline if` merge block, so conditional > returns still fall through). Regression test: > [examples/0038-basic-dead-code-after-terminator.sx](../examples/0038-basic-dead-code-after-terminator.sx). ## Symptom Any statement following a block-terminating statement (`return`, `raise`) at the same block level is lowered into the basic block *after* its terminator, so the LLVM verifier aborts: ``` LLVM verification failed: Terminator found in the middle of a basic block! label %entry ``` Observed: a well-formed program with trailing dead code crashes the compiler. Expected: the dead statements are dropped (unreachable); the program compiles and runs. This blocked ERR E5.1: the canonical failable-closure form from the plan, `closure((x) -> (s32, !) { raise error.X; return x; })`, has a dead `return x;` after the unconditional `raise` and tripped the verifier. ## Reproduction Minimal (non-failable — the bug is general, not error-specific): ```sx #import "modules/std.sx"; main :: () -> s32 { return 0; print("dead\n"); } ``` Failable facet (the form that blocked E5.1): ```sx #import "modules/std.sx"; E :: error { Neg } top :: (x: s64) -> (s64, !E) { raise error.Neg; return x; } main :: () -> s32 { print("r={}\n", top(5) catch e 0); return 0; } ``` Both abort with "Terminator found in the middle of a basic block". A *conditional* terminator (`if c { return 1; } return 2;`) was unaffected — its merge block is fresh and has no terminator. ## Investigation prompt The bug is in block-statement lowering in [src/ir/lower.zig](../src/ir/lower.zig): `lowerBlock` (~line 1455) and `lowerBlockValue` (~line 1496) iterate `blk.stmts` and only check the `block_terminated` flag. `lowerReturn` (~line 1767) emits a `ret`/`br` terminator but intentionally does NOT set `block_terminated` (setting it would leak past `if cond { return }` merge blocks and wrongly skip their trailing statements — see the comment there). The fix is to stop the loop when the *current* basic block has a terminator after lowering a statement, using the existing `currentBlockHasTerminator()` helper (~line 11725), which is naturally false at a merge block. Verify with both repros above (now compile + run) and confirm `examples/0518-packs-pack-value-dispatch.sx` (inline-if + return + trailing statements) still produces all its output.