Commit ecc0108cea

John Schmidt <john.schmidt.h@gmail.com>
2023-03-01 21:44:11
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.
1 parent fea14c7
Changed files (2)
src
test
cases
src/AstGen.zig
@@ -1960,7 +1960,10 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
                 else
                     .@"break";
 
+                block_gz.break_count += 1;
                 if (rhs == 0) {
+                    _ = try rvalue(parent_gz, block_gz.break_result_info, .void_value, node);
+
                     try genDefers(parent_gz, scope, parent_scope, .normal_only);
 
                     // 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
                     _ = try parent_gz.addBreak(break_tag, block_inst, .void_value);
                     return Zir.Inst.Ref.unreachable_value;
                 }
-                block_gz.break_count += 1;
 
                 const operand = try reachableExpr(parent_gz, parent_scope, block_gz.break_result_info, rhs, node);
                 const search_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
@@ -6584,6 +6586,9 @@ fn forExpr(
         cond_block,
         break_tag,
     );
+    if (ri.rl.strategy(&loop_scope).tag == .break_void and loop_scope.break_count == 0) {
+        _ = try rvalue(parent_gz, ri, .void_value, node);
+    }
     if (is_statement) {
         _ = try parent_gz.addUnNode(.ensure_result_used, result, node);
     }
@@ -8525,16 +8530,6 @@ fn builtinCall(
     }
 }
 
-fn simpleNoOpVoid(
-    gz: *GenZir,
-    ri: ResultInfo,
-    node: Ast.Node.Index,
-    tag: Zir.Inst.Tag,
-) InnerError!Zir.Inst.Ref {
-    _ = try gz.addNode(tag, node);
-    return rvalue(gz, ri, .void_value, node);
-}
-
 fn hasDeclOrField(
     gz: *GenZir,
     scope: *Scope,
test/cases/compile_errors/break_void_result_location.zig
@@ -0,0 +1,32 @@
+export fn f1() void {
+    const x: usize = for ("hello") |_| {};
+    _ = x;
+}
+export fn f2() void {
+    const x: usize = for ("hello") |_| {
+        break;
+    };
+    _ = x;
+}
+export fn f3() void {
+    var t: bool = true;
+    const x: usize = while (t) {
+        break;
+    };
+    _ = x;
+}
+export fn f4() void {
+    const x: usize = blk: {
+        break :blk;
+    };
+    _ = x;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :2:22: error: expected type 'usize', found 'void'
+// :7:9: error: expected type 'usize', found 'void'
+// :14:9: error: expected type 'usize', found 'void'
+// :18:1: error: expected type 'usize', found 'void'