| ... | ... | @@ -520,14 +520,14 @@ fn resolveBody( |
| 520 | 520 | /// use to return from the body. |
| 521 | 521 | body_inst: Zir.Inst.Index, |
| 522 | 522 | ) 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; |
| 525 | 525 | // For comptime control flow, we need to detect when `analyzeBody` reports |
| 526 | 526 | // that we need to break from an outer block. In such case we |
| 527 | 527 | // use Zig's error mechanism to send control flow up the stack until |
| 528 | 528 | // we find the corresponding block to this break. |
| 529 | 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 | 531 | return error.ComptimeBreak; |
| 532 | 532 | } |
| 533 | 533 | return sema.resolveInst(break_data.operand); |
| ... | ... | @@ -537,11 +537,37 @@ pub fn analyzeBody( |
| 537 | 537 | sema: *Sema, |
| 538 | 538 | block: *Block, |
| 539 | 539 | 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 | |
| 547 | const BreakData = struct { |
| 548 | block_inst: Zir.Inst.Index, |
| 549 | operand: Air.Inst.Ref, |
| 550 | inst: Air.Inst.Index, |
| 551 | }; |
| 552 | |
| 553 | pub 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 | 559 | error.ComptimeBreak => sema.comptime_break_inst, |
| 543 | 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 | } |
| 546 | 572 | |
| 547 | 573 | /// ZIR instructions which are always `noreturn` return this. This matches the |
| ... | ... | @@ -1045,12 +1071,12 @@ fn analyzeBodyInner( |
| 1045 | 1071 | const inst_data = datas[inst].pl_node; |
| 1046 | 1072 | const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); |
| 1047 | 1073 | 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; |
| 1050 | 1076 | if (inst == break_data.block_inst) { |
| 1051 | 1077 | break :blk sema.resolveInst(break_data.operand); |
| 1052 | 1078 | } else { |
| 1053 | | break break_inst; |
| 1079 | break break_data.inst; |
| 1054 | 1080 | } |
| 1055 | 1081 | }, |
| 1056 | 1082 | .block => blk: { |
| ... | ... | @@ -1068,12 +1094,12 @@ fn analyzeBodyInner( |
| 1068 | 1094 | block.params.deinit(sema.gpa); |
| 1069 | 1095 | block.params = prev_params; |
| 1070 | 1096 | } |
| 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; |
| 1073 | 1099 | if (inst == break_data.block_inst) { |
| 1074 | 1100 | break :blk sema.resolveInst(break_data.operand); |
| 1075 | 1101 | } else { |
| 1076 | | break break_inst; |
| 1102 | break break_data.inst; |
| 1077 | 1103 | } |
| 1078 | 1104 | }, |
| 1079 | 1105 | .block_inline => blk: { |
| ... | ... | @@ -1090,12 +1116,12 @@ fn analyzeBodyInner( |
| 1090 | 1116 | block.params.deinit(sema.gpa); |
| 1091 | 1117 | block.params = prev_params; |
| 1092 | 1118 | } |
| 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; |
| 1095 | 1121 | if (inst == break_data.block_inst) { |
| 1096 | 1122 | break :blk sema.resolveInst(break_data.operand); |
| 1097 | 1123 | } else { |
| 1098 | | break break_inst; |
| 1124 | break break_data.inst; |
| 1099 | 1125 | } |
| 1100 | 1126 | }, |
| 1101 | 1127 | .condbr => blk: { |
| ... | ... | @@ -1108,12 +1134,12 @@ fn analyzeBodyInner( |
| 1108 | 1134 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 1109 | 1135 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); |
| 1110 | 1136 | 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; |
| 1113 | 1139 | if (inst == break_data.block_inst) { |
| 1114 | 1140 | break :blk sema.resolveInst(break_data.operand); |
| 1115 | 1141 | } else { |
| 1116 | | break break_inst; |
| 1142 | break break_data.inst; |
| 1117 | 1143 | } |
| 1118 | 1144 | }, |
| 1119 | 1145 | .condbr_inline => blk: { |
| ... | ... | @@ -1124,12 +1150,12 @@ fn analyzeBodyInner( |
| 1124 | 1150 | const else_body = sema.code.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 1125 | 1151 | const cond = try sema.resolveInstConst(block, cond_src, extra.data.condition); |
| 1126 | 1152 | 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; |
| 1129 | 1155 | if (inst == break_data.block_inst) { |
| 1130 | 1156 | break :blk sema.resolveInst(break_data.operand); |
| 1131 | 1157 | } else { |
| 1132 | | break break_inst; |
| 1158 | break break_data.inst; |
| 1133 | 1159 | } |
| 1134 | 1160 | }, |
| 1135 | 1161 | }; |
| ... | ... | @@ -1915,7 +1941,7 @@ fn zirEnumDecl( |
| 1915 | 1941 | defer assert(enum_block.instructions.items.len == 0); // should all be comptime instructions |
| 1916 | 1942 | |
| 1917 | 1943 | if (body.len != 0) { |
| 1918 | | _ = try sema.analyzeBody(&enum_block, body); |
| 1944 | try sema.analyzeBody(&enum_block, body); |
| 1919 | 1945 | } |
| 1920 | 1946 | |
| 1921 | 1947 | try wip_captures.finalize(); |
| ... | ... | @@ -3639,7 +3665,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError |
| 3639 | 3665 | var loop_block = child_block.makeSubBlock(); |
| 3640 | 3666 | defer loop_block.instructions.deinit(gpa); |
| 3641 | 3667 | |
| 3642 | | _ = try sema.analyzeBody(&loop_block, body); |
| 3668 | try sema.analyzeBody(&loop_block, body); |
| 3643 | 3669 | |
| 3644 | 3670 | try child_block.instructions.append(gpa, loop_inst); |
| 3645 | 3671 | |
| ... | ... | @@ -3681,7 +3707,8 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 3681 | 3707 | }; |
| 3682 | 3708 | defer child_block.instructions.deinit(sema.gpa); |
| 3683 | 3709 | |
| 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); |
| 3685 | 3712 | |
| 3686 | 3713 | const c_import_res = sema.mod.comp.cImport(c_import_buf.items) catch |err| |
| 3687 | 3714 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| ... | ... | @@ -4658,9 +4685,8 @@ fn analyzeCall( |
| 4658 | 4685 | } |
| 4659 | 4686 | |
| 4660 | 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 | 4689 | error.ComptimeReturn => break :result inlining.comptime_result, |
| 4663 | | error.ComptimeBreak => unreachable, // Can't break through a fn call. |
| 4664 | 4690 | error.AnalysisFail => { |
| 4665 | 4691 | const err_msg = inlining.err orelse return err; |
| 4666 | 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 | 7339 | const item = sema.resolveInst(item_ref); |
| 7314 | 7340 | // `item` is already guaranteed to be constant known. |
| 7315 | 7341 | |
| 7316 | | _ = try sema.analyzeBody(&case_block, body); |
| 7342 | try sema.analyzeBody(&case_block, body); |
| 7317 | 7343 | |
| 7318 | 7344 | try wip_captures.finalize(); |
| 7319 | 7345 | |
| ... | ... | @@ -7356,7 +7382,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 7356 | 7382 | |
| 7357 | 7383 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 7358 | 7384 | extra_index += body_len; |
| 7359 | | _ = try sema.analyzeBody(&case_block, body); |
| 7385 | try sema.analyzeBody(&case_block, body); |
| 7360 | 7386 | |
| 7361 | 7387 | try cases_extra.ensureUnusedCapacity(gpa, 2 + items.len + |
| 7362 | 7388 | case_block.instructions.items.len); |
| ... | ... | @@ -7431,7 +7457,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 7431 | 7457 | |
| 7432 | 7458 | const body = sema.code.extra[extra_index..][0..body_len]; |
| 7433 | 7459 | extra_index += body_len; |
| 7434 | | _ = try sema.analyzeBody(&case_block, body); |
| 7460 | try sema.analyzeBody(&case_block, body); |
| 7435 | 7461 | |
| 7436 | 7462 | try wip_captures.finalize(); |
| 7437 | 7463 | |
| ... | ... | @@ -7468,7 +7494,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 7468 | 7494 | case_block.wip_capture_scope = wip_captures.scope; |
| 7469 | 7495 | |
| 7470 | 7496 | if (special.body.len != 0) { |
| 7471 | | _ = try sema.analyzeBody(&case_block, special.body); |
| 7497 | try sema.analyzeBody(&case_block, special.body); |
| 7472 | 7498 | } else { |
| 7473 | 7499 | // We still need a terminator in this block, but we have proven |
| 7474 | 7500 | // that it is unreachable. |
| ... | ... | @@ -10990,7 +11016,8 @@ fn zirTypeofPeer( |
| 10990 | 11016 | .is_typeof = true, |
| 10991 | 11017 | }; |
| 10992 | 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); |
| 10994 | 11021 | |
| 10995 | 11022 | const args = sema.code.refSlice(extra.end, extended.small); |
| 10996 | 11023 | |
| ... | ... | @@ -11186,6 +11213,8 @@ fn zirCondbr( |
| 11186 | 11213 | |
| 11187 | 11214 | if (try sema.resolveDefinedValue(parent_block, src, cond)) |cond_val| { |
| 11188 | 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 | 11218 | return sema.analyzeBodyInner(parent_block, body); |
| 11190 | 11219 | } |
| 11191 | 11220 | |
| ... | ... | @@ -11199,11 +11228,11 @@ fn zirCondbr( |
| 11199 | 11228 | sub_block.runtime_index += 1; |
| 11200 | 11229 | defer sub_block.instructions.deinit(gpa); |
| 11201 | 11230 | |
| 11202 | | _ = try sema.analyzeBody(&sub_block, then_body); |
| 11231 | try sema.analyzeBody(&sub_block, then_body); |
| 11203 | 11232 | const true_instructions = sub_block.instructions.toOwnedSlice(gpa); |
| 11204 | 11233 | defer gpa.free(true_instructions); |
| 11205 | 11234 | |
| 11206 | | _ = try sema.analyzeBody(&sub_block, else_body); |
| 11235 | try sema.analyzeBody(&sub_block, else_body); |
| 11207 | 11236 | try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + |
| 11208 | 11237 | true_instructions.len + sub_block.instructions.items.len); |
| 11209 | 11238 | _ = try parent_block.addInst(.{ |
| ... | ... | @@ -19186,7 +19215,7 @@ fn semaStructFields( |
| 19186 | 19215 | } |
| 19187 | 19216 | |
| 19188 | 19217 | if (body.len != 0) { |
| 19189 | | _ = try sema.analyzeBody(&block_scope, body); |
| 19218 | try sema.analyzeBody(&block_scope, body); |
| 19190 | 19219 | } |
| 19191 | 19220 | |
| 19192 | 19221 | try wip_captures.finalize(); |
| ... | ... | @@ -19360,7 +19389,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { |
| 19360 | 19389 | } |
| 19361 | 19390 | |
| 19362 | 19391 | if (body.len != 0) { |
| 19363 | | _ = try sema.analyzeBody(&block_scope, body); |
| 19392 | try sema.analyzeBody(&block_scope, body); |
| 19364 | 19393 | } |
| 19365 | 19394 | |
| 19366 | 19395 | try wip_captures.finalize(); |