authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-18 18:32:52-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-18 18:32:52-08:00
log6ecf3b1ef35d1ce8a89a20ecead244a2c37269c6
treec8859e64c52e379f8f2940187fd2c22a765be829
parent7d81c952d57a76454c31b13b3ec8e21388f02171
parentc4cff443b81b81711c8ed7367f05fe7fdffe8239
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18599 from dweiller/err-union-switch-err-trace

astgen: fix error return trace on error union switch

3 files changed, 72 insertions(+), 0 deletions(-)

src/AstGen.zig+16
...@@ -6919,6 +6919,8 @@ fn switchExprErrUnion(...@@ -6919,6 +6919,8 @@ fn switchExprErrUnion(
6919 };6919 };
6920 assert(node_tags[switch_node] == .@"switch" or node_tags[switch_node] == .switch_comma);6920 assert(node_tags[switch_node] == .@"switch" or node_tags[switch_node] == .switch_comma);
69216921
6922 const do_err_trace = astgen.fn_block != null;
6923
6922 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);6924 const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange);
6923 const case_nodes = tree.extra_data[extra.start..extra.end];6925 const case_nodes = tree.extra_data[extra.start..extra.end];
69246926
...@@ -7304,10 +7306,14 @@ fn switchExprErrUnion(...@@ -7304,10 +7306,14 @@ fn switchExprErrUnion(
7304 case_scope.instructions_top = parent_gz.instructions.items.len;7306 case_scope.instructions_top = parent_gz.instructions.items.len;
7305 defer case_scope.unstack();7307 defer case_scope.unstack();
73067308
7309 if (do_err_trace and nodeMayAppendToErrorTrace(tree, operand_node))
7310 _ = try case_scope.addSaveErrRetIndex(.always);
7311
7307 try case_scope.addDbgBlockBegin();7312 try case_scope.addDbgBlockBegin();
7308 if (dbg_var_name != .empty) {7313 if (dbg_var_name != .empty) {
7309 try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);7314 try case_scope.addDbgVar(.dbg_var_val, dbg_var_name, dbg_var_inst);
7310 }7315 }
7316
7311 const target_expr_node = case.ast.target_expr;7317 const target_expr_node = case.ast.target_expr;
7312 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);7318 const case_result = try expr(&case_scope, sub_scope, block_scope.break_result_info, target_expr_node);
7313 // check capture_scope, not err_scope to avoid false positive unused error capture7319 // check capture_scope, not err_scope to avoid false positive unused error capture
...@@ -7318,7 +7324,17 @@ fn switchExprErrUnion(...@@ -7318,7 +7324,17 @@ fn switchExprErrUnion(
7318 any_uses_err_capture = true;7324 any_uses_err_capture = true;
7319 }7325 }
7320 try case_scope.addDbgBlockEnd();7326 try case_scope.addDbgBlockEnd();
7327
7321 if (!parent_gz.refIsNoReturn(case_result)) {7328 if (!parent_gz.refIsNoReturn(case_result)) {
7329 if (do_err_trace)
7330 try restoreErrRetIndex(
7331 &case_scope,
7332 .{ .block = switch_block },
7333 block_scope.break_result_info,
7334 target_expr_node,
7335 case_result,
7336 );
7337
7322 _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);7338 _ = try case_scope.addBreakWithSrcNode(.@"break", switch_block, case_result, target_expr_node);
7323 }7339 }
73247340
src/Sema.zig+1
...@@ -13117,6 +13117,7 @@ fn validateErrSetSwitch(...@@ -13117,6 +13117,7 @@ fn validateErrSetSwitch(
13117 .defer_err_code,13117 .defer_err_code,
13118 .err_union_code,13118 .err_union_code,
13119 .ret_err_value_code,13119 .ret_err_value_code,
13120 .save_err_ret_index,
13120 .restore_err_ret_index,13121 .restore_err_ret_index,
13121 .is_non_err,13122 .is_non_err,
13122 .ret_is_non_err,13123 .ret_is_non_err,
test/stack_traces.zig+55
...@@ -807,4 +807,59 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -807,4 +807,59 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
807 ,807 ,
808 },808 },
809 });809 });
810 cases.addCase(.{
811 .name = "error union switch with call operand",
812 .source =
813 \\pub fn main() !void {
814 \\ try foo();
815 \\ return error.TheSkyIsFalling;
816 \\}
817 \\
818 \\noinline fn failure() error{ Fatal, NonFatal }!void {
819 \\ return error.NonFatal;
820 \\}
821 \\
822 \\fn foo() error{Fatal}!void {
823 \\ return failure() catch |err| switch (err) {
824 \\ error.Fatal => return error.Fatal,
825 \\ error.NonFatal => return,
826 \\ };
827 \\}
828 ,
829 .Debug = .{
830 .expect =
831 \\error: TheSkyIsFalling
832 \\source.zig:3:5: [address] in main (test)
833 \\ return error.TheSkyIsFalling;
834 \\ ^
835 \\
836 ,
837 },
838 .ReleaseSafe = .{
839 .exclude_os = &.{
840 .windows, // TODO
841 .linux, // defeated by aggressive inlining
842 },
843 .expect =
844 \\error: TheSkyIsFalling
845 \\source.zig:3:5: [address] in [function]
846 \\ return error.TheSkyIsFalling;
847 \\ ^
848 \\
849 ,
850 .error_tracing = true,
851 },
852 .ReleaseFast = .{
853 .expect =
854 \\error: TheSkyIsFalling
855 \\
856 ,
857 },
858 .ReleaseSmall = .{
859 .expect =
860 \\error: TheSkyIsFalling
861 \\
862 ,
863 },
864 });
810}865}