From ecc0108cea97772b6e921b36d8fdc8f90d5fc6cb Mon Sep 17 00:00:00 2001 From: John Schmidt Date: Wed, 1 Mar 2023 21:44:11 +0100 Subject: [PATCH] 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. --- src/AstGen.zig | 17 ++++------ .../break_void_result_location.zig | 32 +++++++++++++++++++ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 test/cases/compile_errors/break_void_result_location.zig diff --git a/src/AstGen.zig b/src/AstGen.zig index f91845a1fd..7b2138a535 100644 --- a/src/AstGen.zig +++ b/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, diff --git a/test/cases/compile_errors/break_void_result_location.zig b/test/cases/compile_errors/break_void_result_location.zig new file mode 100644 index 0000000000..696ea39667 --- /dev/null +++ b/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'