| author | |
| committer | |
| log | 5316a00a188955d60cc38d56def51b8605181225 |
| tree | d26f110e2472fe5ea0853056ab86924f17e046c0 |
| parent | 28054d96f0ed5280660811612732cb000f9c09e8 |
4 files changed, 111 insertions(+), 5 deletions(-)
src/AstGen.zig+39-2| ... | ... | @@ -2471,6 +2471,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2471 | 2471 | .try_ptr, |
| 2472 | 2472 | //.try_inline, |
| 2473 | 2473 | //.try_ptr_inline, |
| 2474 | .save_err_ret_index, | |
| 2474 | 2475 | => break :b false, |
| 2475 | 2476 | |
| 2476 | 2477 | .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { |
| ... | ... | @@ -2533,6 +2534,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2533 | 2534 | .validate_array_init_ty, |
| 2534 | 2535 | .validate_struct_init_ty, |
| 2535 | 2536 | .validate_deref, |
| 2537 | .restore_err_ret_index, | |
| 2536 | 2538 | => break :b true, |
| 2537 | 2539 | |
| 2538 | 2540 | .@"defer" => unreachable, |
| ... | ... | @@ -5152,10 +5154,16 @@ fn orelseCatchExpr( |
| 5152 | 5154 | const astgen = parent_gz.astgen; |
| 5153 | 5155 | const tree = astgen.tree; |
| 5154 | 5156 | |
| 5157 | const do_err_trace = astgen.fn_block != null and (cond_op == .is_non_err or cond_op == .is_non_err_ptr); | |
| 5158 | ||
| 5155 | 5159 | var block_scope = parent_gz.makeSubBlock(scope); |
| 5156 | 5160 | block_scope.setBreakResultLoc(rl); |
| 5157 | 5161 | defer block_scope.unstack(); |
| 5158 | 5162 | |
| 5163 | if (do_err_trace) { | |
| 5164 | block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node); | |
| 5165 | } | |
| 5166 | ||
| 5159 | 5167 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 5160 | 5168 | .ref => .ref, |
| 5161 | 5169 | else => .none, |
| ... | ... | @@ -5220,7 +5228,7 @@ fn orelseCatchExpr( |
| 5220 | 5228 | // instructions or not. |
| 5221 | 5229 | |
| 5222 | 5230 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; |
| 5223 | return finishThenElseBlock( | |
| 5231 | const result = try finishThenElseBlock( | |
| 5224 | 5232 | parent_gz, |
| 5225 | 5233 | rl, |
| 5226 | 5234 | node, |
| ... | ... | @@ -5235,6 +5243,16 @@ fn orelseCatchExpr( |
| 5235 | 5243 | block, |
| 5236 | 5244 | break_tag, |
| 5237 | 5245 | ); |
| 5246 | if (do_err_trace) { | |
| 5247 | _ = try parent_gz.add(.{ | |
| 5248 | .tag = .restore_err_ret_index, | |
| 5249 | .data = .{ .un_node = .{ | |
| 5250 | .operand = parent_gz.saved_err_trace_index, | |
| 5251 | .src_node = parent_gz.nodeIndexToRelative(node), | |
| 5252 | } }, | |
| 5253 | }); | |
| 5254 | } | |
| 5255 | return result; | |
| 5238 | 5256 | } |
| 5239 | 5257 | |
| 5240 | 5258 | /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. |
| ... | ... | @@ -5430,10 +5448,16 @@ fn ifExpr( |
| 5430 | 5448 | const tree = astgen.tree; |
| 5431 | 5449 | const token_tags = tree.tokens.items(.tag); |
| 5432 | 5450 | |
| 5451 | const do_err_trace = astgen.fn_block != null and if_full.error_token != null; | |
| 5452 | ||
| 5433 | 5453 | var block_scope = parent_gz.makeSubBlock(scope); |
| 5434 | 5454 | block_scope.setBreakResultLoc(rl); |
| 5435 | 5455 | defer block_scope.unstack(); |
| 5436 | 5456 | |
| 5457 | if (do_err_trace) { | |
| 5458 | block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node); | |
| 5459 | } | |
| 5460 | ||
| 5437 | 5461 | const payload_is_ref = if (if_full.payload_token) |payload_token| |
| 5438 | 5462 | token_tags[payload_token] == .asterisk |
| 5439 | 5463 | else |
| ... | ... | @@ -5602,7 +5626,7 @@ fn ifExpr( |
| 5602 | 5626 | }; |
| 5603 | 5627 | |
| 5604 | 5628 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; |
| 5605 | return finishThenElseBlock( | |
| 5629 | const result = try finishThenElseBlock( | |
| 5606 | 5630 | parent_gz, |
| 5607 | 5631 | rl, |
| 5608 | 5632 | node, |
| ... | ... | @@ -5617,6 +5641,16 @@ fn ifExpr( |
| 5617 | 5641 | block, |
| 5618 | 5642 | break_tag, |
| 5619 | 5643 | ); |
| 5644 | if (do_err_trace) { | |
| 5645 | _ = try parent_gz.add(.{ | |
| 5646 | .tag = .restore_err_ret_index, | |
| 5647 | .data = .{ .un_node = .{ | |
| 5648 | .operand = parent_gz.saved_err_trace_index, | |
| 5649 | .src_node = parent_gz.nodeIndexToRelative(node), | |
| 5650 | } }, | |
| 5651 | }); | |
| 5652 | } | |
| 5653 | return result; | |
| 5620 | 5654 | } |
| 5621 | 5655 | |
| 5622 | 5656 | /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. |
| ... | ... | @@ -10300,6 +10334,8 @@ const GenZir = struct { |
| 10300 | 10334 | /// Keys are the raw instruction index, values are the closure_capture instruction. |
| 10301 | 10335 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, |
| 10302 | 10336 | |
| 10337 | saved_err_trace_index: Zir.Inst.Ref = .none, | |
| 10338 | ||
| 10303 | 10339 | const unstacked_top = std.math.maxInt(usize); |
| 10304 | 10340 | /// Call unstack before adding any new instructions to containing GenZir. |
| 10305 | 10341 | fn unstack(self: *GenZir) void { |
| ... | ... | @@ -10344,6 +10380,7 @@ const GenZir = struct { |
| 10344 | 10380 | .any_defer_node = gz.any_defer_node, |
| 10345 | 10381 | .instructions = gz.instructions, |
| 10346 | 10382 | .instructions_top = gz.instructions.items.len, |
| 10383 | .saved_err_trace_index = gz.saved_err_trace_index, | |
| 10347 | 10384 | }; |
| 10348 | 10385 | } |
| 10349 | 10386 |
src/Sema.zig+53-2| ... | ... | @@ -926,6 +926,8 @@ fn analyzeBodyInner( |
| 926 | 926 | .ret_ptr => try sema.zirRetPtr(block, inst), |
| 927 | 927 | .ret_type => try sema.addType(sema.fn_ret_ty), |
| 928 | 928 | |
| 929 | .save_err_ret_index => try sema.zirSaveErrRetIndex(block, inst), | |
| 930 | ||
| 929 | 931 | // Instructions that we know to *always* be noreturn based solely on their tag. |
| 930 | 932 | // These functions match the return type of analyzeBody so that we can |
| 931 | 933 | // tail call them here. |
| ... | ... | @@ -1208,6 +1210,11 @@ fn analyzeBodyInner( |
| 1208 | 1210 | i += 1; |
| 1209 | 1211 | continue; |
| 1210 | 1212 | }, |
| 1213 | .restore_err_ret_index => { | |
| 1214 | try sema.zirRestoreErrRetIndex(block, inst); | |
| 1215 | i += 1; | |
| 1216 | continue; | |
| 1217 | }, | |
| 1211 | 1218 | |
| 1212 | 1219 | // Special case instructions to handle comptime control flow. |
| 1213 | 1220 | .@"break" => { |
| ... | ... | @@ -16176,6 +16183,52 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { |
| 16176 | 16183 | backend_supports_error_return_tracing; |
| 16177 | 16184 | } |
| 16178 | 16185 | |
| 16186 | fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 16187 | const inst_data = sema.code.instructions.items(.data)[inst].node; | |
| 16188 | const src = LazySrcLoc.nodeOffset(inst_data); | |
| 16189 | ||
| 16190 | // This is only relevant at runtime. | |
| 16191 | if (block.is_comptime) return Air.Inst.Ref.zero_usize; | |
| 16192 | ||
| 16193 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; | |
| 16194 | const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and | |
| 16195 | sema.mod.comp.bin_file.options.error_return_tracing and | |
| 16196 | backend_supports_error_return_tracing; | |
| 16197 | if (!ok) return Air.Inst.Ref.zero_usize; | |
| 16198 | ||
| 16199 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); | |
| 16200 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); | |
| 16201 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | |
| 16202 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | |
| 16203 | return sema.fieldVal(block, src, err_return_trace, "index", src); | |
| 16204 | } | |
| 16205 | ||
| 16206 | fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { | |
| 16207 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 16208 | const src = inst_data.src(); | |
| 16209 | ||
| 16210 | // This is only relevant at runtime. | |
| 16211 | if (block.is_comptime) return; | |
| 16212 | ||
| 16213 | const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm; | |
| 16214 | const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and | |
| 16215 | sema.mod.comp.bin_file.options.error_return_tracing and | |
| 16216 | backend_supports_error_return_tracing; | |
| 16217 | if (!ok) return; | |
| 16218 | ||
| 16219 | const operand = if (inst_data.operand != .none) | |
| 16220 | try sema.resolveInst(inst_data.operand) | |
| 16221 | else | |
| 16222 | .zero_usize; | |
| 16223 | ||
| 16224 | const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace"); | |
| 16225 | const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty); | |
| 16226 | const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty); | |
| 16227 | const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); | |
| 16228 | const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true); | |
| 16229 | try sema.storePtr2(block, src, field_ptr, src, operand, src, .store); | |
| 16230 | } | |
| 16231 | ||
| 16179 | 16232 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 16180 | 16233 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); |
| 16181 | 16234 | |
| ... | ... | @@ -17181,8 +17234,6 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17181 | 17234 | |
| 17182 | 17235 | fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17183 | 17236 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 17184 | const src = inst_data.src(); | |
| 17185 | _ = src; | |
| 17186 | 17237 | const operand = try sema.resolveInst(inst_data.operand); |
| 17187 | 17238 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; |
| 17188 | 17239 |
src/Zir.zig+16| ... | ... | @@ -988,6 +988,15 @@ pub const Inst = struct { |
| 988 | 988 | /// Uses the `err_defer_code` union field. |
| 989 | 989 | defer_err_code, |
| 990 | 990 | |
| 991 | /// Saves the current error return case if it exists, | |
| 992 | /// otherwise just returns zero. | |
| 993 | /// Uses the `node` union field. | |
| 994 | save_err_ret_index, | |
| 995 | /// Sets error return trace to zero if no operand is given, | |
| 996 | /// otherwise sets the value to the given amount. | |
| 997 | /// Uses the `un_node` union field. | |
| 998 | restore_err_ret_index, | |
| 999 | ||
| 991 | 1000 | /// The ZIR instruction tag is one of the `Extended` ones. |
| 992 | 1001 | /// Uses the `extended` union field. |
| 993 | 1002 | extended, |
| ... | ... | @@ -1236,6 +1245,8 @@ pub const Inst = struct { |
| 1236 | 1245 | //.try_ptr_inline, |
| 1237 | 1246 | .@"defer", |
| 1238 | 1247 | .defer_err_code, |
| 1248 | .save_err_ret_index, | |
| 1249 | .restore_err_ret_index, | |
| 1239 | 1250 | => false, |
| 1240 | 1251 | |
| 1241 | 1252 | .@"break", |
| ... | ... | @@ -1305,6 +1316,7 @@ pub const Inst = struct { |
| 1305 | 1316 | .check_comptime_control_flow, |
| 1306 | 1317 | .@"defer", |
| 1307 | 1318 | .defer_err_code, |
| 1319 | .restore_err_ret_index, | |
| 1308 | 1320 | => true, |
| 1309 | 1321 | |
| 1310 | 1322 | .param, |
| ... | ... | @@ -1530,6 +1542,7 @@ pub const Inst = struct { |
| 1530 | 1542 | .try_ptr, |
| 1531 | 1543 | //.try_inline, |
| 1532 | 1544 | //.try_ptr_inline, |
| 1545 | .save_err_ret_index, | |
| 1533 | 1546 | => false, |
| 1534 | 1547 | |
| 1535 | 1548 | .extended => switch (data.extended.opcode) { |
| ... | ... | @@ -1810,6 +1823,9 @@ pub const Inst = struct { |
| 1810 | 1823 | .@"defer" = .@"defer", |
| 1811 | 1824 | .defer_err_code = .defer_err_code, |
| 1812 | 1825 | |
| 1826 | .save_err_ret_index = .node, | |
| 1827 | .restore_err_ret_index = .un_node, | |
| 1828 | ||
| 1813 | 1829 | .extended = .extended, |
| 1814 | 1830 | }); |
| 1815 | 1831 | }; |
src/print_zir.zig+3-1| ... | ... | @@ -232,6 +232,7 @@ const Writer = struct { |
| 232 | 232 | .validate_deref, |
| 233 | 233 | .overflow_arithmetic_ptr, |
| 234 | 234 | .check_comptime_control_flow, |
| 235 | .restore_err_ret_index, | |
| 235 | 236 | => try self.writeUnNode(stream, inst), |
| 236 | 237 | |
| 237 | 238 | .ref, |
| ... | ... | @@ -405,6 +406,7 @@ const Writer = struct { |
| 405 | 406 | .alloc_inferred_comptime_mut, |
| 406 | 407 | .ret_ptr, |
| 407 | 408 | .ret_type, |
| 409 | .save_err_ret_index, | |
| 408 | 410 | => try self.writeNode(stream, inst), |
| 409 | 411 | |
| 410 | 412 | .error_value, |
| ... | ... | @@ -440,7 +442,7 @@ const Writer = struct { |
| 440 | 442 | |
| 441 | 443 | .dbg_block_begin, |
| 442 | 444 | .dbg_block_end, |
| 443 | => try stream.writeAll("))"), | |
| 445 | => try stream.writeAll(")"), | |
| 444 | 446 | |
| 445 | 447 | .closure_get => try self.writeInstNode(stream, inst), |
| 446 | 448 |