| 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,6 +2471,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2471 | .try_ptr, | 2471 | .try_ptr, |
| 2472 | //.try_inline, | 2472 | //.try_inline, |
| 2473 | //.try_ptr_inline, | 2473 | //.try_ptr_inline, |
| 2474 | .save_err_ret_index, | ||
| 2474 | => break :b false, | 2475 | => break :b false, |
| 2475 | 2476 | ||
| 2476 | .extended => switch (gz.astgen.instructions.items(.data)[inst].extended.opcode) { | 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,6 +2534,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2533 | .validate_array_init_ty, | 2534 | .validate_array_init_ty, |
| 2534 | .validate_struct_init_ty, | 2535 | .validate_struct_init_ty, |
| 2535 | .validate_deref, | 2536 | .validate_deref, |
| 2537 | .restore_err_ret_index, | ||
| 2536 | => break :b true, | 2538 | => break :b true, |
| 2537 | 2539 | ||
| 2538 | .@"defer" => unreachable, | 2540 | .@"defer" => unreachable, |
| ... | @@ -5152,10 +5154,16 @@ fn orelseCatchExpr( | ... | @@ -5152,10 +5154,16 @@ fn orelseCatchExpr( |
| 5152 | const astgen = parent_gz.astgen; | 5154 | const astgen = parent_gz.astgen; |
| 5153 | const tree = astgen.tree; | 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 | var block_scope = parent_gz.makeSubBlock(scope); | 5159 | var block_scope = parent_gz.makeSubBlock(scope); |
| 5156 | block_scope.setBreakResultLoc(rl); | 5160 | block_scope.setBreakResultLoc(rl); |
| 5157 | defer block_scope.unstack(); | 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 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { | 5167 | const operand_rl: ResultLoc = switch (block_scope.break_result_loc) { |
| 5160 | .ref => .ref, | 5168 | .ref => .ref, |
| 5161 | else => .none, | 5169 | else => .none, |
| ... | @@ -5220,7 +5228,7 @@ fn orelseCatchExpr( | ... | @@ -5220,7 +5228,7 @@ fn orelseCatchExpr( |
| 5220 | // instructions or not. | 5228 | // instructions or not. |
| 5221 | 5229 | ||
| 5222 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; | 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 | parent_gz, | 5232 | parent_gz, |
| 5225 | rl, | 5233 | rl, |
| 5226 | node, | 5234 | node, |
| ... | @@ -5235,6 +5243,16 @@ fn orelseCatchExpr( | ... | @@ -5235,6 +5243,16 @@ fn orelseCatchExpr( |
| 5235 | block, | 5243 | block, |
| 5236 | break_tag, | 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 | /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`. | 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,10 +5448,16 @@ fn ifExpr( |
| 5430 | const tree = astgen.tree; | 5448 | const tree = astgen.tree; |
| 5431 | const token_tags = tree.tokens.items(.tag); | 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 | var block_scope = parent_gz.makeSubBlock(scope); | 5453 | var block_scope = parent_gz.makeSubBlock(scope); |
| 5434 | block_scope.setBreakResultLoc(rl); | 5454 | block_scope.setBreakResultLoc(rl); |
| 5435 | defer block_scope.unstack(); | 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 | const payload_is_ref = if (if_full.payload_token) |payload_token| | 5461 | const payload_is_ref = if (if_full.payload_token) |payload_token| |
| 5438 | token_tags[payload_token] == .asterisk | 5462 | token_tags[payload_token] == .asterisk |
| 5439 | else | 5463 | else |
| ... | @@ -5602,7 +5626,7 @@ fn ifExpr( | ... | @@ -5602,7 +5626,7 @@ fn ifExpr( |
| 5602 | }; | 5626 | }; |
| 5603 | 5627 | ||
| 5604 | const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break"; | 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 | parent_gz, | 5630 | parent_gz, |
| 5607 | rl, | 5631 | rl, |
| 5608 | node, | 5632 | node, |
| ... | @@ -5617,6 +5641,16 @@ fn ifExpr( | ... | @@ -5617,6 +5641,16 @@ fn ifExpr( |
| 5617 | block, | 5641 | block, |
| 5618 | break_tag, | 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 | /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. | 5656 | /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`. |
| ... | @@ -10300,6 +10334,8 @@ const GenZir = struct { | ... | @@ -10300,6 +10334,8 @@ const GenZir = struct { |
| 10300 | /// Keys are the raw instruction index, values are the closure_capture instruction. | 10334 | /// Keys are the raw instruction index, values are the closure_capture instruction. |
| 10301 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, | 10335 | captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}, |
| 10302 | 10336 | ||
| 10337 | saved_err_trace_index: Zir.Inst.Ref = .none, | ||
| 10338 | |||
| 10303 | const unstacked_top = std.math.maxInt(usize); | 10339 | const unstacked_top = std.math.maxInt(usize); |
| 10304 | /// Call unstack before adding any new instructions to containing GenZir. | 10340 | /// Call unstack before adding any new instructions to containing GenZir. |
| 10305 | fn unstack(self: *GenZir) void { | 10341 | fn unstack(self: *GenZir) void { |
| ... | @@ -10344,6 +10380,7 @@ const GenZir = struct { | ... | @@ -10344,6 +10380,7 @@ const GenZir = struct { |
| 10344 | .any_defer_node = gz.any_defer_node, | 10380 | .any_defer_node = gz.any_defer_node, |
| 10345 | .instructions = gz.instructions, | 10381 | .instructions = gz.instructions, |
| 10346 | .instructions_top = gz.instructions.items.len, | 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,6 +926,8 @@ fn analyzeBodyInner( |
| 926 | .ret_ptr => try sema.zirRetPtr(block, inst), | 926 | .ret_ptr => try sema.zirRetPtr(block, inst), |
| 927 | .ret_type => try sema.addType(sema.fn_ret_ty), | 927 | .ret_type => try sema.addType(sema.fn_ret_ty), |
| 928 | 928 | ||
| 929 | .save_err_ret_index => try sema.zirSaveErrRetIndex(block, inst), | ||
| 930 | |||
| 929 | // Instructions that we know to *always* be noreturn based solely on their tag. | 931 | // Instructions that we know to *always* be noreturn based solely on their tag. |
| 930 | // These functions match the return type of analyzeBody so that we can | 932 | // These functions match the return type of analyzeBody so that we can |
| 931 | // tail call them here. | 933 | // tail call them here. |
| ... | @@ -1208,6 +1210,11 @@ fn analyzeBodyInner( | ... | @@ -1208,6 +1210,11 @@ fn analyzeBodyInner( |
| 1208 | i += 1; | 1210 | i += 1; |
| 1209 | continue; | 1211 | continue; |
| 1210 | }, | 1212 | }, |
| 1213 | .restore_err_ret_index => { | ||
| 1214 | try sema.zirRestoreErrRetIndex(block, inst); | ||
| 1215 | i += 1; | ||
| 1216 | continue; | ||
| 1217 | }, | ||
| 1211 | 1218 | ||
| 1212 | // Special case instructions to handle comptime control flow. | 1219 | // Special case instructions to handle comptime control flow. |
| 1213 | .@"break" => { | 1220 | .@"break" => { |
| ... | @@ -16176,6 +16183,52 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { | ... | @@ -16176,6 +16183,52 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool { |
| 16176 | backend_supports_error_return_tracing; | 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 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { | 16232 | fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void { |
| 16180 | assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion); | 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,8 +17234,6 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 17181 | 17234 | ||
| 17182 | fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 17235 | fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 17183 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | 17236 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 17184 | const src = inst_data.src(); | ||
| 17185 | _ = src; | ||
| 17186 | const operand = try sema.resolveInst(inst_data.operand); | 17237 | const operand = try sema.resolveInst(inst_data.operand); |
| 17187 | const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | 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,6 +988,15 @@ pub const Inst = struct { |
| 988 | /// Uses the `err_defer_code` union field. | 988 | /// Uses the `err_defer_code` union field. |
| 989 | defer_err_code, | 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 | /// The ZIR instruction tag is one of the `Extended` ones. | 1000 | /// The ZIR instruction tag is one of the `Extended` ones. |
| 992 | /// Uses the `extended` union field. | 1001 | /// Uses the `extended` union field. |
| 993 | extended, | 1002 | extended, |
| ... | @@ -1236,6 +1245,8 @@ pub const Inst = struct { | ... | @@ -1236,6 +1245,8 @@ pub const Inst = struct { |
| 1236 | //.try_ptr_inline, | 1245 | //.try_ptr_inline, |
| 1237 | .@"defer", | 1246 | .@"defer", |
| 1238 | .defer_err_code, | 1247 | .defer_err_code, |
| 1248 | .save_err_ret_index, | ||
| 1249 | .restore_err_ret_index, | ||
| 1239 | => false, | 1250 | => false, |
| 1240 | 1251 | ||
| 1241 | .@"break", | 1252 | .@"break", |
| ... | @@ -1305,6 +1316,7 @@ pub const Inst = struct { | ... | @@ -1305,6 +1316,7 @@ pub const Inst = struct { |
| 1305 | .check_comptime_control_flow, | 1316 | .check_comptime_control_flow, |
| 1306 | .@"defer", | 1317 | .@"defer", |
| 1307 | .defer_err_code, | 1318 | .defer_err_code, |
| 1319 | .restore_err_ret_index, | ||
| 1308 | => true, | 1320 | => true, |
| 1309 | 1321 | ||
| 1310 | .param, | 1322 | .param, |
| ... | @@ -1530,6 +1542,7 @@ pub const Inst = struct { | ... | @@ -1530,6 +1542,7 @@ pub const Inst = struct { |
| 1530 | .try_ptr, | 1542 | .try_ptr, |
| 1531 | //.try_inline, | 1543 | //.try_inline, |
| 1532 | //.try_ptr_inline, | 1544 | //.try_ptr_inline, |
| 1545 | .save_err_ret_index, | ||
| 1533 | => false, | 1546 | => false, |
| 1534 | 1547 | ||
| 1535 | .extended => switch (data.extended.opcode) { | 1548 | .extended => switch (data.extended.opcode) { |
| ... | @@ -1810,6 +1823,9 @@ pub const Inst = struct { | ... | @@ -1810,6 +1823,9 @@ pub const Inst = struct { |
| 1810 | .@"defer" = .@"defer", | 1823 | .@"defer" = .@"defer", |
| 1811 | .defer_err_code = .defer_err_code, | 1824 | .defer_err_code = .defer_err_code, |
| 1812 | 1825 | ||
| 1826 | .save_err_ret_index = .node, | ||
| 1827 | .restore_err_ret_index = .un_node, | ||
| 1828 | |||
| 1813 | .extended = .extended, | 1829 | .extended = .extended, |
| 1814 | }); | 1830 | }); |
| 1815 | }; | 1831 | }; |
src/print_zir.zig+3-1| ... | @@ -232,6 +232,7 @@ const Writer = struct { | ... | @@ -232,6 +232,7 @@ const Writer = struct { |
| 232 | .validate_deref, | 232 | .validate_deref, |
| 233 | .overflow_arithmetic_ptr, | 233 | .overflow_arithmetic_ptr, |
| 234 | .check_comptime_control_flow, | 234 | .check_comptime_control_flow, |
| 235 | .restore_err_ret_index, | ||
| 235 | => try self.writeUnNode(stream, inst), | 236 | => try self.writeUnNode(stream, inst), |
| 236 | 237 | ||
| 237 | .ref, | 238 | .ref, |
| ... | @@ -405,6 +406,7 @@ const Writer = struct { | ... | @@ -405,6 +406,7 @@ const Writer = struct { |
| 405 | .alloc_inferred_comptime_mut, | 406 | .alloc_inferred_comptime_mut, |
| 406 | .ret_ptr, | 407 | .ret_ptr, |
| 407 | .ret_type, | 408 | .ret_type, |
| 409 | .save_err_ret_index, | ||
| 408 | => try self.writeNode(stream, inst), | 410 | => try self.writeNode(stream, inst), |
| 409 | 411 | ||
| 410 | .error_value, | 412 | .error_value, |
| ... | @@ -440,7 +442,7 @@ const Writer = struct { | ... | @@ -440,7 +442,7 @@ const Writer = struct { |
| 440 | 442 | ||
| 441 | .dbg_block_begin, | 443 | .dbg_block_begin, |
| 442 | .dbg_block_end, | 444 | .dbg_block_end, |
| 443 | => try stream.writeAll("))"), | 445 | => try stream.writeAll(")"), |
| 444 | 446 | ||
| 445 | .closure_get => try self.writeInstNode(stream, inst), | 447 | .closure_get => try self.writeInstNode(stream, inst), |
| 446 | 448 |