authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-09 12:24:18+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-03-09 17:07:25+02:00
logbb1fa0bdbd7235308362528e5c1ca408681064e9
tree2eaebdf0fe8e292032f6a5028df0029aa602a7c6
parent0f0d27ce2427bff9d48d14b829e29a2003ba0e9c

Sema: handle noreturn result in condbr_inline


5 files changed, 78 insertions(+), 38 deletions(-)

src/AstGen.zig+1
...@@ -7646,6 +7646,7 @@ fn cImport(...@@ -7646,6 +7646,7 @@ fn cImport(
76467646
7647 const block_inst = try gz.makeBlockInst(.c_import, node);7647 const block_inst = try gz.makeBlockInst(.c_import, node);
7648 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);7648 const block_result = try expr(&block_scope, &block_scope.base, .none, body_node);
7649 _ = try gz.addUnNode(.ensure_result_used, block_result, node);
7649 if (!gz.refIsNoReturn(block_result)) {7650 if (!gz.refIsNoReturn(block_result)) {
7650 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);7651 _ = try block_scope.addBreak(.break_inline, block_inst, .void_value);
7651 }7652 }
src/Module.zig+2-4
...@@ -3739,9 +3739,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {...@@ -3739,9 +3739,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
3739 const inst_data = zir_datas[zir_block_index].pl_node;3739 const inst_data = zir_datas[zir_block_index].pl_node;
3740 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);3740 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
3741 const body = zir.extra[extra.end..][0..extra.data.body_len];3741 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;
3743 try wip_captures.finalize();3743 try wip_captures.finalize();
3744 const result_ref = zir_datas[break_index].@"break".operand;
3745 const src: LazySrcLoc = .{ .node_offset = 0 };3744 const src: LazySrcLoc = .{ .node_offset = 0 };
3746 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);3745 const decl_tv = try sema.resolveInstValue(&block_scope, src, result_ref);
3747 const align_val = blk: {3746 const align_val = blk: {
...@@ -4681,12 +4680,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem...@@ -4681,12 +4680,11 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn, arena: Allocator) Sem
4681 func.state = .in_progress;4680 func.state = .in_progress;
4682 log.debug("set {s} to in_progress", .{decl.name});4681 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) {
4685 // TODO make these unreachable instead of @panic4684 // TODO make these unreachable instead of @panic
4686 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),4685 error.NeededSourceLocation => @panic("zig compiler bug: NeededSourceLocation"),
4687 error.GenericPoison => @panic("zig compiler bug: GenericPoison"),4686 error.GenericPoison => @panic("zig compiler bug: GenericPoison"),
4688 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),4687 error.ComptimeReturn => @panic("zig compiler bug: ComptimeReturn"),
4689 error.ComptimeBreak => @panic("zig compiler bug: ComptimeBreak"),
4690 else => |e| return e,4688 else => |e| return e,
4691 };4689 };
46924690
src/Sema.zig+63-34
...@@ -520,14 +520,14 @@ fn resolveBody(...@@ -520,14 +520,14 @@ fn resolveBody(
520 /// use to return from the body.520 /// use to return from the body.
521 body_inst: Zir.Inst.Index,521 body_inst: Zir.Inst.Index,
522) CompileError!Air.Inst.Ref {522) CompileError!Air.Inst.Ref {
523 const break_inst = try sema.analyzeBody(block, body);523 const break_data = (try sema.analyzeBodyBreak(block, body)) orelse
524 const break_data = sema.code.instructions.items(.data)[break_inst].@"break";524 return Air.Inst.Ref.unreachable_value;
525 // For comptime control flow, we need to detect when `analyzeBody` reports525 // For comptime control flow, we need to detect when `analyzeBody` reports
526 // that we need to break from an outer block. In such case we526 // that we need to break from an outer block. In such case we
527 // use Zig's error mechanism to send control flow up the stack until527 // use Zig's error mechanism to send control flow up the stack until
528 // we find the corresponding block to this break.528 // we find the corresponding block to this break.
529 if (block.is_comptime and break_data.block_inst != body_inst) {529 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;
531 return error.ComptimeBreak;531 return error.ComptimeBreak;
532 }532 }
533 return sema.resolveInst(break_data.operand);533 return sema.resolveInst(break_data.operand);
...@@ -537,11 +537,37 @@ pub fn analyzeBody(...@@ -537,11 +537,37 @@ pub fn analyzeBody(
537 sema: *Sema,537 sema: *Sema,
538 block: *Block,538 block: *Block,
539 body: []const Zir.Inst.Index,539 body: []const Zir.Inst.Index,
540) CompileError!Zir.Inst.Index {540) !void {
541 return sema.analyzeBodyInner(block, body) catch |err| switch (err) {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) {
542 error.ComptimeBreak => sema.comptime_break_inst,559 error.ComptimeBreak => sema.comptime_break_inst,
543 else => |e| return e,560 else => |e| return e,
544 };561 };
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 };
545}571}
546572
547/// ZIR instructions which are always `noreturn` return this. This matches the573/// ZIR instructions which are always `noreturn` return this. This matches the
...@@ -1045,12 +1071,12 @@ fn analyzeBodyInner(...@@ -1045,12 +1071,12 @@ fn analyzeBodyInner(
1045 const inst_data = datas[inst].pl_node;1071 const inst_data = datas[inst].pl_node;
1046 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);1072 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
1047 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];1073 const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
1048 const break_inst = try sema.analyzeBody(block, inline_body);1074 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1049 const break_data = datas[break_inst].@"break";1075 break always_noreturn;
1050 if (inst == break_data.block_inst) {1076 if (inst == break_data.block_inst) {
1051 break :blk sema.resolveInst(break_data.operand);1077 break :blk sema.resolveInst(break_data.operand);
1052 } else {1078 } else {
1053 break break_inst;1079 break break_data.inst;
1054 }1080 }
1055 },1081 },
1056 .block => blk: {1082 .block => blk: {
...@@ -1068,12 +1094,12 @@ fn analyzeBodyInner(...@@ -1068,12 +1094,12 @@ fn analyzeBodyInner(
1068 block.params.deinit(sema.gpa);1094 block.params.deinit(sema.gpa);
1069 block.params = prev_params;1095 block.params = prev_params;
1070 }1096 }
1071 const break_inst = try sema.analyzeBody(block, inline_body);1097 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1072 const break_data = datas[break_inst].@"break";1098 break always_noreturn;
1073 if (inst == break_data.block_inst) {1099 if (inst == break_data.block_inst) {
1074 break :blk sema.resolveInst(break_data.operand);1100 break :blk sema.resolveInst(break_data.operand);
1075 } else {1101 } else {
1076 break break_inst;1102 break break_data.inst;
1077 }1103 }
1078 },1104 },
1079 .block_inline => blk: {1105 .block_inline => blk: {
...@@ -1090,12 +1116,12 @@ fn analyzeBodyInner(...@@ -1090,12 +1116,12 @@ fn analyzeBodyInner(
1090 block.params.deinit(sema.gpa);1116 block.params.deinit(sema.gpa);
1091 block.params = prev_params;1117 block.params = prev_params;
1092 }1118 }
1093 const break_inst = try sema.analyzeBody(block, inline_body);1119 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1094 const break_data = datas[break_inst].@"break";1120 break always_noreturn;
1095 if (inst == break_data.block_inst) {1121 if (inst == break_data.block_inst) {
1096 break :blk sema.resolveInst(break_data.operand);1122 break :blk sema.resolveInst(break_data.operand);
1097 } else {1123 } else {
1098 break break_inst;1124 break break_data.inst;
1099 }1125 }
1100 },1126 },
1101 .condbr => blk: {1127 .condbr => blk: {
...@@ -1108,12 +1134,12 @@ fn analyzeBodyInner(...@@ -1108,12 +1134,12 @@ fn analyzeBodyInner(
1108 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1134 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1109 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);1135 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
1110 const inline_body = if (cond.val.toBool()) then_body else else_body;1136 const inline_body = if (cond.val.toBool()) then_body else else_body;
1111 const break_inst = try sema.analyzeBody(block, inline_body);1137 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1112 const break_data = datas[break_inst].@"break";1138 break always_noreturn;
1113 if (inst == break_data.block_inst) {1139 if (inst == break_data.block_inst) {
1114 break :blk sema.resolveInst(break_data.operand);1140 break :blk sema.resolveInst(break_data.operand);
1115 } else {1141 } else {
1116 break break_inst;1142 break break_data.inst;
1117 }1143 }
1118 },1144 },
1119 .condbr_inline => blk: {1145 .condbr_inline => blk: {
...@@ -1124,12 +1150,12 @@ fn analyzeBodyInner(...@@ -1124,12 +1150,12 @@ fn analyzeBodyInner(
1124 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];1150 const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len];
1125 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);1151 const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition);
1126 const inline_body = if (cond.val.toBool()) then_body else else_body;1152 const inline_body = if (cond.val.toBool()) then_body else else_body;
1127 const break_inst = try sema.analyzeBody(block, inline_body);1153 const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
1128 const break_data = datas[break_inst].@"break";1154 break always_noreturn;
1129 if (inst == break_data.block_inst) {1155 if (inst == break_data.block_inst) {
1130 break :blk sema.resolveInst(break_data.operand);1156 break :blk sema.resolveInst(break_data.operand);
1131 } else {1157 } else {
1132 break break_inst;1158 break break_data.inst;
1133 }1159 }
1134 },1160 },
1135 };1161 };
...@@ -1915,7 +1941,7 @@ fn zirEnumDecl(...@@ -1915,7 +1941,7 @@ fn zirEnumDecl(
1915 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions1941 defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions
19161942
1917 if (body.len != 0) {1943 if (body.len != 0) {
1918 _ = try sema.analyzeBody(&enum_block, body);1944 try sema.analyzeBody(&enum_block, body);
1919 }1945 }
19201946
1921 try wip_captures.finalize();1947 try wip_captures.finalize();
...@@ -3639,7 +3665,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError...@@ -3639,7 +3665,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
3639 var loop_block = child_block.makeSubBlock();3665 var loop_block = child_block.makeSubBlock();
3640 defer loop_block.instructions.deinit(gpa);3666 defer loop_block.instructions.deinit(gpa);
36413667
3642 _ = try sema.analyzeBody(&loop_block, body);3668 try sema.analyzeBody(&loop_block, body);
36433669
3644 try child_block.instructions.append(gpa, loop_inst);3670 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...@@ -3681,7 +3707,8 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
3681 };3707 };
3682 defer child_block.instructions.deinit(sema.gpa);3708 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
3686 const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err|3713 const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err|
3687 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});3714 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
...@@ -4658,9 +4685,8 @@ fn analyzeCall(...@@ -4658,9 +4685,8 @@ fn analyzeCall(
4658 }4685 }
46594686
4660 const result = result: {4687 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) {
4662 error.ComptimeReturn => break :result inlining.comptime_result,4689 error.ComptimeReturn => break :result inlining.comptime_result,
4663 error.ComptimeBreak => unreachable, // Can't break through a fn call.
4664 error.AnalysisFail => {4690 error.AnalysisFail => {
4665 const err_msg = inlining.err orelse return err;4691 const err_msg = inlining.err orelse return err;
4666 try sema.errNote(block, call_src, err_msg, "called from here", .{});4692 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...@@ -7313,7 +7339,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
7313 const item = sema.resolveInst(item_ref);7339 const item = sema.resolveInst(item_ref);
7314 // `item` is already guaranteed to be constant known.7340 // `item` is already guaranteed to be constant known.
73157341
7316 _ = try sema.analyzeBody(&case_block, body);7342 try sema.analyzeBody(&case_block, body);
73177343
7318 try wip_captures.finalize();7344 try wip_captures.finalize();
73197345
...@@ -7356,7 +7382,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7356,7 +7382,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
73567382
7357 const body = sema.code.extra[extra_index..][0..body_len];7383 const body = sema.code.extra[extra_index..][0..body_len];
7358 extra_index += body_len;7384 extra_index += body_len;
7359 _ = try sema.analyzeBody(&case_block, body);7385 try sema.analyzeBody(&case_block, body);
73607386
7361 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +7387 try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len +
7362 case_block.instructions.items.len);7388 case_block.instructions.items.len);
...@@ -7431,7 +7457,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7431,7 +7457,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
74317457
7432 const body = sema.code.extra[extra_index..][0..body_len];7458 const body = sema.code.extra[extra_index..][0..body_len];
7433 extra_index += body_len;7459 extra_index += body_len;
7434 _ = try sema.analyzeBody(&case_block, body);7460 try sema.analyzeBody(&case_block, body);
74357461
7436 try wip_captures.finalize();7462 try wip_captures.finalize();
74377463
...@@ -7468,7 +7494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -7468,7 +7494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
7468 case_block.wip_capture_scope = wip_captures.scope;7494 case_block.wip_capture_scope = wip_captures.scope;
74697495
7470 if (special.body.len != 0) {7496 if (special.body.len != 0) {
7471 _ = try sema.analyzeBody(&case_block, special.body);7497 try sema.analyzeBody(&case_block, special.body);
7472 } else {7498 } else {
7473 // We still need a terminator in this block, but we have proven7499 // We still need a terminator in this block, but we have proven
7474 // that it is unreachable.7500 // that it is unreachable.
...@@ -10990,7 +11016,8 @@ fn zirTypeofPeer(...@@ -10990,7 +11016,8 @@ fn zirTypeofPeer(
10990 .is_typeof = true,11016 .is_typeof = true,
10991 };11017 };
10992 defer child_block.instructions.deinit(sema.gpa);11018 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
10995 const args = sema.code.refSlice(extra.end, extended.small);11022 const args = sema.code.refSlice(extra.end, extended.small);
1099611023
...@@ -11186,6 +11213,8 @@ fn zirCondbr(...@@ -11186,6 +11213,8 @@ fn zirCondbr(
1118611213
11187 if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {11214 if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| {
11188 const body = if (cond_val.toBool()) then_body else else_body;11215 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.
11189 return sema.analyzeBodyInner(parent_block, body);11218 return sema.analyzeBodyInner(parent_block, body);
11190 }11219 }
1119111220
...@@ -11199,11 +11228,11 @@ fn zirCondbr(...@@ -11199,11 +11228,11 @@ fn zirCondbr(
11199 sub_block.runtime_index += 1;11228 sub_block.runtime_index += 1;
11200 defer sub_block.instructions.deinit(gpa);11229 defer sub_block.instructions.deinit(gpa);
1120111230
11202 _ = try sema.analyzeBody(&sub_block, then_body);11231 try sema.analyzeBody(&sub_block, then_body);
11203 const true_instructions = sub_block.instructions.toOwnedSlice(gpa);11232 const true_instructions = sub_block.instructions.toOwnedSlice(gpa);
11204 defer gpa.free(true_instructions);11233 defer gpa.free(true_instructions);
1120511234
11206 _ = try sema.analyzeBody(&sub_block, else_body);11235 try sema.analyzeBody(&sub_block, else_body);
11207 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +11236 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
11208 true_instructions.len + sub_block.instructions.items.len);11237 true_instructions.len + sub_block.instructions.items.len);
11209 _ = try parent_block.addInst(.{11238 _ = try parent_block.addInst(.{
...@@ -19186,7 +19215,7 @@ fn semaStructFields(...@@ -19186,7 +19215,7 @@ fn semaStructFields(
19186 }19215 }
1918719216
19188 if (body.len != 0) {19217 if (body.len != 0) {
19189 _ = try sema.analyzeBody(&block_scope, body);19218 try sema.analyzeBody(&block_scope, body);
19190 }19219 }
1919119220
19192 try wip_captures.finalize();19221 try wip_captures.finalize();
...@@ -19360,7 +19389,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {...@@ -19360,7 +19389,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
19360 }19389 }
1936119390
19362 if (body.len != 0) {19391 if (body.len != 0) {
19363 _ = try sema.analyzeBody(&block_scope, body);19392 try sema.analyzeBody(&block_scope, body);
19364 }19393 }
1936519394
19366 try wip_captures.finalize();19395 try wip_captures.finalize();
test/behavior.zig+1
...@@ -46,6 +46,7 @@ test {...@@ -46,6 +46,7 @@ test {
46 _ = @import("behavior/bugs/4954.zig");46 _ = @import("behavior/bugs/4954.zig");
47 _ = @import("behavior/bugs/6850.zig");47 _ = @import("behavior/bugs/6850.zig");
48 _ = @import("behavior/bugs/7250.zig");48 _ = @import("behavior/bugs/7250.zig");
49 _ = @import("behavior/bugs/11100.zig");
49 _ = @import("behavior/call.zig");50 _ = @import("behavior/call.zig");
50 _ = @import("behavior/cast.zig");51 _ = @import("behavior/cast.zig");
51 _ = @import("behavior/comptime_memory.zig");52 _ = @import("behavior/comptime_memory.zig");
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}