authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 15:07:00-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-09 15:07:00-05:00
logb936fe0a5855872814c9f70f958363f64896217b
treee5ac6ea062d051f5b062d3d11643d17e6dfd58ff
parent0f0d27ce2427bff9d48d14b829e29a2003ba0e9c
parent01b454f8515312531ff0c70985203f9aecb022db
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11101 from Vexu/stage2

Sema: handle noreturn result in condbr_inline

6 files changed, 88 insertions(+), 38 deletions(-)

src/AstGen.zig+4
......@@ -1991,6 +1991,9 @@ fn labeledBlockExpr(
19911991 defer block_scope.labeled_breaks.deinit(astgen.gpa);
19921992
19931993 try blockExprStmts(&block_scope, &block_scope.base, statements);
1994 if (!block_scope.endsWithNoReturn()) {
1995 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
1996 }
19941997
19951998 if (!block_scope.label.?.used) {
19961999 try astgen.appendErrorTok(label_token, "unused block label", .{});
......@@ -7646,6 +7649,7 @@ fn cImport(
76467649
76477650 const block_inst = try gz.makeBlockInst(.c_import, node);
76487651 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
7652 _ = try gz.addUnNode(.ensure_result_used, block_result, node);
76497653 if (!gz.refIsNoReturn(block_result)) {
76507654 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
76517655 }
src/Module.zig+2-4
......@@ -3739,9 +3739,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
37393739 const inst_data = zir_datas[zir_block_index].pl_node;
37403740 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
37413741 const body = zir.extra[extra.end..][0..extra.data.body_len];
3742 const break_index = try sema.analyzeBody(&block_scope, body);
3742 const result_ref = (try sema.analyzeBodyBreak(&block_scope, body)).?.operand;
37433743 try wip_captures.finalize();
3744 const result_ref = zir_datas[break_index].@"break".operand;
37453744 const src: LazySrcLoc = .{ .node_offset = 0 };
37463745 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
37473746 const align_val = blk: {
......@@ -4681,12 +4680,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
46814680 func.state = .in_progress;
46824681 log.debug("set {s} to in_progress", .{decl.name});
46834682
4684 _ = sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
4683 sema.analyzeBody(&inner_block, fn_info.body) catch |err| switch (err) {
46854684 // TODO make these unreachable instead of @panic
46864685 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
46874686 error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
46884687 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
4689 error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
46904688 else => |e| return e,
46914689 };
46924690
src/Sema.zig+63-34
......@@ -520,14 +520,14 @@ fn resolveBody(
520520 /// use to return from the body.
521521 body_inst: Zir.Inst.Index,
522522) CompileError!Air.Inst.Ref {
523 const break_inst = try sema.analyzeBody(block, body);
524 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
523 const break_data = (try sema.analyzeBodyBreak(block, body)) orelse
524 return Air.Inst.Ref.unreachable_value;
525525 // For comptime control flow, we need to detect when `analyzeBody` reports
526526 // that we need to break from an outer block. In such case we
527527 // use Zig's error mechanism to send control flow up the stack until
528528 // we find the corresponding block to this break.
529529 if (block.is_comptime and break_data.block_inst != body_inst) {
530 sema.comptime_break_inst = break_inst;
530 sema.comptime_break_inst = break_data.inst;
531531 return error.ComptimeBreak;
532532 }
533533 return sema.resolveInst(break_data.operand);
......@@ -537,11 +537,37 @@ pub fn analyzeBody(
537537 sema: *Sema,
538538 block: *Block,
539539 body: []const Zir.Inst.Index,
540) CompileError!Zir.Inst.Index {
541 return sema.analyzeBodyInner(block, body) catch |err| switch (err) {
540) !void {
541 _ = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
542 error.ComptimeBreak => unreachable, // unexpected comptime control flow
543 else => |e| return e,
544 };
545}
546
547const BreakData = struct {
548 block_inst: Zir.Inst.Index,
549 operand: Air.Inst.Ref,
550 inst: Air.Inst.Index,
551};
552
553pub fn analyzeBodyBreak(
554 sema: *Sema,
555 block: *Block,
556 body: []const Zir.Inst.Index,
557) CompileError!?BreakData {
558 const break_inst = sema.analyzeBodyInner(block, body) catch |err| switch (err) {
542559 error.ComptimeBreak => sema.comptime_break_inst,
543560 else => |e| return e,
544561 };
562 if (block.instructions.items.len != 0 and
563 sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn())
564 return null;
565 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
566 return BreakData{
567 .block_inst = break_data.block_inst,
568 .operand = break_data.operand,
569 .inst = break_inst,
570 };
545571}
546572
547573/// ZIR instructions which are always `noreturn` return this. This matches the
......@@ -1045,12 +1071,12 @@ fn analyzeBodyInner(
10451071 const inst_data = datas[inst].pl_node;
10461072 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
10471073 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1048 const break_inst = try sema.analyzeBody(block, inline_body);
1049 const break_data = datas[break_inst].@"break";
1074 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1075 break always_noreturn;
10501076 if (inst == break_data.block_inst) {
10511077 break :blk sema.resolveInst(break_data.operand);
10521078 } else {
1053 break break_inst;
1079 break break_data.inst;
10541080 }
10551081 },
10561082 .block => blk: {
......@@ -1068,12 +1094,12 @@ fn analyzeBodyInner(
10681094 block.params.deinit(sema.gpa);
10691095 block.params = prev_params;
10701096 }
1071 const break_inst = try sema.analyzeBody(block, inline_body);
1072 const break_data = datas[break_inst].@"break";
1097 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1098 break always_noreturn;
10731099 if (inst == break_data.block_inst) {
10741100 break :blk sema.resolveInst(break_data.operand);
10751101 } else {
1076 break break_inst;
1102 break break_data.inst;
10771103 }
10781104 },
10791105 .block_inline => blk: {
......@@ -1090,12 +1116,12 @@ fn analyzeBodyInner(
10901116 block.params.deinit(sema.gpa);
10911117 block.params = prev_params;
10921118 }
1093 const break_inst = try sema.analyzeBody(block, inline_body);
1094 const break_data = datas[break_inst].@"break";
1119 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1120 break always_noreturn;
10951121 if (inst == break_data.block_inst) {
10961122 break :blk sema.resolveInst(break_data.operand);
10971123 } else {
1098 break break_inst;
1124 break break_data.inst;
10991125 }
11001126 },
11011127 .condbr => blk: {
......@@ -1108,12 +1134,12 @@ fn analyzeBodyInner(
11081134 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
11091135 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
11101136 const inline_body = if (cond.val.toBool()) then_body else else_body;
1111 const break_inst = try sema.analyzeBody(block, inline_body);
1112 const break_data = datas[break_inst].@"break";
1137 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1138 break always_noreturn;
11131139 if (inst == break_data.block_inst) {
11141140 break :blk sema.resolveInst(break_data.operand);
11151141 } else {
1116 break break_inst;
1142 break break_data.inst;
11171143 }
11181144 },
11191145 .condbr_inline => blk: {
......@@ -1124,12 +1150,12 @@ fn analyzeBodyInner(
11241150 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
11251151 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
11261152 const inline_body = if (cond.val.toBool()) then_body else else_body;
1127 const break_inst = try sema.analyzeBody(block, inline_body);
1128 const break_data = datas[break_inst].@"break";
1153 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1154 break always_noreturn;
11291155 if (inst == break_data.block_inst) {
11301156 break :blk sema.resolveInst(break_data.operand);
11311157 } else {
1132 break break_inst;
1158 break break_data.inst;
11331159 }
11341160 },
11351161 };
......@@ -1915,7 +1941,7 @@ fn zirEnumDecl(
19151941 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions
19161942
19171943 if (body.len != 0) {
1918 _ = try sema.analyzeBody(&enum_block, body);
1944 try sema.analyzeBody(&enum_block, body);
19191945 }
19201946
19211947 try wip_captures.finalize();
......@@ -3639,7 +3665,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
36393665 var loop_block = child_block.makeSubBlock();
36403666 defer loop_block.instructions.deinit(gpa);
36413667
3642 _ = try sema.analyzeBody(&loop_block, body);
3668 try sema.analyzeBody(&loop_block, body);
36433669
36443670 try child_block.instructions.append(gpa, loop_inst);
36453671
......@@ -3681,7 +3707,8 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
36813707 };
36823708 defer child_block.instructions.deinit(sema.gpa);
36833709
3684 _ = try sema.analyzeBody(&child_block, body);
3710 // Ignore the result, all the relevant operations have written to c_import_buf already.
3711 _ = try sema.analyzeBodyBreak(&child_block, body);
36853712
36863713 const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err|
36873714 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
......@@ -4658,9 +4685,8 @@ fn analyzeCall(
46584685 }
46594686
46604687 const result = result: {
4661 _ = sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
4688 sema.analyzeBody(&child_block, fn_info.body) catch |err| switch (err) {
46624689 error.ComptimeReturn => break :result inlining.comptime_result,
4663 error.ComptimeBreak => unreachable, // Can't break through a fn call.
46644690 error.AnalysisFail => {
46654691 const err_msg = inlining.err orelse return err;
46664692 try sema.errNote(block, call_src, err_msg, "called from here", .{});
......@@ -7313,7 +7339,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
73137339 const item = sema.resolveInst(item_ref);
73147340 // `item` is already guaranteed to be constant known.
73157341
7316 _ = try sema.analyzeBody(&case_block, body);
7342 try sema.analyzeBody(&case_block, body);
73177343
73187344 try wip_captures.finalize();
73197345
......@@ -7356,7 +7382,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
73567382
73577383 const body = sema.code.extra[extra_index..][0..body_len];
73587384 extra_index += body_len;
7359 _ = try sema.analyzeBody(&case_block, body);
7385 try sema.analyzeBody(&case_block, body);
73607386
73617387 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
73627388 case_block.instructions.items.len);
......@@ -7431,7 +7457,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
74317457
74327458 const body = sema.code.extra[extra_index..][0..body_len];
74337459 extra_index += body_len;
7434 _ = try sema.analyzeBody(&case_block, body);
7460 try sema.analyzeBody(&case_block, body);
74357461
74367462 try wip_captures.finalize();
74377463
......@@ -7468,7 +7494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
74687494 case_block.wip_capture_scope = wip_captures.scope;
74697495
74707496 if (special.body.len != 0) {
7471 _ = try sema.analyzeBody(&case_block, special.body);
7497 try sema.analyzeBody(&case_block, special.body);
74727498 } else {
74737499 // We still need a terminator in this block, but we have proven
74747500 // that it is unreachable.
......@@ -10990,7 +11016,8 @@ fn zirTypeofPeer(
1099011016 .is_typeof = true,
1099111017 };
1099211018 defer child_block.instructions.deinit(sema.gpa);
10993 _ = try sema.analyzeBody(&child_block, body);
11019 // Ignore the result, we only care about the instructions in `args`.
11020 _ = try sema.analyzeBodyBreak(&child_block, body);
1099411021
1099511022 const args = sema.code.refSlice(extra.end, extended.small);
1099611023
......@@ -11186,6 +11213,8 @@ fn zirCondbr(
1118611213
1118711214 if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {
1118811215 const body = if (cond_val.toBool()) then_body else else_body;
11216 // We use `analyzeBodyInner` since we want to propagate any possible
11217 // `error.ComptimeBreak` to the caller.
1118911218 return sema.analyzeBodyInner(parent_block, body);
1119011219 }
1119111220
......@@ -11199,11 +11228,11 @@ fn zirCondbr(
1119911228 sub_block.runtime_index += 1;
1120011229 defer sub_block.instructions.deinit(gpa);
1120111230
11202 _ = try sema.analyzeBody(&sub_block, then_body);
11231 try sema.analyzeBody(&sub_block, then_body);
1120311232 const true_instructions = sub_block.instructions.toOwnedSlice(gpa);
1120411233 defer gpa.free(true_instructions);
1120511234
11206 _ = try sema.analyzeBody(&sub_block, else_body);
11235 try sema.analyzeBody(&sub_block, else_body);
1120711236 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
1120811237 true_instructions.len + sub_block.instructions.items.len);
1120911238 _ = try parent_block.addInst(.{
......@@ -19186,7 +19215,7 @@ fn semaStructFields(
1918619215 }
1918719216
1918819217 if (body.len != 0) {
19189 _ = try sema.analyzeBody(&block_scope, body);
19218 try sema.analyzeBody(&block_scope, body);
1919019219 }
1919119220
1919219221 try wip_captures.finalize();
......@@ -19360,7 +19389,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
1936019389 }
1936119390
1936219391 if (body.len != 0) {
19363 _ = try sema.analyzeBody(&block_scope, body);
19392 try sema.analyzeBody(&block_scope, body);
1936419393 }
1936519394
1936619395 try wip_captures.finalize();
test/behavior.zig+1
......@@ -46,6 +46,7 @@ test {
4646 _ = @import("behavior/bugs/4954.zig");
4747 _ = @import("behavior/bugs/6850.zig");
4848 _ = @import("behavior/bugs/7250.zig");
49 _ = @import("behavior/bugs/11100.zig");
4950 _ = @import("behavior/call.zig");
5051 _ = @import("behavior/cast.zig");
5152 _ = @import("behavior/comptime_memory.zig");
test/behavior/basic.zig+7
......@@ -846,3 +846,10 @@ test "discarding the result of various expressions" {
846846 _ = while (S.bar()) |some| break some else {};
847847 _ = for ("foo") |char| break char else {};
848848}
849
850test "labeled block implicitly ends in a break" {
851 var a = false;
852 blk: {
853 if (a) break :blk;
854 }
855}
test/behavior/bugs/11100.zig created+11
......@@ -0,0 +1,11 @@
1const std = @import("std");
2pub fn do() bool {
3 inline for (.{"a"}) |_| {
4 if (true) return false;
5 }
6 return true;
7}
8
9test "bug" {
10 try std.testing.expect(!do());
11}