authorgravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-09-12 23:09:14-07:00
committergravatar for topolarity@tapscott.meCody Tapscott <topolarity@tapscott.me> 2022-10-21 10:44:19-07:00
log0c3a50fe1c1370c975d7de1f2f00458b4a3ec299
tree0e282d7a4702780f75ccebba7b9e7937d4e59985
parenteda3eb1561ec9a68e692821d5de71d03e6f50d42

stage2: Do not pop error trace if result is an error

This allows for errors to be "re-thrown" by yielding any error as the result of a catch block. For example: ```zig fn errorable() !void { return error.FallingOutOfPlane; } fn foo(have_parachute: bool) !void { return errorable() catch |err| b: { if (have_parachute) { // error trace will include the call to errorable() break :b error.NoParachute; } else { return; } }; } pub fn main() !void { // Anything that returns a non-error does not pollute the error trace. try foo(true); // This error trace will still include errorable(), whose error was "re-thrown" by foo() try foo(false); } ``` This is piece (2/3) of https://github.com/ziglang/zig/issues/1923#issuecomment-1218495574

2 files changed, 200 insertions(+), 89 deletions(-)

src/AstGen.zig+147-89
......@@ -223,6 +223,10 @@ pub const ResultLoc = union(enum) {
223223 /// The expression must generate a pointer rather than a value. For example, the left hand side
224224 /// of an assignment uses this kind of result location.
225225 ref,
226 /// Exactly like `none`, except also indicates this is an error-handling expr (try/catch/return etc.)
227 catch_none,
228 /// Exactly like `ref`, except also indicates this is an error-handling expr (try/catch/return etc.)
229 catch_ref,
226230 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
227231 ty: Zir.Inst.Ref,
228232 /// Same as `ty` but for shift operands.
......@@ -265,7 +269,7 @@ pub const ResultLoc = union(enum) {
265269 fn strategy(rl: ResultLoc, block_scope: *GenZir) Strategy {
266270 switch (rl) {
267271 // In this branch there will not be any store_to_block_ptr instructions.
268 .none, .ty, .ty_shift_operand, .coerced_ty, .ref => return .{
272 .none, .catch_none, .ty, .ty_shift_operand, .coerced_ty, .ref, .catch_ref => return .{
269273 .tag = .break_operand,
270274 .elide_store_to_block_ptr_instructions = false,
271275 },
......@@ -838,7 +842,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
838842 const lhs = try expr(gz, scope, .none, node_datas[node].lhs);
839843 _ = try gz.addUnNode(.validate_deref, lhs, node);
840844 switch (rl) {
841 .ref => return lhs,
845 .ref, .catch_ref => return lhs,
842846 else => {
843847 const result = try gz.addUnNode(.load, lhs, node);
844848 return rvalue(gz, rl, result, node);
......@@ -855,7 +859,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
855859 return rvalue(gz, rl, result, node);
856860 },
857861 .unwrap_optional => switch (rl) {
858 .ref => return gz.addUnNode(
862 .ref, .catch_ref => return gz.addUnNode(
859863 .optional_payload_safe_ptr,
860864 try expr(gz, scope, .ref, node_datas[node].lhs),
861865 node,
......@@ -900,7 +904,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
900904 else
901905 null;
902906 switch (rl) {
903 .ref => return orelseCatchExpr(
907 .ref, .catch_ref => return orelseCatchExpr(
904908 gz,
905909 scope,
906910 rl,
......@@ -927,7 +931,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerEr
927931 }
928932 },
929933 .@"orelse" => switch (rl) {
930 .ref => return orelseCatchExpr(
934 .ref, .catch_ref => return orelseCatchExpr(
931935 gz,
932936 scope,
933937 rl,
......@@ -1372,11 +1376,11 @@ fn arrayInitExpr(
13721376 }
13731377 return Zir.Inst.Ref.void_value;
13741378 },
1375 .ref => {
1379 .ref, .catch_ref => {
13761380 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init_ref else .array_init_anon_ref;
13771381 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
13781382 },
1379 .none => {
1383 .none, .catch_none => {
13801384 const tag: Zir.Inst.Tag = if (types.array != .none) .array_init else .array_init_anon;
13811385 return arrayInitExprInner(gz, scope, node, array_init.ast.elements, types.array, types.elem, tag);
13821386 },
......@@ -1608,7 +1612,7 @@ fn structInitExpr(
16081612 }
16091613 return Zir.Inst.Ref.void_value;
16101614 },
1611 .ref => {
1615 .ref, .catch_ref => {
16121616 if (struct_init.ast.type_expr != 0) {
16131617 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
16141618 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
......@@ -1617,7 +1621,7 @@ fn structInitExpr(
16171621 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref);
16181622 }
16191623 },
1620 .none => {
1624 .none, .catch_none => {
16211625 if (struct_init.ast.type_expr != 0) {
16221626 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
16231627 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
......@@ -1891,15 +1895,8 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
18911895
18921896 // As our last action before the break, "pop" the error trace if needed
18931897 if (err_trace_index_to_restore != .none) {
1894 // TODO: error-liveness and is_non_err
1895
1896 _ = try parent_gz.add(.{
1897 .tag = .restore_err_ret_index,
1898 .data = .{ .un_node = .{
1899 .operand = err_trace_index_to_restore,
1900 .src_node = parent_gz.nodeIndexToRelative(node),
1901 } },
1902 });
1898 // void is a non-error so we always pop - no need to call `popErrorReturnTrace`
1899 _ = try parent_gz.addUnNode(.restore_err_ret_index, err_trace_index_to_restore, node);
19031900 }
19041901
19051902 _ = try parent_gz.addBreak(break_tag, block_inst, .void_value);
......@@ -1914,15 +1911,15 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
19141911
19151912 // As our last action before the break, "pop" the error trace if needed
19161913 if (err_trace_index_to_restore != .none) {
1917 // TODO: error-liveness and is_non_err
1918
1919 _ = try parent_gz.add(.{
1920 .tag = .restore_err_ret_index,
1921 .data = .{ .un_node = .{
1922 .operand = err_trace_index_to_restore,
1923 .src_node = parent_gz.nodeIndexToRelative(node),
1924 } },
1925 });
1914 // Pop the error trace, unless the operand is an error and breaking to an error-handling expr.
1915 try popErrorReturnTrace(
1916 parent_gz,
1917 scope,
1918 block_gz.break_result_loc,
1919 rhs,
1920 operand,
1921 err_trace_index_to_restore,
1922 );
19261923 }
19271924
19281925 switch (block_gz.break_result_loc) {
......@@ -2177,7 +2174,7 @@ fn labeledBlockExpr(
21772174 try block_scope.setBlockBody(block_inst);
21782175 const block_ref = indexToRef(block_inst);
21792176 switch (rl) {
2180 .ref => return block_ref,
2177 .ref, .catch_ref => return block_ref,
21812178 else => return rvalue(gz, rl, block_ref, block_node),
21822179 }
21832180 },
......@@ -5141,14 +5138,14 @@ fn tryExpr(
51415138 const try_column = astgen.source_column;
51425139
51435140 const operand_rl: ResultLoc = switch (rl) {
5144 .ref => .ref,
5145 else => .none,
5141 .ref, .catch_ref => .catch_ref,
5142 else => .catch_none,
51465143 };
51475144 // This could be a pointer or value depending on the `rl` parameter.
51485145 const operand = try reachableExpr(parent_gz, scope, operand_rl, operand_node, node);
51495146 const is_inline = parent_gz.force_comptime;
51505147 const is_inline_bit = @as(u2, @boolToInt(is_inline));
5151 const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref)) << 1;
5148 const is_ptr_bit = @as(u2, @boolToInt(operand_rl == .ref or operand_rl == .catch_ref)) << 1;
51525149 const block_tag: Zir.Inst.Tag = switch (is_inline_bit | is_ptr_bit) {
51535150 0b00 => .@"try",
51545151 0b01 => .@"try",
......@@ -5164,7 +5161,7 @@ fn tryExpr(
51645161 defer else_scope.unstack();
51655162
51665163 const err_tag = switch (rl) {
5167 .ref => Zir.Inst.Tag.err_union_code_ptr,
5164 .ref, .catch_ref => Zir.Inst.Tag.err_union_code_ptr,
51685165 else => Zir.Inst.Tag.err_union_code,
51695166 };
51705167 const err_code = try else_scope.addUnNode(err_tag, operand, node);
......@@ -5175,11 +5172,86 @@ fn tryExpr(
51755172 try else_scope.setTryBody(try_inst, operand);
51765173 const result = indexToRef(try_inst);
51775174 switch (rl) {
5178 .ref => return result,
5175 .ref, .catch_ref => return result,
51795176 else => return rvalue(parent_gz, rl, result, node),
51805177 }
51815178}
51825179
5180/// Pops the error return trace, unless:
5181/// 1. the result is a non-error, AND
5182/// 2. the result location corresponds to an error-handling expression
5183///
5184/// For reference, the full list of error-handling expressions is:
5185/// - try X
5186/// - X catch ...
5187/// - if (X) |_| { ... } |_| { ... }
5188/// - return X
5189///
5190fn popErrorReturnTrace(
5191 gz: *GenZir,
5192 scope: *Scope,
5193 rl: ResultLoc,
5194 node: Ast.Node.Index,
5195 result_inst: Zir.Inst.Ref,
5196 error_trace_index: Zir.Inst.Ref,
5197) InnerError!void {
5198 const astgen = gz.astgen;
5199 const tree = astgen.tree;
5200
5201 const result_is_err = nodeMayEvalToError(tree, node);
5202
5203 // If we are breaking to a try/catch/error-union-if/return, the error trace propagates.
5204 const propagate_error_trace = switch (rl) {
5205 .catch_none, .catch_ref => true, // Propagate to try/catch/error-union-if
5206 .ptr, .ty => |ref| b: { // Otherwise, propagate if result loc is a return
5207 const inst = refToIndex(ref) orelse break :b false;
5208 const zir_tags = astgen.instructions.items(.tag);
5209 break :b zir_tags[inst] == .ret_ptr or zir_tags[inst] == .ret_type;
5210 },
5211 else => false,
5212 };
5213
5214 if (result_is_err == .never or !propagate_error_trace) {
5215 // We are returning a non-error, or returning to a non-error-handling operator.
5216 // In either case, we need to pop the error trace.
5217 _ = try gz.addUnNode(.restore_err_ret_index, error_trace_index, node);
5218 } else if (result_is_err == .maybe) {
5219 // We are returning to an error-handling operator with a maybe-error.
5220 // Restore only if it's a non-error, implying the catch was successfully handled.
5221 var block_scope = gz.makeSubBlock(scope);
5222 block_scope.setBreakResultLoc(.discard);
5223 defer block_scope.unstack();
5224
5225 // Emit conditional branch for restoring error trace index
5226 const is_non_err = switch (rl) {
5227 .catch_ref => try block_scope.addUnNode(.is_non_err_ptr, result_inst, node),
5228 .ptr => |ptr| try block_scope.addUnNode(.is_non_err_ptr, ptr, node),
5229 .ty, .catch_none => try block_scope.addUnNode(.is_non_err, result_inst, node),
5230 else => unreachable, // Error-handling operators only generate the above result locations
5231 };
5232 const condbr = try block_scope.addCondBr(.condbr, node);
5233
5234 const block = try gz.makeBlockInst(.block, node);
5235 try block_scope.setBlockBody(block);
5236 // block_scope unstacked now, can add new instructions to gz
5237
5238 try gz.instructions.append(astgen.gpa, block);
5239
5240 var then_scope = block_scope.makeSubBlock(scope);
5241 defer then_scope.unstack();
5242
5243 _ = try then_scope.addUnNode(.restore_err_ret_index, error_trace_index, node);
5244 const then_break = try then_scope.makeBreak(.@"break", block, .void_value);
5245
5246 var else_scope = block_scope.makeSubBlock(scope);
5247 defer else_scope.unstack();
5248
5249 const else_break = try else_scope.makeBreak(.@"break", block, .void_value);
5250
5251 try setCondBrPayload(condbr, is_non_err, &then_scope, then_break, &else_scope, else_break);
5252 }
5253}
5254
51835255fn orelseCatchExpr(
51845256 parent_gz: *GenZir,
51855257 scope: *Scope,
......@@ -5204,8 +5276,8 @@ fn orelseCatchExpr(
52045276 const saved_err_trace_index = if (do_err_trace) try parent_gz.addNode(.save_err_ret_index, node) else .none;
52055277
52065278 const operand_rl: ResultLoc = switch (block_scope.break_result_loc) {
5207 .ref => .ref,
5208 else => .none,
5279 .ref, .catch_ref => if (do_err_trace) ResultLoc{ .catch_ref = {} } else .ref,
5280 else => if (do_err_trace) ResultLoc{ .catch_none = {} } else .none,
52095281 };
52105282 block_scope.break_count += 1;
52115283 // This could be a pointer or value depending on the `operand_rl` parameter.
......@@ -5227,7 +5299,7 @@ fn orelseCatchExpr(
52275299 // This could be a pointer or value depending on `unwrap_op`.
52285300 const unwrapped_payload = try then_scope.addUnNode(unwrap_op, operand, node);
52295301 const then_result = switch (rl) {
5230 .ref => unwrapped_payload,
5302 .ref, .catch_ref => unwrapped_payload,
52315303 else => try rvalue(&then_scope, block_scope.break_result_loc, unwrapped_payload, node),
52325304 };
52335305
......@@ -5266,15 +5338,15 @@ fn orelseCatchExpr(
52665338 if (!else_scope.endsWithNoReturn()) {
52675339 block_scope.break_count += 1;
52685340
5269 // TODO: Add is_non_err and break check
52705341 if (do_err_trace) {
5271 _ = try else_scope.add(.{
5272 .tag = .restore_err_ret_index,
5273 .data = .{ .un_node = .{
5274 .operand = saved_err_trace_index,
5275 .src_node = parent_gz.nodeIndexToRelative(node),
5276 } },
5277 });
5342 try popErrorReturnTrace(
5343 &else_scope,
5344 else_sub_scope,
5345 block_scope.break_result_loc,
5346 rhs,
5347 else_result,
5348 saved_err_trace_index,
5349 );
52785350 }
52795351 }
52805352 try checkUsed(parent_gz, &else_scope.base, else_sub_scope);
......@@ -5351,7 +5423,7 @@ fn finishThenElseBlock(
53515423 }
53525424 const block_ref = indexToRef(main_block);
53535425 switch (rl) {
5354 .ref => return block_ref,
5426 .ref, .catch_ref => return block_ref,
53555427 else => return rvalue(parent_gz, rl, block_ref, node),
53565428 }
53575429 },
......@@ -5375,7 +5447,7 @@ fn fieldAccess(
53755447 node: Ast.Node.Index,
53765448) InnerError!Zir.Inst.Ref {
53775449 switch (rl) {
5378 .ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node),
5450 .ref, .catch_ref => return addFieldAccess(.field_ptr, gz, scope, .ref, node),
53795451 else => {
53805452 const access = try addFieldAccess(.field_val, gz, scope, .none, node);
53815453 return rvalue(gz, rl, access, node);
......@@ -5416,7 +5488,7 @@ fn arrayAccess(
54165488 const tree = astgen.tree;
54175489 const node_datas = tree.nodes.items(.data);
54185490 switch (rl) {
5419 .ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{
5491 .ref, .catch_ref => return gz.addPlNode(.elem_ptr_node, node, Zir.Inst.Bin{
54205492 .lhs = try expr(gz, scope, .ref, node_datas[node].lhs),
54215493 .rhs = try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
54225494 }),
......@@ -5514,7 +5586,7 @@ fn ifExpr(
55145586 bool_bit: Zir.Inst.Ref,
55155587 } = c: {
55165588 if (if_full.error_token) |_| {
5517 const cond_rl: ResultLoc = if (payload_is_ref) .ref else .none;
5589 const cond_rl: ResultLoc = if (payload_is_ref) .catch_ref else .catch_none;
55185590 const err_union = try expr(&block_scope, &block_scope.base, cond_rl, if_full.ast.cond_expr);
55195591 const tag: Zir.Inst.Tag = if (payload_is_ref) .is_non_err_ptr else .is_non_err;
55205592 break :c .{
......@@ -5660,6 +5732,17 @@ fn ifExpr(
56605732 const e = try expr(&else_scope, sub_scope, block_scope.break_result_loc, else_node);
56615733 if (!else_scope.endsWithNoReturn()) {
56625734 block_scope.break_count += 1;
5735
5736 if (do_err_trace) {
5737 try popErrorReturnTrace(
5738 &else_scope,
5739 sub_scope,
5740 block_scope.break_result_loc,
5741 else_node,
5742 e,
5743 saved_err_trace_index,
5744 );
5745 }
56635746 }
56645747 try checkUsed(parent_gz, &else_scope.base, sub_scope);
56655748 try else_scope.addDbgBlockEnd();
......@@ -5676,18 +5759,6 @@ fn ifExpr(
56765759 },
56775760 };
56785761
5679 if (do_err_trace and !else_scope.endsWithNoReturn()) {
5680 // TODO: is_non_err and other checks
5681
5682 _ = try else_scope.add(.{
5683 .tag = .restore_err_ret_index,
5684 .data = .{ .un_node = .{
5685 .operand = saved_err_trace_index,
5686 .src_node = parent_gz.nodeIndexToRelative(node),
5687 } },
5688 });
5689 }
5690
56915762 const break_tag: Zir.Inst.Tag = if (parent_gz.force_comptime) .break_inline else .@"break";
56925763 const result = try finishThenElseBlock(
56935764 parent_gz,
......@@ -6760,7 +6831,7 @@ fn switchExpr(
67606831 }
67616832
67626833 const block_ref = indexToRef(switch_block);
6763 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref)
6834 if (strat.tag == .break_operand and strat.elide_store_to_block_ptr_instructions and rl != .ref and rl != .catch_ref)
67646835 return rvalue(parent_gz, rl, block_ref, switch_node);
67656836 return block_ref;
67666837}
......@@ -6839,19 +6910,12 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
68396910 .never => {
68406911 // Returning a value that cannot be an error; skip error defers.
68416912 try genDefers(gz, defer_outer, scope, .normal_only);
6842 try emitDbgStmt(gz, ret_line, ret_column);
68436913
68446914 // As our last action before the return, "pop" the error trace if needed
6845 if (gz.outermost_err_trace_index != .none) {
6846 _ = try gz.add(.{
6847 .tag = .restore_err_ret_index,
6848 .data = .{ .un_node = .{
6849 .operand = gz.outermost_err_trace_index,
6850 .src_node = gz.nodeIndexToRelative(node),
6851 } },
6852 });
6853 }
6915 if (gz.outermost_err_trace_index != .none)
6916 _ = try gz.addUnNode(.restore_err_ret_index, gz.outermost_err_trace_index, node);
68546917
6918 try emitDbgStmt(gz, ret_line, ret_column);
68556919 try gz.addRet(rl, operand, node);
68566920 return Zir.Inst.Ref.unreachable_value;
68576921 },
......@@ -6882,6 +6946,11 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
68826946 defer then_scope.unstack();
68836947
68846948 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6949
6950 // As our last action before the return, "pop" the error trace if needed
6951 if (then_scope.outermost_err_trace_index != .none)
6952 _ = try then_scope.addUnNode(.restore_err_ret_index, then_scope.outermost_err_trace_index, node);
6953
68856954 try emitDbgStmt(&then_scope, ret_line, ret_column);
68866955 try then_scope.addRet(rl, operand, node);
68876956
......@@ -6893,17 +6962,6 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
68936962 };
68946963 try genDefers(&else_scope, defer_outer, scope, which_ones);
68956964 try emitDbgStmt(&else_scope, ret_line, ret_column);
6896
6897 // As our last action before the return, "pop" the error trace if needed
6898 if (else_scope.outermost_err_trace_index != .none) {
6899 _ = try else_scope.add(.{
6900 .tag = .restore_err_ret_index,
6901 .data = .{ .un_node = .{
6902 .operand = else_scope.outermost_err_trace_index,
6903 .src_node = else_scope.nodeIndexToRelative(node),
6904 } },
6905 });
6906 }
69076965 try else_scope.addRet(rl, operand, node);
69086966
69096967 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
......@@ -7068,7 +7126,7 @@ fn localVarRef(
70687126 );
70697127
70707128 switch (rl) {
7071 .ref => return ptr_inst,
7129 .ref, .catch_ref => return ptr_inst,
70727130 else => {
70737131 const loaded = try gz.addUnNode(.load, ptr_inst, ident);
70747132 return rvalue(gz, rl, loaded, ident);
......@@ -7105,7 +7163,7 @@ fn localVarRef(
71057163 // Decl references happen by name rather than ZIR index so that when unrelated
71067164 // decls are modified, ZIR code containing references to them can be unmodified.
71077165 switch (rl) {
7108 .ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
7166 .ref, .catch_ref => return gz.addStrTok(.decl_ref, name_str_index, ident_token),
71097167 else => {
71107168 const result = try gz.addStrTok(.decl_val, name_str_index, ident_token);
71117169 return rvalue(gz, rl, result, ident);
......@@ -7452,7 +7510,7 @@ fn as(
74527510) InnerError!Zir.Inst.Ref {
74537511 const dest_type = try typeExpr(gz, scope, lhs);
74547512 switch (rl) {
7455 .none, .discard, .ref, .ty, .ty_shift_operand, .coerced_ty => {
7513 .none, .catch_none, .discard, .ref, .catch_ref, .ty, .ty_shift_operand, .coerced_ty => {
74567514 const result = try reachableExpr(gz, scope, .{ .ty = dest_type }, rhs, node);
74577515 return rvalue(gz, rl, result, node);
74587516 },
......@@ -7652,7 +7710,7 @@ fn builtinCall(
76527710 return rvalue(gz, rl, result, node);
76537711 },
76547712 .field => {
7655 if (rl == .ref) {
7713 if (rl == .ref or rl == .catch_ref) {
76567714 return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
76577715 .lhs = try expr(gz, scope, .ref, params[0]),
76587716 .field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]),
......@@ -9600,13 +9658,13 @@ fn rvalue(
96009658 };
96019659 if (gz.endsWithNoReturn()) return result;
96029660 switch (rl) {
9603 .none, .coerced_ty => return result,
9661 .none, .catch_none, .coerced_ty => return result,
96049662 .discard => {
96059663 // Emit a compile error for discarding error values.
96069664 _ = try gz.addUnNode(.ensure_result_non_error, result, src_node);
96079665 return result;
96089666 },
9609 .ref => {
9667 .ref, .catch_ref => {
96109668 // We need a pointer but we have a value.
96119669 // Unfortunately it's not quite as simple as directly emitting a ref
96129670 // instruction here because we need subsequent address-of operator on
......@@ -10575,7 +10633,7 @@ const GenZir = struct {
1057510633 gz.break_result_loc = parent_rl;
1057610634 },
1057710635
10578 .discard, .none, .ref => {
10636 .discard, .none, .catch_none, .ref, .catch_ref => {
1057910637 gz.rl_ty_inst = .none;
1058010638 gz.break_result_loc = parent_rl;
1058110639 },
test/stack_traces.zig+53
......@@ -155,6 +155,59 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
155155 },
156156 });
157157
158 cases.addCase(.{
159 .name = "catch and re-throw error",
160 .source =
161 \\fn foo() !void {
162 \\ return error.TheSkyIsFalling;
163 \\}
164 \\
165 \\pub fn main() !void {
166 \\ return foo() catch error.AndMyCarIsOutOfGas;
167 \\}
168 ,
169 .Debug = .{
170 .expect =
171 \\error: AndMyCarIsOutOfGas
172 \\source.zig:2:5: [address] in foo (test)
173 \\ return error.TheSkyIsFalling;
174 \\ ^
175 \\source.zig:6:5: [address] in main (test)
176 \\ return foo() catch error.AndMyCarIsOutOfGas;
177 \\ ^
178 \\
179 ,
180 },
181 .ReleaseSafe = .{
182 .exclude_os = .{
183 .windows, // TODO
184 .linux, // defeated by aggressive inlining
185 },
186 .expect =
187 \\error: AndMyCarIsOutOfGas
188 \\source.zig:2:5: [address] in [function]
189 \\ return error.TheSkyIsFalling;
190 \\ ^
191 \\source.zig:6:5: [address] in [function]
192 \\ return foo() catch error.AndMyCarIsOutOfGas;
193 \\ ^
194 \\
195 ,
196 },
197 .ReleaseFast = .{
198 .expect =
199 \\error: AndMyCarIsOutOfGas
200 \\
201 ,
202 },
203 .ReleaseSmall = .{
204 .expect =
205 \\error: AndMyCarIsOutOfGas
206 \\
207 ,
208 },
209 });
210
158211 cases.addCase(.{
159212 .name = "try return from within catch",
160213 .source =