authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-22 01:51:39+00:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2025-01-22 02:22:56-05:00
log1bce01de97f04984feea7e79ae0809d7b623cdd0
tree35da62a30d630a34b97b3f46f4a64fede28b4b08
parent941677e08318c2baaabc9d0fc87892d1b63487ae

compiler: pass error return traces everywhere


4 files changed, 44 insertions(+), 60 deletions(-)

src/InternPool.zig+7-18
......@@ -2294,17 +2294,6 @@ pub const Key = union(enum) {
22942294 return @atomicLoad(FuncAnalysis, func.analysisPtr(ip), .unordered);
22952295 }
22962296
2297 pub fn setCallsOrAwaitsErrorableFn(func: Func, ip: *InternPool, value: bool) void {
2298 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
2299 extra_mutex.lock();
2300 defer extra_mutex.unlock();
2301
2302 const analysis_ptr = func.analysisPtr(ip);
2303 var analysis = analysis_ptr.*;
2304 analysis.calls_or_awaits_errorable_fn = value;
2305 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
2306 }
2307
23082297 pub fn setBranchHint(func: Func, ip: *InternPool, hint: std.builtin.BranchHint) void {
23092298 const extra_mutex = &ip.getLocal(func.tid).mutate.extra.mutex;
23102299 extra_mutex.lock();
......@@ -5975,7 +5964,7 @@ pub const FuncAnalysis = packed struct(u32) {
59755964 is_analyzed: bool,
59765965 branch_hint: std.builtin.BranchHint,
59775966 is_noinline: bool,
5978 calls_or_awaits_errorable_fn: bool,
5967 has_error_trace: bool,
59795968 /// True if this function has an inferred error set.
59805969 inferred_error_set: bool,
59815970 disable_instrumentation: bool,
......@@ -9007,7 +8996,7 @@ pub fn getFuncDecl(
90078996 .is_analyzed = false,
90088997 .branch_hint = .none,
90098998 .is_noinline = key.is_noinline,
9010 .calls_or_awaits_errorable_fn = false,
8999 .has_error_trace = false,
90119000 .inferred_error_set = false,
90129001 .disable_instrumentation = false,
90139002 },
......@@ -9116,7 +9105,7 @@ pub fn getFuncDeclIes(
91169105 .is_analyzed = false,
91179106 .branch_hint = .none,
91189107 .is_noinline = key.is_noinline,
9119 .calls_or_awaits_errorable_fn = false,
9108 .has_error_trace = false,
91209109 .inferred_error_set = true,
91219110 .disable_instrumentation = false,
91229111 },
......@@ -9312,7 +9301,7 @@ pub fn getFuncInstance(
93129301 .is_analyzed = false,
93139302 .branch_hint = .none,
93149303 .is_noinline = arg.is_noinline,
9315 .calls_or_awaits_errorable_fn = false,
9304 .has_error_trace = false,
93169305 .inferred_error_set = false,
93179306 .disable_instrumentation = false,
93189307 },
......@@ -9410,7 +9399,7 @@ pub fn getFuncInstanceIes(
94109399 .is_analyzed = false,
94119400 .branch_hint = .none,
94129401 .is_noinline = arg.is_noinline,
9413 .calls_or_awaits_errorable_fn = false,
9402 .has_error_trace = false,
94149403 .inferred_error_set = true,
94159404 .disable_instrumentation = false,
94169405 },
......@@ -12174,7 +12163,7 @@ pub fn funcAnalysisUnordered(ip: *const InternPool, func: Index) FuncAnalysis {
1217412163 return @atomicLoad(FuncAnalysis, ip.funcAnalysisPtr(func), .unordered);
1217512164}
1217612165
12177pub fn funcSetCallsOrAwaitsErrorableFn(ip: *InternPool, func: Index) void {
12166pub fn funcSetHasErrorTrace(ip: *InternPool, func: Index, has_error_trace: bool) void {
1217812167 const unwrapped_func = func.unwrap(ip);
1217912168 const extra_mutex = &ip.getLocal(unwrapped_func.tid).mutate.extra.mutex;
1218012169 extra_mutex.lock();
......@@ -12182,7 +12171,7 @@ pub fn funcSetCallsOrAwaitsErrorableFn(ip: *InternPool, func: Index) void {
1218212171
1218312172 const analysis_ptr = ip.funcAnalysisPtr(func);
1218412173 var analysis = analysis_ptr.*;
12185 analysis.calls_or_awaits_errorable_fn = true;
12174 analysis.has_error_trace = has_error_trace;
1218612175 @atomicStore(FuncAnalysis, analysis_ptr, analysis, .release);
1218712176}
1218812177
src/Sema.zig+19-24
......@@ -7191,14 +7191,6 @@ fn zirCall(
71917191 const call_dbg_node: Zir.Inst.Index = @enumFromInt(@intFromEnum(inst) - 1);
71927192 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
71937193
7194 switch (sema.owner.unwrap()) {
7195 .@"comptime", .type, .memoized_state, .nav_ty, .nav_val => input_is_error = false,
7196 .func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {
7197 // No errorable fn actually called; we have no error return trace
7198 input_is_error = false;
7199 },
7200 }
7201
72027194 if (block.ownerModule().error_tracing and
72037195 !block.isComptime() and !block.is_typeof and (input_is_error or pop_error_return_trace))
72047196 {
......@@ -7865,6 +7857,12 @@ fn analyzeCall(
78657857 }
78667858 break :msg msg;
78677859 });
7860 if (func_ty_info.cc == .auto) {
7861 switch (sema.owner.unwrap()) {
7862 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
7863 .func => |owner_func| ip.funcSetHasErrorTrace(owner_func, true),
7864 }
7865 }
78687866 for (args, 0..) |arg, arg_idx| {
78697867 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
78707868 }
......@@ -7939,13 +7937,6 @@ fn analyzeCall(
79397937 try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern());
79407938 }
79417939
7942 switch (sema.owner.unwrap()) {
7943 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
7944 .func => |owner_func| if (resolved_ret_ty.isError(zcu)) {
7945 ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
7946 },
7947 }
7948
79497940 const call_tag: Air.Inst.Tag = switch (modifier) {
79507941 .auto, .no_async => .call,
79517942 .never_tail => .call_never_tail,
......@@ -19699,16 +19690,16 @@ fn retWithErrTracing(
1969919690 .bool_false => false,
1970019691 else => true,
1970119692 };
19693
19694 // This means we're returning something that might be an error!
19695 // This should only be possible with the `auto` cc, so we definitely have an error trace.
19696 assert(pt.zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).has_error_trace);
19697
1970219698 const gpa = sema.gpa;
19703 const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
19704 try stack_trace_ty.resolveFields(pt);
19705 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
19706 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
1970719699 const return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError));
19708 const args: [1]Air.Inst.Ref = .{err_return_trace};
1970919700
1971019701 if (!need_check) {
19711 try sema.callBuiltin(block, src, return_err_fn, .never_inline, &args, .@"error return");
19702 try sema.callBuiltin(block, src, return_err_fn, .never_inline, &.{}, .@"error return");
1971219703 _ = try block.addUnOp(ret_tag, operand);
1971319704 return;
1971419705 }
......@@ -19719,7 +19710,7 @@ fn retWithErrTracing(
1971919710
1972019711 var else_block = block.makeSubBlock();
1972119712 defer else_block.instructions.deinit(gpa);
19722 try sema.callBuiltin(&else_block, src, return_err_fn, .never_inline, &args, .@"error return");
19713 try sema.callBuiltin(&else_block, src, return_err_fn, .never_inline, &.{}, .@"error return");
1972319714 _ = try else_block.addUnOp(ret_tag, operand);
1972419715
1972519716 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".fields.len +
......@@ -19830,7 +19821,7 @@ fn restoreErrRetIndex(sema: *Sema, start_block: *Block, src: LazySrcLoc, target_
1983019821 return;
1983119822 }
1983219823
19833 if (!zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).calls_or_awaits_errorable_fn) return;
19824 if (!zcu.intern_pool.funcAnalysisUnordered(sema.owner.unwrap().func).has_error_trace) return;
1983419825 if (!start_block.ownerModule().error_tracing) return;
1983519826
1983619827 assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere
......@@ -21116,7 +21107,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
2111621107 const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
2111721108
2111821109 switch (sema.owner.unwrap()) {
21119 .func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {
21110 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {
2112021111 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
2112121112 },
2112221113 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
......@@ -27089,6 +27080,10 @@ fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPo
2708927080 const zcu = sema.pt.zcu;
2709027081 try sema.ensureMemoizedStateResolved(src, .panic);
2709127082 try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.get(.@"Panic.call"));
27083 switch (sema.owner.unwrap()) {
27084 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
27085 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(owner_func, true),
27086 }
2709227087 return zcu.builtin_decl_values.get(panic_id.toBuiltin());
2709327088}
2709427089
src/Zcu/PerThread.zig+4-6
......@@ -2596,7 +2596,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
25962596 }
25972597
25982598 // reset in case calls to errorable functions are removed.
2599 func.setCallsOrAwaitsErrorableFn(ip, false);
2599 ip.funcSetHasErrorTrace(func_index, fn_ty_info.cc == .auto);
26002600
26012601 // First few indexes of extra are reserved and set at the end.
26022602 const reserved_count = @typeInfo(Air.ExtraIndex).@"enum".fields.len;
......@@ -2707,11 +2707,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
27072707
27082708 func.setBranchHint(ip, sema.branch_hint orelse .none);
27092709
2710 // If we don't get an error return trace from a caller, create our own.
2711 if (func.analysisUnordered(ip).calls_or_awaits_errorable_fn and
2712 zcu.comp.config.any_error_tracing and
2713 !sema.fn_ret_ty.isError(zcu))
2714 {
2710 if (zcu.comp.config.any_error_tracing and func.analysisUnordered(ip).has_error_trace and fn_ty_info.cc != .auto) {
2711 // We're using an error trace, but didn't start out with one from the caller.
2712 // We'll have to create it at the start of the function.
27152713 sema.setupErrorReturnTrace(&inner_block, last_arg_index) catch |err| switch (err) {
27162714 error.ComptimeReturn => unreachable,
27172715 error.ComptimeBreak => unreachable,
src/codegen/llvm.zig+14-12
......@@ -1497,8 +1497,7 @@ pub const Object = struct {
14971497 .unsigned => try attributes.addRetAttr(.zeroext, &o.builder),
14981498 };
14991499
1500 const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and
1501 comp.config.any_error_tracing;
1500 const err_return_tracing = fn_info.cc == .auto and comp.config.any_error_tracing;
15021501
15031502 const err_ret_trace: Builder.Value = if (err_return_tracing) param: {
15041503 const param = wip.arg(llvm_arg_i);
......@@ -2805,9 +2804,7 @@ pub const Object = struct {
28052804 debug_param_types.appendAssumeCapacity(try o.lowerDebugType(Type.void));
28062805 }
28072806
2808 if (Type.fromInterned(fn_info.return_type).isError(zcu) and
2809 zcu.comp.config.any_error_tracing)
2810 {
2807 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
28112808 const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType());
28122809 debug_param_types.appendAssumeCapacity(try o.lowerDebugType(ptr_ty));
28132810 }
......@@ -2970,8 +2967,7 @@ pub const Object = struct {
29702967 llvm_arg_i += 1;
29712968 }
29722969
2973 const err_return_tracing = Type.fromInterned(fn_info.return_type).isError(zcu) and
2974 zcu.comp.config.any_error_tracing;
2970 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
29752971
29762972 if (err_return_tracing) {
29772973 try attributes.addParamAttr(llvm_arg_i, .nonnull, &o.builder);
......@@ -3736,9 +3732,7 @@ pub const Object = struct {
37363732 try llvm_params.append(o.gpa, .ptr);
37373733 }
37383734
3739 if (Type.fromInterned(fn_info.return_type).isError(zcu) and
3740 zcu.comp.config.any_error_tracing)
3741 {
3735 if (fn_info.cc == .auto and zcu.comp.config.any_error_tracing) {
37423736 const ptr_ty = try pt.singleMutPtrType(try o.getStackTraceType());
37433737 try llvm_params.append(o.gpa, try o.lowerType(ptr_ty));
37443738 }
......@@ -5483,7 +5477,7 @@ pub const FuncGen = struct {
54835477 break :blk ret_ptr;
54845478 };
54855479
5486 const err_return_tracing = return_type.isError(zcu) and zcu.comp.config.any_error_tracing;
5480 const err_return_tracing = fn_info.cc == .auto and zcu.comp.config.any_error_tracing;
54875481 if (err_return_tracing) {
54885482 assert(self.err_ret_trace != .none);
54895483 try llvm_args.append(self.err_ret_trace);
......@@ -5762,6 +5756,8 @@ pub const FuncGen = struct {
57625756 const panic_nav = ip.getNav(panic_func.owner_nav);
57635757 const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
57645758 const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
5759 const has_err_trace = zcu.comp.config.any_error_tracing and fn_info.cc == .auto;
5760 if (has_err_trace) assert(fg.err_ret_trace != .none);
57655761 _ = try fg.wip.callIntrinsicAssumeCold();
57665762 _ = try fg.wip.call(
57675763 .normal,
......@@ -5769,7 +5765,13 @@ pub const FuncGen = struct {
57695765 .none,
57705766 panic_global.typeOf(&o.builder),
57715767 panic_global.toValue(&o.builder),
5772 &.{
5768 if (has_err_trace) &.{
5769 fg.err_ret_trace,
5770 msg_ptr.toValue(),
5771 try o.builder.intValue(llvm_usize, msg_len),
5772 try o.builder.nullValue(.ptr),
5773 null_opt_addr_global.toValue(),
5774 } else &.{
57735775 msg_ptr.toValue(),
57745776 try o.builder.intValue(llvm_usize, msg_len),
57755777 try o.builder.nullValue(.ptr),