authorgravatar for 8965202+gpanders@users.noreply.github.comGregory Anders <8965202+gpanders@users.noreply.github.com> 2022-06-06 04:13:52-06:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-06 13:13:52+03:00
log135b91aecd9be1f6f5806b667e07e383dd481198
tree4bcc701521d344b75b2541ec1347ce2652e020c0
parent33826a6a2e035d2a2be65314ed80a6b7abaf7f12
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Treat blocks with "return" as "noreturn"

Block statements that end with "break" should not be considered "noreturn" for the enclosing scope, but other "noreturn" instructions (return, panic, compile error, etc.) should be. This differentiation necessitates handling "break" differently from the other "noreturn" instructions when inside a block statement.

3 files changed, 37 insertions(+), 0 deletions(-)

src/AstGen.zig+10
......@@ -1967,6 +1967,9 @@ fn blockExpr(
19671967 }
19681968
19691969 try blockExprStmts(gz, scope, statements);
1970 if (gz.endsWithNoReturn() and !gz.endsWithBreak()) {
1971 return Zir.Inst.Ref.unreachable_value;
1972 }
19701973 return rvalue(gz, rl, .void_value, block_node);
19711974}
19721975
......@@ -9930,6 +9933,13 @@ const GenZir = struct {
99309933 return tags[last_inst].isNoReturn();
99319934 }
99329935
9936 fn endsWithBreak(gz: GenZir) bool {
9937 if (gz.isEmpty()) return false;
9938 const tags = gz.astgen.instructions.items(.tag);
9939 const last_inst = gz.instructions.items[gz.instructions.items.len - 1];
9940 return tags[last_inst].isBreak();
9941 }
9942
99339943 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`.
99349944 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
99359945 if (inst_ref == .unreachable_value) return true;
src/Zir.zig+13
......@@ -1250,6 +1250,19 @@ pub const Inst = struct {
12501250 };
12511251 }
12521252
1253 /// Returns whether the instruction is a "break". This differs from
1254 /// isNoReturn because a "break" in a block statement is not a
1255 /// "noreturn" for the outer scope, whereas the other "noreturn"
1256 /// instructions are.
1257 pub fn isBreak(tag: Tag) bool {
1258 return switch (tag) {
1259 .@"break",
1260 .break_inline,
1261 => true,
1262 else => false,
1263 };
1264 }
1265
12531266 /// AstGen uses this to find out if `Ref.void_value` should be used in place
12541267 /// of the result of a given instruction. This allows Sema to forego adding
12551268 /// the instruction to the map after analysis.
test/cases/compile_errors/stage2/code_after_return_in_block_is_unreachable.zig created+14
......@@ -0,0 +1,14 @@
1export fn entry() void {
2 {
3 return;
4 }
5
6 return;
7}
8
9// error
10// target=native
11//
12// :6:5: error: unreachable code
13// :2:5: note: control flow is diverted here
14