authorgravatar for john.schmidt.h@gmail.comJohn Schmidt <john.schmidt.h@gmail.com> 2023-03-01 21:44:11+01:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2023-03-08 16:35:53+02:00
logecc0108cea97772b6e921b36d8fdc8f90d5fc6cb
tree8b31f57cd8887de57430eb44d2c12f57fe5dd25c
parentfea14c78d1374af909a2f11e37fe057777f3985d

astgen: fill result location with `void` value if no other value

With this change, `break` and `break :blk` will fill the result location with `.void_value`, ensuring that the value will be type checked. The same will happen for a for loop that contains no `break`s in it's body. Closes https://github.com/ziglang/zig/issues/14686.

2 files changed, 38 insertions(+), 11 deletions(-)

src/AstGen.zig+6-11
...@@ -1960,7 +1960,10 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -1960,7 +1960,10 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
1960 else1960 else
1961 .@"break";1961 .@"break";
19621962
1963 block_gz.break_count += 1;
1963 if (rhs == 0) {1964 if (rhs == 0) {
1965 _ = try rvalue(parent_gz, block_gz.break_result_info, .void_value, node);
1966
1964 try genDefers(parent_gz, scope, parent_scope, .normal_only);1967 try genDefers(parent_gz, scope, parent_scope, .normal_only);
19651968
1966 // As our last action before the break, "pop" the error trace if needed1969 // As our last action before the break, "pop" the error trace if needed
...@@ -1970,7 +1973,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -1970,7 +1973,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
1970 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value);1973 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value);
1971 return Zir.Inst.Ref.unreachable_value;1974 return Zir.Inst.Ref.unreachable_value;
1972 }1975 }
1973 block_gz.break_count += 1;
19741976
1975 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_info, rhs, node);1977 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_info, rhs, node);
1976 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len);1978 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
...@@ -6584,6 +6586,9 @@ fn forExpr(...@@ -6584,6 +6586,9 @@ fn forExpr(
6584 cond_block,6586 cond_block,
6585 break_tag,6587 break_tag,
6586 );6588 );
6589 if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) {
6590 _ = try rvalue(parent_gz, ri, .void_value, node);
6591 }
6587 if (is_statement) {6592 if (is_statement) {
6588 _ = try parent_gz.addUnNode(.ensure_result_used, result, node);6593 _ = try parent_gz.addUnNode(.ensure_result_used, result, node);
6589 }6594 }
...@@ -8525,16 +8530,6 @@ fn builtinCall(...@@ -8525,16 +8530,6 @@ fn builtinCall(
8525 }8530 }
8526}8531}
85278532
8528fn simpleNoOpVoid(
8529 gz: *GenZir,
8530 ri: ResultInfo,
8531 node: Ast.Node.Index,
8532 tag: Zir.Inst.Tag,
8533) InnerError!Zir.Inst.Ref {
8534 _ = try gz.addNode(tag, node);
8535 return rvalue(gz, ri, .void_value, node);
8536}
8537
8538fn hasDeclOrField(8533fn hasDeclOrField(
8539 gz: *GenZir,8534 gz: *GenZir,
8540 scope: *Scope,8535 scope: *Scope,
test/cases/compile_errors/break_void_result_location.zig created+32
...@@ -0,0 +1,32 @@
1export fn f1() void {
2 const x: usize = for ("hello") |_| {};
3 _ = x;
4}
5export fn f2() void {
6 const x: usize = for ("hello") |_| {
7 break;
8 };
9 _ = x;
10}
11export fn f3() void {
12 var t: bool = true;
13 const x: usize = while (t) {
14 break;
15 };
16 _ = x;
17}
18export fn f4() void {
19 const x: usize = blk: {
20 break :blk;
21 };
22 _ = x;
23}
24
25// error
26// backend=stage2
27// target=native
28//
29// :2:22: error: expected type 'usize', found 'void'
30// :7:9: error: expected type 'usize', found 'void'
31// :14:9: error: expected type 'usize', found 'void'
32// :18:1: error: expected type 'usize', found 'void'