srctree

Andrew Kelley parent 7d81c952 c4cff443 6ecf3b1e
Merge pull request #18599 from dweiller/err-union-switch-err-trace

astgen: fix error return trace on error union switch

inlinesplit
src/AstGen.zig added: 75, removed: 3, total 72
@@ -6919,6 +6919,8 @@ fn switchExprErrUnion(
};
assert(node_tags[switch_node] == .@"switch" or node_tags[switch_node] == .switch_comma);
 
const do_err_trace = astgen.fn_block != null;
 
const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
const case_nodes = tree.extra_data[extra.start..extra.end];
 
@@ -7304,10 +7306,14 @@ fn switchExprErrUnion(
case_scope.instructions_top = parent_gz.instructions.items.len;
defer case_scope.unstack();
 
if (do_err_trace and nodeMayAppendToErrorTrace(tree, operand_node))
_ = try case_scope.addSaveErrRetIndex(.always);
 
try case_scope.addDbgBlockBegin();
if (dbg_var_name != .empty) {
try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
}
 
const target_expr_node = case.ast.target_expr;
const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);
// check capture_scope, not err_scope to avoid false positive unused error capture
@@ -7318,7 +7324,17 @@ fn switchExprErrUnion(
any_uses_err_capture = true;
}
try case_scope.addDbgBlockEnd();
 
if (!parent_gz.refIsNoReturn(case_result)) {
if (do_err_trace)
try restoreErrRetIndex(
&case_scope,
.{ .block = switch_block },
block_scope.break_result_info,
target_expr_node,
case_result,
);
 
_ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);
}
 
 
src/Sema.zig added: 75, removed: 3, total 72
@@ -13117,6 +13117,7 @@ fn validateErrSetSwitch(
.defer_err_code,
.err_union_code,
.ret_err_value_code,
.save_err_ret_index,
.restore_err_ret_index,
.is_non_err,
.ret_is_non_err,
 
test/stack_traces.zig added: 75, removed: 3, total 72
@@ -807,4 +807,59 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
,
},
});
cases.addCase(.{
.name = "error union switch with call operand",
.source =
\\pub fn main() !void {
\\ try foo();
\\ return error.TheSkyIsFalling;
\\}
\\
\\noinline fn failure() error{ Fatal, NonFatal }!void {
\\ return error.NonFatal;
\\}
\\
\\fn foo() error{Fatal}!void {
\\ return failure() catch |err| switch (err) {
\\ error.Fatal => return error.Fatal,
\\ error.NonFatal => return,
\\ };
\\}
,
.Debug = .{
.expect =
\\error: TheSkyIsFalling
\\source.zig:3:5: [address] in main (test)
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
},
.ReleaseSafe = .{
.exclude_os = &.{
.windows, // TODO
.linux, // defeated by aggressive inlining
},
.expect =
\\error: TheSkyIsFalling
\\source.zig:3:5: [address] in [function]
\\ return error.TheSkyIsFalling;
\\ ^
\\
,
.error_tracing = true,
},
.ReleaseFast = .{
.expect =
\\error: TheSkyIsFalling
\\
,
},
.ReleaseSmall = .{
.expect =
\\error: TheSkyIsFalling
\\
,
},
});
}