diff --git a/src/AstGen.zig b/src/AstGen.zig index ab5befa4ba..21e5170030 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -1967,6 +1967,9 @@ fn blockExpr( } try blockExprStmts(gz, scope, statements); + if (gz.endsWithNoReturn() and !gz.endsWithBreak()) { + return Zir.Inst.Ref.unreachable_value; + } return rvalue(gz, rl, .void_value, block_node); } @@ -9930,6 +9933,13 @@ const GenZir = struct { return tags[last_inst].isNoReturn(); } + fn endsWithBreak(gz: GenZir) bool { + if (gz.isEmpty()) return false; + const tags = gz.astgen.instructions.items(.tag); + const last_inst = gz.instructions.items[gz.instructions.items.len - 1]; + return tags[last_inst].isBreak(); + } + /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`. fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool { if (inst_ref == .unreachable_value) return true; diff --git a/src/Zir.zig b/src/Zir.zig index f09f2015e0..bad7b91488 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -1250,6 +1250,19 @@ pub const Inst = struct { }; } + /// Returns whether the instruction is a "break". This differs from + /// isNoReturn because a "break" in a block statement is not a + /// "noreturn" for the outer scope, whereas the other "noreturn" + /// instructions are. + pub fn isBreak(tag: Tag) bool { + return switch (tag) { + .@"break", + .break_inline, + => true, + else => false, + }; + } + /// AstGen uses this to find out if `Ref.void_value` should be used in place /// of the result of a given instruction. This allows Sema to forego adding /// the instruction to the map after analysis. diff --git a/test/cases/compile_errors/stage2/code_after_return_in_block_is_unreachable.zig b/test/cases/compile_errors/stage2/code_after_return_in_block_is_unreachable.zig new file mode 100644 index 0000000000..e62edcb358 --- /dev/null +++ b/test/cases/compile_errors/stage2/code_after_return_in_block_is_unreachable.zig @@ -0,0 +1,14 @@ +export fn entry() void { + { + return; + } + + return; +} + +// error +// target=native +// +// :6:5: error: unreachable code +// :2:5: note: control flow is diverted here +