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(...@@ -1967,6 +1967,9 @@ fn blockExpr(
1967 }1967 }
19681968
1969 try blockExprStmts(gz, scope, statements);1969 try blockExprStmts(gz, scope, statements);
1970 if (gz.endsWithNoReturn() and !gz.endsWithBreak()) {
1971 return Zir.Inst.Ref.unreachable_value;
1972 }
1970 return rvalue(gz, rl, .void_value, block_node);1973 return rvalue(gz, rl, .void_value, block_node);
1971}1974}
19721975
...@@ -9930,6 +9933,13 @@ const GenZir = struct {...@@ -9930,6 +9933,13 @@ const GenZir = struct {
9930 return tags[last_inst].isNoReturn();9933 return tags[last_inst].isNoReturn();
9931 }9934 }
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
9933 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`.9943 /// TODO all uses of this should be replaced with uses of `endsWithNoReturn`.
9934 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {9944 fn refIsNoReturn(gz: GenZir, inst_ref: Zir.Inst.Ref) bool {
9935 if (inst_ref == .unreachable_value) return true;9945 if (inst_ref == .unreachable_value) return true;
src/Zir.zig+13
...@@ -1250,6 +1250,19 @@ pub const Inst = struct {...@@ -1250,6 +1250,19 @@ pub const Inst = struct {
1250 };1250 };
1251 }1251 }
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
1253 /// AstGen uses this to find out if `Ref.void_value` should be used in place1266 /// AstGen uses this to find out if `Ref.void_value` should be used in place
1254 /// of the result of a given instruction. This allows Sema to forego adding1267 /// of the result of a given instruction. This allows Sema to forego adding
1255 /// the instruction to the map after analysis.1268 /// 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