authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-09 02:11:58-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-08-09 02:11:58-07:00
log85a3f9b0544c1b90a77ce26f99f9fc26116d756b
treea42093d83336a1dbbf90447154ec9e83dd2dcebf
parentc76b5c1a31ebe09726cd29e7a6da69613eabfd10
parentfeb90f6ed4f64eb0faef8fbbcf8c51fad5392b39
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #12383 from ziglang/stage2-stack-traces

several improvements to error return tracing in the self-hosted compiler

4 files changed, 193 insertions(+), 24 deletions(-)

lib/std/builtin.zig+1-2
...@@ -867,10 +867,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {...@@ -867,10 +867,9 @@ pub fn panicOutOfBounds(index: usize, len: usize) noreturn {
867 std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len });867 std.debug.panic("attempt to index out of bound: index {d}, len {d}", .{ index, len });
868}868}
869869
870pub noinline fn returnError(maybe_st: ?*StackTrace) void {870pub noinline fn returnError(st: *StackTrace) void {
871 @setCold(true);871 @setCold(true);
872 @setRuntimeSafety(false);872 @setRuntimeSafety(false);
873 const st = maybe_st orelse return;
874 addErrRetTraceAddr(st, @returnAddress());873 addErrRetTraceAddr(st, @returnAddress());
875}874}
876875
src/AstGen.zig+52
...@@ -3070,6 +3070,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {...@@ -3070,6 +3070,19 @@ fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void {
3070 const line = astgen.source_line - gz.decl_line;3070 const line = astgen.source_line - gz.decl_line;
3071 const column = astgen.source_column;3071 const column = astgen.source_column;
30723072
3073 if (gz.instructions.items.len > 0) {
3074 const last = gz.instructions.items[gz.instructions.items.len - 1];
3075 const zir_tags = astgen.instructions.items(.tag);
3076 if (zir_tags[last] == .dbg_stmt) {
3077 const zir_datas = astgen.instructions.items(.data);
3078 zir_datas[last].dbg_stmt = .{
3079 .line = line,
3080 .column = column,
3081 };
3082 return;
3083 }
3084 }
3085
3073 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{3086 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
3074 .dbg_stmt = .{3087 .dbg_stmt = .{
3075 .line = line,3088 .line = line,
...@@ -5050,6 +5063,16 @@ fn tryExpr(...@@ -5050,6 +5063,16 @@ fn tryExpr(
50505063
5051 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});5064 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});
50525065
5066 // Ensure debug line/column information is emitted for this try expression.
5067 // Then we will save the line/column so that we can emit another one that goes
5068 // "backwards" because we want to evaluate the operand, but then put the debug
5069 // info back at the try keyword for error return tracing.
5070 if (!parent_gz.force_comptime) {
5071 try emitDbgNode(parent_gz, node);
5072 }
5073 const try_line = astgen.source_line - parent_gz.decl_line;
5074 const try_column = astgen.source_column;
5075
5053 const operand_rl: ResultLoc = switch (rl) {5076 const operand_rl: ResultLoc = switch (rl) {
5054 .ref => .ref,5077 .ref => .ref,
5055 else => .none,5078 else => .none,
...@@ -5079,6 +5102,7 @@ fn tryExpr(...@@ -5079,6 +5102,7 @@ fn tryExpr(
5079 };5102 };
5080 const err_code = try else_scope.addUnNode(err_tag, operand, node);5103 const err_code = try else_scope.addUnNode(err_tag, operand, node);
5081 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });5104 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });
5105 try emitDbgStmt(&else_scope, try_line, try_column);
5082 _ = try else_scope.addUnNode(.ret_node, err_code, node);5106 _ = try else_scope.addUnNode(.ret_node, err_code, node);
50835107
5084 try else_scope.setTryBody(try_inst, operand);5108 try else_scope.setTryBody(try_inst, operand);
...@@ -6585,6 +6609,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6585,6 +6609,16 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
65856609
6586 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});6610 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
65876611
6612 // Ensure debug line/column information is emitted for this return expression.
6613 // Then we will save the line/column so that we can emit another one that goes
6614 // "backwards" because we want to evaluate the operand, but then put the debug
6615 // info back at the return keyword for error return tracing.
6616 if (!gz.force_comptime) {
6617 try emitDbgNode(gz, node);
6618 }
6619 const ret_line = astgen.source_line - gz.decl_line;
6620 const ret_column = astgen.source_column;
6621
6588 const defer_outer = &astgen.fn_block.?.base;6622 const defer_outer = &astgen.fn_block.?.base;
65896623
6590 const operand_node = node_datas[node].lhs;6624 const operand_node = node_datas[node].lhs;
...@@ -6603,11 +6637,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6603,11 +6637,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6603 const defer_counts = countDefers(astgen, defer_outer, scope);6637 const defer_counts = countDefers(astgen, defer_outer, scope);
6604 if (!defer_counts.need_err_code) {6638 if (!defer_counts.need_err_code) {
6605 try genDefers(gz, defer_outer, scope, .both_sans_err);6639 try genDefers(gz, defer_outer, scope, .both_sans_err);
6640 try emitDbgStmt(gz, ret_line, ret_column);
6606 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);6641 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
6607 return Zir.Inst.Ref.unreachable_value;6642 return Zir.Inst.Ref.unreachable_value;
6608 }6643 }
6609 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);6644 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
6610 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6645 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6646 try emitDbgStmt(gz, ret_line, ret_column);
6611 _ = try gz.addUnNode(.ret_node, err_code, node);6647 _ = try gz.addUnNode(.ret_node, err_code, node);
6612 return Zir.Inst.Ref.unreachable_value;6648 return Zir.Inst.Ref.unreachable_value;
6613 }6649 }
...@@ -6626,6 +6662,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6626,6 +6662,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6626 .never => {6662 .never => {
6627 // Returning a value that cannot be an error; skip error defers.6663 // Returning a value that cannot be an error; skip error defers.
6628 try genDefers(gz, defer_outer, scope, .normal_only);6664 try genDefers(gz, defer_outer, scope, .normal_only);
6665 try emitDbgStmt(gz, ret_line, ret_column);
6629 try gz.addRet(rl, operand, node);6666 try gz.addRet(rl, operand, node);
6630 return Zir.Inst.Ref.unreachable_value;6667 return Zir.Inst.Ref.unreachable_value;
6631 },6668 },
...@@ -6633,6 +6670,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6633,6 +6670,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6633 // Value is always an error. Emit both error defers and regular defers.6670 // Value is always an error. Emit both error defers and regular defers.
6634 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;6671 const err_code = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6635 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6672 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6673 try emitDbgStmt(gz, ret_line, ret_column);
6636 try gz.addRet(rl, operand, node);6674 try gz.addRet(rl, operand, node);
6637 return Zir.Inst.Ref.unreachable_value;6675 return Zir.Inst.Ref.unreachable_value;
6638 },6676 },
...@@ -6641,6 +6679,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6641,6 +6679,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6641 if (!defer_counts.have_err) {6679 if (!defer_counts.have_err) {
6642 // Only regular defers; no branch needed.6680 // Only regular defers; no branch needed.
6643 try genDefers(gz, defer_outer, scope, .normal_only);6681 try genDefers(gz, defer_outer, scope, .normal_only);
6682 try emitDbgStmt(gz, ret_line, ret_column);
6644 try gz.addRet(rl, operand, node);6683 try gz.addRet(rl, operand, node);
6645 return Zir.Inst.Ref.unreachable_value;6684 return Zir.Inst.Ref.unreachable_value;
6646 }6685 }
...@@ -6654,6 +6693,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6654,6 +6693,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6654 defer then_scope.unstack();6693 defer then_scope.unstack();
66556694
6656 try genDefers(&then_scope, defer_outer, scope, .normal_only);6695 try genDefers(&then_scope, defer_outer, scope, .normal_only);
6696 try emitDbgStmt(&then_scope, ret_line, ret_column);
6657 try then_scope.addRet(rl, operand, node);6697 try then_scope.addRet(rl, operand, node);
66586698
6659 var else_scope = gz.makeSubBlock(scope);6699 var else_scope = gz.makeSubBlock(scope);
...@@ -6663,6 +6703,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6663,6 +6703,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6663 .both = try else_scope.addUnNode(.err_union_code, result, node),6703 .both = try else_scope.addUnNode(.err_union_code, result, node),
6664 };6704 };
6665 try genDefers(&else_scope, defer_outer, scope, which_ones);6705 try genDefers(&else_scope, defer_outer, scope, which_ones);
6706 try emitDbgStmt(&else_scope, ret_line, ret_column);
6666 try else_scope.addRet(rl, operand, node);6707 try else_scope.addRet(rl, operand, node);
66676708
6668 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);6709 try setCondBrPayload(condbr, is_non_err, &then_scope, 0, &else_scope, 0);
...@@ -11702,3 +11743,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {...@@ -11702,3 +11743,14 @@ fn countBodyLenAfterFixups(astgen: *AstGen, body: []const Zir.Inst.Index) u32 {
11702 }11743 }
11703 return @intCast(u32, count);11744 return @intCast(u32, count);
11704}11745}
11746
11747fn emitDbgStmt(gz: *GenZir, line: u32, column: u32) !void {
11748 if (gz.force_comptime) return;
11749
11750 _ = try gz.add(.{ .tag = .dbg_stmt, .data = .{
11751 .dbg_stmt = .{
11752 .line = line,
11753 .column = column,
11754 },
11755 } });
11756}
src/Sema.zig+139-22
...@@ -14489,6 +14489,20 @@ fn zirBoolBr(...@@ -14489,6 +14489,20 @@ fn zirBoolBr(
14489 const rhs_result = try sema.resolveBody(rhs_block, body, inst);14489 const rhs_result = try sema.resolveBody(rhs_block, body, inst);
14490 _ = try rhs_block.addBr(block_inst, rhs_result);14490 _ = try rhs_block.addBr(block_inst, rhs_result);
1449114491
14492 return finishCondBr(sema, parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
14493}
14494
14495fn finishCondBr(
14496 sema: *Sema,
14497 parent_block: *Block,
14498 child_block: *Block,
14499 then_block: *Block,
14500 else_block: *Block,
14501 cond: Air.Inst.Ref,
14502 block_inst: Air.Inst.Index,
14503) !Air.Inst.Ref {
14504 const gpa = sema.gpa;
14505
14492 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +14506 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
14493 then_block.instructions.items.len + else_block.instructions.items.len +14507 then_block.instructions.items.len + else_block.instructions.items.len +
14494 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);14508 @typeInfo(Air.Block).Struct.fields.len + child_block.instructions.items.len + 1);
...@@ -14501,7 +14515,7 @@ fn zirBoolBr(...@@ -14501,7 +14515,7 @@ fn zirBoolBr(
14501 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);14515 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
1450214516
14503 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{14517 _ = try child_block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
14504 .operand = lhs,14518 .operand = cond,
14505 .payload = cond_br_payload,14519 .payload = cond_br_payload,
14506 } } });14520 } } });
1450714521
...@@ -14871,10 +14885,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir...@@ -14871,10 +14885,83 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
14871 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);14885 const operand = try sema.analyzeLoad(block, src, ret_ptr, src);
14872 return sema.analyzeRet(block, operand, src);14886 return sema.analyzeRet(block, operand, src);
14873 }14887 }
14888
14889 if (sema.wantErrorReturnTracing()) {
14890 const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
14891 return retWithErrTracing(sema, block, src, is_non_err, .ret_load, ret_ptr);
14892 }
14893
14874 _ = try block.addUnOp(.ret_load, ret_ptr);14894 _ = try block.addUnOp(.ret_load, ret_ptr);
14875 return always_noreturn;14895 return always_noreturn;
14876}14896}
1487714897
14898fn retWithErrTracing(
14899 sema: *Sema,
14900 block: *Block,
14901 src: LazySrcLoc,
14902 is_non_err: Air.Inst.Ref,
14903 ret_tag: Air.Inst.Tag,
14904 operand: Air.Inst.Ref,
14905) CompileError!Zir.Inst.Index {
14906 const need_check = switch (is_non_err) {
14907 .bool_true => {
14908 _ = try block.addUnOp(ret_tag, operand);
14909 return always_noreturn;
14910 },
14911 .bool_false => false,
14912 else => true,
14913 };
14914 const gpa = sema.gpa;
14915 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
14916 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
14917 const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
14918 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
14919 const return_err_fn = try sema.getBuiltin(block, src, "returnError");
14920 const args: [1]Air.Inst.Ref = .{err_return_trace};
14921
14922 if (!need_check) {
14923 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
14924 _ = try block.addUnOp(ret_tag, operand);
14925 return always_noreturn;
14926 }
14927
14928 var then_block = block.makeSubBlock();
14929 defer then_block.instructions.deinit(gpa);
14930 _ = try then_block.addUnOp(ret_tag, operand);
14931
14932 var else_block = block.makeSubBlock();
14933 defer else_block.instructions.deinit(gpa);
14934 _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null);
14935 _ = try else_block.addUnOp(ret_tag, operand);
14936
14937 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
14938 then_block.instructions.items.len + else_block.instructions.items.len +
14939 @typeInfo(Air.Block).Struct.fields.len + 1);
14940
14941 const cond_br_payload = sema.addExtraAssumeCapacity(Air.CondBr{
14942 .then_body_len = @intCast(u32, then_block.instructions.items.len),
14943 .else_body_len = @intCast(u32, else_block.instructions.items.len),
14944 });
14945 sema.air_extra.appendSliceAssumeCapacity(then_block.instructions.items);
14946 sema.air_extra.appendSliceAssumeCapacity(else_block.instructions.items);
14947
14948 _ = try block.addInst(.{ .tag = .cond_br, .data = .{ .pl_op = .{
14949 .operand = is_non_err,
14950 .payload = cond_br_payload,
14951 } } });
14952
14953 return always_noreturn;
14954}
14955
14956fn wantErrorReturnTracing(sema: *Sema) bool {
14957 // TODO implement this feature in all the backends and then delete this check.
14958 const backend_supports_error_return_tracing = sema.mod.comp.bin_file.options.use_llvm;
14959
14960 return sema.fn_ret_ty.isError() and
14961 sema.mod.comp.bin_file.options.error_return_tracing and
14962 backend_supports_error_return_tracing;
14963}
14964
14878fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {14965fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
14879 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);14966 assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
1488014967
...@@ -14920,27 +15007,15 @@ fn analyzeRet(...@@ -14920,27 +15007,15 @@ fn analyzeRet(
14920 return always_noreturn;15007 return always_noreturn;
14921 }15008 }
1492215009
14923 // TODO implement this feature in all the backends and then delete this check.15010 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
14924 const backend_supports_error_return_tracing =
14925 sema.mod.comp.bin_file.options.use_llvm;
1492615011
14927 if (sema.fn_ret_ty.isError() and15012 if (sema.wantErrorReturnTracing()) {
14928 sema.mod.comp.bin_file.options.error_return_tracing and15013 // Avoid adding a frame to the error return trace in case the value is comptime-known
14929 backend_supports_error_return_tracing)15014 // to be not an error.
14930 ret_err: {15015 const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
14931 if (try sema.resolveMaybeUndefVal(block, src, operand)) |ret_val| {15016 return retWithErrTracing(sema, block, src, is_non_err, .ret, operand);
14932 if (ret_val.tag() != .@"error") break :ret_err;
14933 }
14934 const return_err_fn = try sema.getBuiltin(block, src, "returnError");
14935 const unresolved_stack_trace_ty = try sema.getBuiltinType(block, src, "StackTrace");
14936 const stack_trace_ty = try sema.resolveTypeFields(block, src, unresolved_stack_trace_ty);
14937 const ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
14938 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
14939 const args: [1]Air.Inst.Ref = .{err_return_trace};
14940 _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
14941 }15017 }
1494215018
14943 try sema.resolveTypeLayout(block, src, sema.fn_ret_ty);
14944 _ = try block.addUnOp(.ret, operand);15019 _ = try block.addUnOp(.ret, operand);
14945 return always_noreturn;15020 return always_noreturn;
14946}15021}
...@@ -25418,6 +25493,27 @@ fn analyzeIsNull(...@@ -25418,6 +25493,27 @@ fn analyzeIsNull(
25418 return block.addUnOp(air_tag, operand);25493 return block.addUnOp(air_tag, operand);
25419}25494}
2542025495
25496fn analyzePtrIsNonErrComptimeOnly(
25497 sema: *Sema,
25498 block: *Block,
25499 src: LazySrcLoc,
25500 operand: Air.Inst.Ref,
25501) CompileError!Air.Inst.Ref {
25502 const ptr_ty = sema.typeOf(operand);
25503 assert(ptr_ty.zigTypeTag() == .Pointer);
25504 const child_ty = ptr_ty.childType();
25505
25506 const child_tag = child_ty.zigTypeTag();
25507 if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true;
25508 if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false;
25509 assert(child_tag == .ErrorUnion);
25510
25511 _ = block;
25512 _ = src;
25513
25514 return Air.Inst.Ref.none;
25515}
25516
25421fn analyzeIsNonErrComptimeOnly(25517fn analyzeIsNonErrComptimeOnly(
25422 sema: *Sema,25518 sema: *Sema,
25423 block: *Block,25519 block: *Block,
...@@ -25431,10 +25527,16 @@ fn analyzeIsNonErrComptimeOnly(...@@ -25431,10 +25527,16 @@ fn analyzeIsNonErrComptimeOnly(
25431 assert(ot == .ErrorUnion);25527 assert(ot == .ErrorUnion);
2543225528
25433 if (Air.refToIndex(operand)) |operand_inst| {25529 if (Air.refToIndex(operand)) |operand_inst| {
25434 const air_tags = sema.air_instructions.items(.tag);25530 switch (sema.air_instructions.items(.tag)[operand_inst]) {
25435 if (air_tags[operand_inst] == .wrap_errunion_payload) {25531 .wrap_errunion_payload => return Air.Inst.Ref.bool_true,
25436 return Air.Inst.Ref.bool_true;25532 .wrap_errunion_err => return Air.Inst.Ref.bool_false,
25533 else => {},
25437 }25534 }
25535 } else if (operand == .undef) {
25536 return sema.addConstUndef(Type.bool);
25537 } else {
25538 // None of the ref tags can be errors.
25539 return Air.Inst.Ref.bool_true;
25438 }25540 }
2543925541
25440 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);25542 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, src, operand);
...@@ -25510,6 +25612,21 @@ fn analyzeIsNonErr(...@@ -25510,6 +25612,21 @@ fn analyzeIsNonErr(
25510 }25612 }
25511}25613}
2551225614
25615fn analyzePtrIsNonErr(
25616 sema: *Sema,
25617 block: *Block,
25618 src: LazySrcLoc,
25619 operand: Air.Inst.Ref,
25620) CompileError!Air.Inst.Ref {
25621 const result = try sema.analyzePtrIsNonErrComptimeOnly(block, src, operand);
25622 if (result == .none) {
25623 try sema.requireRuntimeBlock(block, src, null);
25624 return block.addUnOp(.is_non_err_ptr, operand);
25625 } else {
25626 return result;
25627 }
25628}
25629
25513fn analyzeSlice(25630fn analyzeSlice(
25514 sema: *Sema,25631 sema: *Sema,
25515 block: *Block,25632 block: *Block,
test/stack_traces.zig+1
...@@ -22,6 +22,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -22,6 +22,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
22 .ReleaseSafe = .{22 .ReleaseSafe = .{
23 .exclude_os = .{23 .exclude_os = .{
24 .windows, // segfault24 .windows, // segfault
25 .linux, // defeated by aggressive inlining
25 },26 },
26 .expect = 27 .expect =
27 \\error: TheSkyIsFalling28 \\error: TheSkyIsFalling