Commit 5316a00a18

Veikka Tuominen <git@vexu.eu>
2022-09-12 19:41:25
stage2: properly reset error return trace index
1 parent 28054d9
src/AstGen.zig
@@ -2471,6 +2471,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
             .try_ptr,
             //.try_inline,
             //.try_ptr_inline,
+            .save_err_ret_index,
             => break :b false,
 
             .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
             .validate_array_init_ty,
             .validate_struct_init_ty,
             .validate_deref,
+            .restore_err_ret_index,
             => break :b true,
 
             .@"defer" => unreachable,
@@ -5152,10 +5154,16 @@ fn orelseCatchExpr(
     const astgen = parent_gz.astgen;
     const tree = astgen.tree;
 
+    const do_err_trace = astgen.fn_block != null and (cond_op == .is_non_err or cond_op == .is_non_err_ptr);
+
     var block_scope = parent_gz.makeSubBlock(scope);
     block_scope.setBreakResultLoc(rl);
     defer block_scope.unstack();
 
+    if (do_err_trace) {
+        block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node);
+    }
+
     const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
         .ref => .ref,
         else => .none,
@@ -5220,7 +5228,7 @@ fn orelseCatchExpr(
     // instructions or not.
 
     const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break";
-    return finishThenElseBlock(
+    const result = try finishThenElseBlock(
         parent_gz,
         rl,
         node,
@@ -5235,6 +5243,16 @@ fn orelseCatchExpr(
         block,
         break_tag,
     );
+    if (do_err_trace) {
+        _ = try parent_gz.add(.{
+            .tag = .restore_err_ret_index,
+            .data = .{ .un_node = .{
+                .operand = parent_gz.saved_err_trace_index,
+                .src_node = parent_gz.nodeIndexToRelative(node),
+            } },
+        });
+    }
+    return result;
 }
 
 /// Supports `else_scope` stacked on `then_scope` stacked on `block_scope`. Unstacks `else_scope` then `then_scope`.
@@ -5430,10 +5448,16 @@ fn ifExpr(
     const tree = astgen.tree;
     const token_tags = tree.tokens.items(.tag);
 
+    const do_err_trace = astgen.fn_block != null and if_full.error_token != null;
+
     var block_scope = parent_gz.makeSubBlock(scope);
     block_scope.setBreakResultLoc(rl);
     defer block_scope.unstack();
 
+    if (do_err_trace) {
+        block_scope.saved_err_trace_index = try parent_gz.addNode(.save_err_ret_index, node);
+    }
+
     const payload_is_ref = if (if_full.payload_token) |payload_token|
         token_tags[payload_token] == .asterisk
     else
@@ -5602,7 +5626,7 @@ fn ifExpr(
     };
 
     const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break";
-    return finishThenElseBlock(
+    const result = try finishThenElseBlock(
         parent_gz,
         rl,
         node,
@@ -5617,6 +5641,16 @@ fn ifExpr(
         block,
         break_tag,
     );
+    if (do_err_trace) {
+        _ = try parent_gz.add(.{
+            .tag = .restore_err_ret_index,
+            .data = .{ .un_node = .{
+                .operand = parent_gz.saved_err_trace_index,
+                .src_node = parent_gz.nodeIndexToRelative(node),
+            } },
+        });
+    }
+    return result;
 }
 
 /// Supports `else_scope` stacked on `then_scope`. Unstacks `else_scope` then `then_scope`.
@@ -10300,6 +10334,8 @@ const GenZir = struct {
     /// Keys are the raw instruction index, values are the closure_capture instruction.
     captures: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{},
 
+    saved_err_trace_index: Zir.Inst.Ref = .none,
+
     const unstacked_top = std.math.maxInt(usize);
     /// Call unstack before adding any new instructions to containing GenZir.
     fn unstack(self: *GenZir) void {
@@ -10344,6 +10380,7 @@ const GenZir = struct {
             .any_defer_node = gz.any_defer_node,
             .instructions = gz.instructions,
             .instructions_top = gz.instructions.items.len,
+            .saved_err_trace_index = gz.saved_err_trace_index,
         };
     }
 
src/print_zir.zig
@@ -232,6 +232,7 @@ const Writer = struct {
             .validate_deref,
             .overflow_arithmetic_ptr,
             .check_comptime_control_flow,
+            .restore_err_ret_index,
             => try self.writeUnNode(stream, inst),
 
             .ref,
@@ -405,6 +406,7 @@ const Writer = struct {
             .alloc_inferred_comptime_mut,
             .ret_ptr,
             .ret_type,
+            .save_err_ret_index,
             => try self.writeNode(stream, inst),
 
             .error_value,
@@ -440,7 +442,7 @@ const Writer = struct {
 
             .dbg_block_begin,
             .dbg_block_end,
-            => try stream.writeAll("))"),
+            => try stream.writeAll(")"),
 
             .closure_get => try self.writeInstNode(stream, inst),
 
src/Sema.zig
@@ -926,6 +926,8 @@ fn analyzeBodyInner(
             .ret_ptr  => try sema.zirRetPtr(block, inst),
             .ret_type => try sema.addType(sema.fn_ret_ty),
 
+            .save_err_ret_index => try sema.zirSaveErrRetIndex(block, inst),
+
             // Instructions that we know to *always* be noreturn based solely on their tag.
             // These functions match the return type of analyzeBody so that we can
             // tail call them here.
@@ -1208,6 +1210,11 @@ fn analyzeBodyInner(
                 i += 1;
                 continue;
             },
+            .restore_err_ret_index => {
+                try sema.zirRestoreErrRetIndex(block, inst);
+                i += 1;
+                continue;
+            },
 
             // Special case instructions to handle comptime control flow.
             .@"break" => {
@@ -16176,6 +16183,52 @@ fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
         backend_supports_error_return_tracing;
 }
 
+fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+    const inst_data = sema.code.instructions.items(.data)[inst].node;
+    const src = LazySrcLoc.nodeOffset(inst_data);
+
+    // This is only relevant at runtime.
+    if (block.is_comptime) return Air.Inst.Ref.zero_usize;
+
+    const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
+    const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
+        sema.mod.comp.bin_file.options.error_return_tracing and
+        backend_supports_error_return_tracing;
+    if (!ok) return Air.Inst.Ref.zero_usize;
+
+    const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
+    const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
+    const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
+    const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
+    return sema.fieldVal(block, src, err_return_trace, "index", src);
+}
+
+fn zirRestoreErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+    const inst_data = sema.code.instructions.items(.data)[inst].un_node;
+    const src = inst_data.src();
+
+    // This is only relevant at runtime.
+    if (block.is_comptime) return;
+
+    const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
+    const ok = sema.owner_func.?.calls_or_awaits_errorable_fn and
+        sema.mod.comp.bin_file.options.error_return_tracing and
+        backend_supports_error_return_tracing;
+    if (!ok) return;
+
+    const operand = if (inst_data.operand != .none)
+        try sema.resolveInst(inst_data.operand)
+    else
+        .zero_usize;
+
+    const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
+    const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
+    const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
+    const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
+    const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true);
+    try sema.storePtr2(block, src, field_ptr, src, operand, src, .store);
+}
+
 fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
     assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
 
@@ -17181,8 +17234,6 @@ fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
 
 fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
     const inst_data = sema.code.instructions.items(.data)[inst].un_node;
-    const src = inst_data.src();
-    _ = src;
     const operand = try sema.resolveInst(inst_data.operand);
     const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
 
src/Zir.zig
@@ -988,6 +988,15 @@ pub const Inst = struct {
         /// Uses the `err_defer_code` union field.
         defer_err_code,
 
+        /// Saves the current error return case if it exists,
+        /// otherwise just returns zero.
+        /// Uses the `node` union field.
+        save_err_ret_index,
+        /// Sets error return trace to zero if no operand is given,
+        /// otherwise sets the value to the given amount.
+        /// Uses the `un_node` union field.
+        restore_err_ret_index,
+
         /// The ZIR instruction tag is one of the `Extended` ones.
         /// Uses the `extended` union field.
         extended,
@@ -1236,6 +1245,8 @@ pub const Inst = struct {
                 //.try_ptr_inline,
                 .@"defer",
                 .defer_err_code,
+                .save_err_ret_index,
+                .restore_err_ret_index,
                 => false,
 
                 .@"break",
@@ -1305,6 +1316,7 @@ pub const Inst = struct {
                 .check_comptime_control_flow,
                 .@"defer",
                 .defer_err_code,
+                .restore_err_ret_index,
                 => true,
 
                 .param,
@@ -1530,6 +1542,7 @@ pub const Inst = struct {
                 .try_ptr,
                 //.try_inline,
                 //.try_ptr_inline,
+                .save_err_ret_index,
                 => false,
 
                 .extended => switch (data.extended.opcode) {
@@ -1810,6 +1823,9 @@ pub const Inst = struct {
                 .@"defer" = .@"defer",
                 .defer_err_code = .defer_err_code,
 
+                .save_err_ret_index = .node,
+                .restore_err_ret_index = .un_node,
+
                 .extended = .extended,
             });
         };