From feb90f6ed4f64eb0faef8fbbcf8c51fad5392b39 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 8 Aug 2022 20:53:06 -0700 Subject: [PATCH] AstGen: emit debug stmt for try This improves the following test case: ```zig pub fn main() !void { try foo(); } fn foo() !void { return error.Bad; } ``` The error return trace now points to the `try` token instead of pointing to the foo() function call, matching stage1. Closes #12308. --- src/AstGen.zig | 27 +++++++++++++++++++-------- test/stack_traces.zig | 1 + 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/AstGen.zig b/src/AstGen.zig index 5087ea6293..4e08b39777 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -5051,6 +5051,16 @@ fn tryExpr( if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{}); + // Ensure debug line/column information is emitted for this try expression. + // Then we will save the line/column so that we can emit another one that goes + // "backwards" because we want to evaluate the operand, but then put the debug + // info back at the try keyword for error return tracing. + if (!parent_gz.force_comptime) { + try emitDbgNode(parent_gz, node); + } + const try_line = astgen.source_line - parent_gz.decl_line; + const try_column = astgen.source_column; + const operand_rl: ResultLoc = switch (rl) { .ref => .ref, else => .none, @@ -5080,6 +5090,7 @@ fn tryExpr( }; const err_code = try else_scope.addUnNode(err_tag, operand, node); try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code }); + try emitDbgStmt(&else_scope, try_line, try_column); _ = try else_scope.addUnNode(.ret_node, err_code, node); try else_scope.setTryBody(try_inst, operand); @@ -6614,13 +6625,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref const defer_counts = countDefers(astgen, defer_outer, scope); if (!defer_counts.need_err_code) { try genDefers(gz, defer_outer, scope, .both_sans_err); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(gz, ret_line, ret_column); _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token); return Zir.Inst.Ref.unreachable_value; } const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token); try genDefers(gz, defer_outer, scope, .{ .both = err_code }); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(gz, ret_line, ret_column); _ = try gz.addUnNode(.ret_node, err_code, node); return Zir.Inst.Ref.unreachable_value; } @@ -6639,7 +6650,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref .never => { // Returning a value that cannot be an error; skip error defers. try genDefers(gz, defer_outer, scope, .normal_only); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(gz, ret_line, ret_column); try gz.addRet(rl, operand, node); return Zir.Inst.Ref.unreachable_value; }, @@ -6647,7 +6658,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref // Value is always an error. Emit both error defers and regular defers. const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand; try genDefers(gz, defer_outer, scope, .{ .both = err_code }); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(gz, ret_line, ret_column); try gz.addRet(rl, operand, node); return Zir.Inst.Ref.unreachable_value; }, @@ -6656,7 +6667,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref if (!defer_counts.have_err) { // Only regular defers; no branch needed. try genDefers(gz, defer_outer, scope, .normal_only); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(gz, ret_line, ret_column); try gz.addRet(rl, operand, node); return Zir.Inst.Ref.unreachable_value; } @@ -6670,7 +6681,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref defer then_scope.unstack(); try genDefers(&then_scope, defer_outer, scope, .normal_only); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(&then_scope, ret_line, ret_column); try then_scope.addRet(rl, operand, node); var else_scope = gz.makeSubBlock(scope); @@ -6680,7 +6691,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref .both = try else_scope.addUnNode(.err_union_code, result, node), }; try genDefers(&else_scope, defer_outer, scope, which_ones); - try emitRetDbgStmt(gz, ret_line, ret_column); + try emitDbgStmt(&else_scope, ret_line, ret_column); try else_scope.addRet(rl, operand, node); try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0); @@ -11698,7 +11709,7 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 { return @intCast(u32, count); } -fn emitRetDbgStmt(gz: *GenZir, line: u32, column: u32) !void { +fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void { if (gz.force_comptime) return; _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{ diff --git a/test/stack_traces.zig b/test/stack_traces.zig index c40413f936..ea27b5beff 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -22,6 +22,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { .ReleaseSafe = .{ .exclude_os = .{ .windows, // segfault + .linux, // defeated by aggressive inlining }, .expect = \\error: TheSkyIsFalling