Commit 135b91aecd
Changed files (3)
test
cases
compile_errors
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;
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.
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
+