From 70040778fbde5d7fcbbfc26dbabc700024c538d5 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sun, 30 Mar 2025 22:59:25 +0100 Subject: [PATCH 1/5] Compilation: fix reference trace behavior without `-freference-trace` When `-freference-trace` is not passed, we want to show exactly one reference trace. Previously, we set the reference trace root in `Sema` iff there were no other failed analyses. However, this results in an arbitrary error being the one with the reference trace after error sorting. It is also incompatible with incremental compilation, where some errors might be unreferenced. Instead, set the field on all analysis errors, and decide in `Compilation.getAllErrorsAlloc` which reference trace[s] to actually show. --- src/Compilation.zig | 29 ++++++++++++++++++++--------- src/Sema.zig | 8 ++------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 351b81c1227808cd45386a53ab896f491004b60e..57e36bfbf7d6f1ca0979fc9084d9dd1f751d4b83 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3328,7 +3328,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { if (comp.zcu) |zcu| zcu_errors: { for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { if (error_msg) |msg| { - try addModuleErrorMsg(zcu, &bundle, msg.*); + try addModuleErrorMsg(zcu, &bundle, msg.*, false); } else { // Must be ZIR or Zoir errors. Note that this may include AST errors. _ = try file.getTree(gpa); // Tree must be loaded. @@ -3378,6 +3378,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { break :s entries.slice(); }; defer sorted_failed_analysis.deinit(gpa); + var added_any_analysis_error = false; for (sorted_failed_analysis.items(.key), sorted_failed_analysis.items(.value)) |anal_unit, error_msg| { if (comp.incremental) { const refs = try zcu.resolveReferences(); @@ -3389,7 +3390,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { zcu.fmtAnalUnit(anal_unit), }); - try addModuleErrorMsg(zcu, &bundle, error_msg.*); + try addModuleErrorMsg(zcu, &bundle, error_msg.*, added_any_analysis_error); + added_any_analysis_error = true; + if (zcu.cimport_errors.get(anal_unit)) |errors| { for (errors.getMessages()) |err_msg_index| { const err_msg = errors.getErrorMessage(err_msg_index); @@ -3412,13 +3415,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { } } for (zcu.failed_codegen.values()) |error_msg| { - try addModuleErrorMsg(zcu, &bundle, error_msg.*); + try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); } for (zcu.failed_types.values()) |error_msg| { - try addModuleErrorMsg(zcu, &bundle, error_msg.*); + try addModuleErrorMsg(zcu, &bundle, error_msg.*, false); } for (zcu.failed_exports.values()) |value| { - try addModuleErrorMsg(zcu, &bundle, value.*); + try addModuleErrorMsg(zcu, &bundle, value.*, false); } const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len; @@ -3527,7 +3530,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { // We don't actually include the error here if `!include_compile_log_sources`. // The sorting above was still necessary, though, to get `log_text` in the right order. if (include_compile_log_sources) { - try addModuleErrorMsg(zcu, &bundle, messages.items[0]); + try addModuleErrorMsg(zcu, &bundle, messages.items[0], false); } break :compile_log_text try log_text.toOwnedSlice(gpa); @@ -3631,10 +3634,14 @@ pub const ErrorNoteHashContext = struct { } }; +const default_reference_trace_len = 2; pub fn addModuleErrorMsg( zcu: *Zcu, eb: *ErrorBundle.Wip, module_err_msg: Zcu.ErrorMsg, + /// If `-freference-trace` is not specified, we only want to show the one reference trace. + /// So, this is whether we have already emitted an error with a reference trace. + already_added_error: bool, ) !void { const gpa = eb.gpa; const ip = &zcu.intern_pool; @@ -3657,14 +3664,18 @@ pub fn addModuleErrorMsg( var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .empty; defer ref_traces.deinit(gpa); - if (module_err_msg.reference_trace_root.unwrap()) |rt_root| { + rt: { + const rt_root = module_err_msg.reference_trace_root.unwrap() orelse break :rt; + const max_references = zcu.comp.reference_trace orelse refs: { + if (already_added_error) break :rt; + break :refs default_reference_trace_len; + }; + const all_references = try zcu.resolveReferences(); var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty; defer seen.deinit(gpa); - const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len; - var referenced_by = rt_root; while (all_references.get(referenced_by)) |maybe_ref| { const ref = maybe_ref orelse break; diff --git a/src/Sema.zig b/src/Sema.zig index 8889b475fd186adb5fc70e80e55b401c3d421cfd..e13aba334905c025a964be520eae288763416b58 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -191,7 +191,6 @@ const LowerZon = @import("Sema/LowerZon.zig"); const arith = @import("Sema/arith.zig"); pub const default_branch_quota = 1000; -pub const default_reference_trace_len = 2; pub const InferredErrorSet = struct { /// The function body from which this error set originates. @@ -2580,7 +2579,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) { var wip_errors: std.zig.ErrorBundle.Wip = undefined; wip_errors.init(gpa) catch @panic("out of memory"); - Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory"); + Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, false) catch @panic("out of memory"); std.debug.print("compile error during Sema:\n", .{}); var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory"); error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); @@ -2600,10 +2599,7 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg } } - const use_ref_trace = if (zcu.comp.reference_trace) |n| n > 0 else zcu.failed_analysis.count() == 0; - if (use_ref_trace) { - err_msg.reference_trace_root = sema.owner.toOptional(); - } + err_msg.reference_trace_root = sema.owner.toOptional(); const gop = try zcu.failed_analysis.getOrPut(gpa, sema.owner); if (gop.found_existing) { -- 2.54.0 From d717c96877355090ea3a8e3662a2584eea02445c Mon Sep 17 00:00:00 2001 From: mlugg Date: Thu, 15 May 2025 13:18:08 +0100 Subject: [PATCH 2/5] compiler: include inline calls in the reference trace Inline calls which happened in the erroring `AnalUnit` still show as error notes, because they tend to make very important context (e.g. to see how comptime values propagate through them). However, "earlier" inline calls are still useful to see to understand how something is being referenced, so we should include them in the reference trace. --- src/Compilation.zig | 66 +++++++++++++++++-------- src/Sema.zig | 84 +++++++++++++++++++------------- src/Sema/comptime_ptr_access.zig | 2 +- src/Zcu.zig | 80 +++++++++++++++++++++++++++++- 4 files changed, 175 insertions(+), 57 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 57e36bfbf7d6f1ca0979fc9084d9dd1f751d4b83..d3cf9e8f38bf4528ccef1be66ad5577a801d1959 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3681,32 +3681,27 @@ pub fn addModuleErrorMsg( const ref = maybe_ref orelse break; const gop = try seen.getOrPut(gpa, ref.referencer); if (gop.found_existing) break; - if (ref_traces.items.len < max_references) skip: { - const src = ref.src.upgrade(zcu); - const source = try src.file_scope.getSource(gpa); - const span = try src.span(gpa); - const loc = std.zig.findLineColumn(source.bytes, span.main); - const rt_file_path = try src.file_scope.fullPath(gpa); - defer gpa.free(rt_file_path); - const name = switch (ref.referencer.unwrap()) { + if (ref_traces.items.len < max_references) { + var last_call_src = ref.src; + var opt_inline_frame = ref.inline_frame; + while (opt_inline_frame.unwrap()) |inline_frame| { + const f = inline_frame.ptr(zcu).*; + const func_nav = ip.indexToKey(f.callee).func.owner_nav; + const func_name = ip.getNav(func_nav).name.toSlice(ip); + try addReferenceTraceFrame(zcu, eb, &ref_traces, func_name, last_call_src, true); + last_call_src = f.call_src; + opt_inline_frame = f.parent; + } + const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { .@"comptime" => "comptime", .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), - .memoized_state => break :skip, + .memoized_state => null, }; - try ref_traces.append(gpa, .{ - .decl_name = try eb.addString(name), - .src_loc = try eb.addSourceLocation(.{ - .src_path = try eb.addString(rt_file_path), - .span_start = span.start, - .span_main = span.main, - .span_end = span.end, - .line = @intCast(loc.line), - .column = @intCast(loc.column), - .source_line = 0, - }), - }); + if (root_name) |n| { + try addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false); + } } referenced_by = ref.referencer; } @@ -3786,6 +3781,35 @@ pub fn addModuleErrorMsg( } } +fn addReferenceTraceFrame( + zcu: *Zcu, + eb: *ErrorBundle.Wip, + ref_traces: *std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace), + name: []const u8, + lazy_src: Zcu.LazySrcLoc, + inlined: bool, +) !void { + const gpa = zcu.gpa; + const src = lazy_src.upgrade(zcu); + const source = try src.file_scope.getSource(gpa); + const span = try src.span(gpa); + const loc = std.zig.findLineColumn(source.bytes, span.main); + const rt_file_path = try src.file_scope.fullPath(gpa); + defer gpa.free(rt_file_path); + try ref_traces.append(gpa, .{ + .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }), + .src_loc = try eb.addSourceLocation(.{ + .src_path = try eb.addString(rt_file_path), + .span_start = span.start, + .span_main = span.main, + .span_end = span.end, + .line = @intCast(loc.line), + .column = @intCast(loc.column), + .source_line = 0, + }), + }); +} + pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void { const gpa = eb.gpa; const src_path = try file.fullPath(gpa); diff --git a/src/Sema.zig b/src/Sema.zig index e13aba334905c025a964be520eae288763416b58..d267dcdb473ec9f0565c70b29d8c57a93bb4eaed 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -448,6 +448,21 @@ pub const Block = struct { func: InternPool.Index, comptime_result: Air.Inst.Ref, merges: Merges, + /// Populated lazily by `refFrame`. + ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none, + + fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index { + if (inlining.ref_frame == .none) { + inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{ + .callee = inlining.func, + .call_src = inlining.call_src, + .parent = if (inlining.call_block.inlining) |parent_inlining| p: { + break :p (try parent_inlining.refFrame(zcu)).toOptional(); + } else .none, + })).toOptional(); + } + return inlining.ref_frame.unwrap().?; + } }; pub const Merges = struct { @@ -4287,7 +4302,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com if (zcu.intern_pool.isFuncBody(val)) { const ty = Type.fromInterned(zcu.intern_pool.typeOf(val)); if (try ty.fnHasRuntimeBitsSema(pt)) { - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val })); + try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = val })); try zcu.ensureFuncBodyAnalysisQueued(val); } } @@ -6615,7 +6630,7 @@ pub fn analyzeExport( if (options.linkage == .internal) return; - try sema.ensureNavResolved(src, orig_nav_index, .fully); + try sema.ensureNavResolved(block, src, orig_nav_index, .fully); const exported_nav_index = switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) { .variable => |v| v.owner_nav, @@ -6644,7 +6659,7 @@ pub fn analyzeExport( return sema.fail(block, src, "export target cannot be extern", .{}); } - try sema.maybeQueueFuncBodyAnalysis(src, exported_nav_index); + try sema.maybeQueueFuncBodyAnalysis(block, src, exported_nav_index); try sema.exports.append(gpa, .{ .opts = options, @@ -6892,7 +6907,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air .no_embedded_nulls, ); const nav_index = try sema.lookupIdentifier(block, src, decl_name); - return sema.analyzeNavRef(src, nav_index); + return sema.analyzeNavRef(block, src, nav_index); } fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { @@ -6988,7 +7003,7 @@ fn lookupInNamespace( } for (usingnamespaces.items) |sub_ns_nav| { - try sema.ensureNavResolved(src, sub_ns_nav, .fully); + try sema.ensureNavResolved(block, src, sub_ns_nav, .fully); const sub_ns_ty = Type.fromInterned(ip.getNav(sub_ns_nav).status.fully_resolved.val); const sub_ns = zcu.namespacePtr(sub_ns_ty.getNamespaceIndex(zcu)); try checked_namespaces.put(gpa, sub_ns, {}); @@ -7720,8 +7735,8 @@ fn analyzeCall( var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{ .call_block = block, .call_src = call_src, + .func = func_val.?.toIntern(), .has_comptime_args = false, // unused by error reporting - .func = .none, // unused by error reporting .comptime_result = .none, // unused by error reporting .merges = undefined, // unused because we'll never `return` } else undefined; @@ -7999,7 +8014,7 @@ fn analyzeCall( ref_func: { const runtime_func_val = try sema.resolveValue(runtime_func) orelse break :ref_func; if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func; - try sema.addReferenceEntry(call_src, .wrap(.{ .func = runtime_func_val.toIntern() })); + try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = runtime_func_val.toIntern() })); try zcu.ensureFuncBodyAnalysisQueued(runtime_func_val.toIntern()); } @@ -17254,7 +17269,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat .@"comptime" => |index| return Air.internedToRef(index), .runtime => |index| index, .nav_val => |nav| return sema.analyzeNavVal(block, src, nav), - .nav_ref => |nav| return sema.analyzeNavRef(src, nav), + .nav_ref => |nav| return sema.analyzeNavRef(block, src, nav), }; // The comptime case is handled already above. Runtime case below. @@ -18407,7 +18422,7 @@ fn typeInfoNamespaceDecls( if (zcu.analysis_in_progress.contains(.wrap(.{ .nav_val = nav }))) { continue; } - try sema.ensureNavResolved(src, nav, .fully); + try sema.ensureNavResolved(block, src, nav, .fully); const namespace_ty = Type.fromInterned(ip.getNav(nav).status.fully_resolved.val); try sema.typeInfoNamespaceDecls(block, src, namespace_ty.getNamespaceIndex(zcu).toOptional(), declaration_ty, decl_vals, seen_namespaces); } @@ -27932,7 +27947,7 @@ fn namespaceLookupRef( decl_name: InternPool.NullTerminatedString, ) CompileError!?Air.Inst.Ref { const nav = try sema.namespaceLookup(block, src, namespace, decl_name) orelse return null; - return try sema.analyzeNavRef(src, nav); + return try sema.analyzeNavRef(block, src, nav); } fn namespaceLookupVal( @@ -29095,7 +29110,7 @@ fn coerceExtra( .@"extern" => |e| e.owner_nav, else => unreachable, }; - const inst_as_ptr = try sema.analyzeNavRef(inst_src, fn_nav); + const inst_as_ptr = try sema.analyzeNavRef(block, inst_src, fn_nav); return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); } @@ -30748,7 +30763,7 @@ fn coerceVarArgParam( .@"fn" => fn_ptr: { const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); const fn_nav = zcu.funcInfo(fn_val.toIntern()).owner_nav; - break :fn_ptr try sema.analyzeNavRef(inst_src, fn_nav); + break :fn_ptr try sema.analyzeNavRef(block, inst_src, fn_nav); }, .array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), .float => float: { @@ -31758,12 +31773,13 @@ fn analyzeNavVal( src: LazySrcLoc, nav_index: InternPool.Nav.Index, ) CompileError!Air.Inst.Ref { - const ref = try sema.analyzeNavRefInner(src, nav_index, false); + const ref = try sema.analyzeNavRefInner(block, src, nav_index, false); return sema.analyzeLoad(block, src, ref, src); } fn addReferenceEntry( sema: *Sema, + opt_block: ?*Block, src: LazySrcLoc, referenced_unit: AnalUnit, ) !void { @@ -31771,10 +31787,12 @@ fn addReferenceEntry( if (!zcu.comp.incremental and zcu.comp.reference_trace == 0) return; const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); if (gop.found_existing) return; - // TODO: we need to figure out how to model inline calls here. - // They aren't references in the analysis sense, but ought to show up in the reference trace! - // Would representing inline calls in the reference table cause excessive memory usage? - try zcu.addUnitReference(sema.owner, referenced_unit, src); + try zcu.addUnitReference(sema.owner, referenced_unit, src, inline_frame: { + const block = opt_block orelse break :inline_frame .none; + const inlining = block.inlining orelse break :inline_frame .none; + const frame = try inlining.refFrame(zcu); + break :inline_frame frame.toOptional(); + }); } pub fn addTypeReferenceEntry( @@ -31793,7 +31811,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M const pt = sema.pt; const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); - try sema.addReferenceEntry(src, unit); + try sema.addReferenceEntry(null, src, unit); try sema.declareDependency(.{ .memoized_state = stage }); if (pt.zcu.analysis_in_progress.contains(unit)) { @@ -31802,7 +31820,7 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M try pt.ensureMemoizedStateUpToDate(stage); } -pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { +pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -31825,7 +31843,7 @@ pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav .type => .{ .nav_ty = nav_index }, .fully => .{ .nav_val = nav_index }, }); - try sema.addReferenceEntry(src, anal_unit); + try sema.addReferenceEntry(block, src, anal_unit); if (zcu.analysis_in_progress.contains(anal_unit)) { return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{ @@ -31855,25 +31873,25 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { } })); } -fn analyzeNavRef(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref { - return sema.analyzeNavRefInner(src, nav_index, true); +fn analyzeNavRef(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) CompileError!Air.Inst.Ref { + return sema.analyzeNavRefInner(block, src, nav_index, true); } /// Analyze a reference to the `Nav` at the given index. Ensures the underlying `Nav` is analyzed. /// If this pointer will be used directly, `is_ref` must be `true`. /// If this pointer will be immediately loaded (i.e. a `decl_val` instruction), `is_ref` must be `false`. -fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref { +fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_index: InternPool.Nav.Index, is_ref: bool) CompileError!Air.Inst.Ref { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; - try sema.ensureNavResolved(src, orig_nav_index, if (is_ref) .type else .fully); + try sema.ensureNavResolved(block, src, orig_nav_index, if (is_ref) .type else .fully); const nav_index = nav: { if (ip.getNav(orig_nav_index).isExternOrFn(ip)) { // Getting a pointer to this `Nav` might mean we actually get a pointer to something else! // We need to resolve the value to know for sure. - if (is_ref) try sema.ensureNavResolved(src, orig_nav_index, .fully); + if (is_ref) try sema.ensureNavResolved(block, src, orig_nav_index, .fully); switch (ip.indexToKey(ip.getNav(orig_nav_index).status.fully_resolved.val)) { .func => |f| break :nav f.owner_nav, .@"extern" => |e| break :nav e.owner_nav, @@ -31897,7 +31915,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N }, }); if (is_ref) { - try sema.maybeQueueFuncBodyAnalysis(src, nav_index); + try sema.maybeQueueFuncBodyAnalysis(block, src, nav_index); } return Air.internedToRef((try pt.intern(.{ .ptr = .{ .ty = ptr_ty.toIntern(), @@ -31906,7 +31924,7 @@ fn analyzeNavRefInner(sema: *Sema, src: LazySrcLoc, orig_nav_index: InternPool.N } }))); } -fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void { +fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index) !void { const pt = sema.pt; const zcu = pt.zcu; const ip = &zcu.intern_pool; @@ -31914,16 +31932,16 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, nav_index: InternPoo // To avoid forcing too much resolution, let's first resolve the type, and check if it's a function. // If it is, we can resolve the *value*, and queue analysis as needed. - try sema.ensureNavResolved(src, nav_index, .type); + try sema.ensureNavResolved(block, src, nav_index, .type); const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip)); if (nav_ty.zigTypeTag(zcu) != .@"fn") return; if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return; - try sema.ensureNavResolved(src, nav_index, .fully); + try sema.ensureNavResolved(block, src, nav_index, .fully); const nav_val = zcu.navValue(nav_index); if (!ip.isFuncBody(nav_val.toIntern())) return; - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = nav_val.toIntern() })); + try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = nav_val.toIntern() })); try zcu.ensureFuncBodyAnalysisQueued(nav_val.toIntern()); } @@ -31939,8 +31957,8 @@ fn analyzeRef( if (try sema.resolveValue(operand)) |val| { switch (zcu.intern_pool.indexToKey(val.toIntern())) { - .@"extern" => |e| return sema.analyzeNavRef(src, e.owner_nav), - .func => |f| return sema.analyzeNavRef(src, f.owner_nav), + .@"extern" => |e| return sema.analyzeNavRef(block, src, e.owner_nav), + .func => |f| return sema.analyzeNavRef(block, src, f.owner_nav), else => return uavRef(sema, val.toIntern()), } } @@ -35504,7 +35522,7 @@ fn resolveInferredErrorSet( } // In this case we are dealing with the actual InferredErrorSet object that // corresponds to the function, not one created to track an inline/comptime call. - try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index })); + try sema.addReferenceEntry(block, src, AnalUnit.wrap(.{ .func = func_index })); try pt.ensureFuncBodyUpToDate(func_index); } diff --git a/src/Sema/comptime_ptr_access.zig b/src/Sema/comptime_ptr_access.zig index 2e21c31f2be64c611888d80b32183c5a796caf46..f4ac8971549c554f4a64c70ef264c13ebb1e46dd 100644 --- a/src/Sema/comptime_ptr_access.zig +++ b/src/Sema/comptime_ptr_access.zig @@ -228,7 +228,7 @@ fn loadComptimePtrInner( const base_val: MutableValue = switch (ptr.base_addr) { .nav => |nav| val: { - try sema.ensureNavResolved(src, nav, .fully); + try sema.ensureNavResolved(block, src, nav, .fully); const val = ip.getNav(nav).status.fully_resolved.val; switch (ip.indexToKey(val)) { .variable => return .runtime_load, diff --git a/src/Zcu.zig b/src/Zcu.zig index fab40763e8dadb15bc516a79fbf44fea99d049aa..584eb8ca3d11c5ca04f8b33e8d14a379f430a689 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -215,6 +215,9 @@ all_references: std.ArrayListUnmanaged(Reference) = .empty, /// Freelist of indices in `all_references`. free_references: std.ArrayListUnmanaged(u32) = .empty, +inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame) = .empty, +free_inline_reference_frames: std.ArrayListUnmanaged(InlineReferenceFrame.Index) = .empty, + /// Key is the `AnalUnit` *performing* the reference. This representation allows /// incremental updates to quickly delete references caused by a specific `AnalUnit`. /// Value is index into `all_type_reference` of the first reference triggered by the unit. @@ -583,6 +586,42 @@ pub const Reference = struct { next: u32, /// The source location of the reference. src: LazySrcLoc, + /// If not `.none`, this is the index of the `InlineReferenceFrame` which should appear + /// between the referencer and `referenced` in the reference trace. These frames represent + /// inline calls, which do not create actual references (since they happen in the caller's + /// `AnalUnit`), but do show in the reference trace. + inline_frame: InlineReferenceFrame.Index.Optional, +}; + +pub const InlineReferenceFrame = struct { + /// The inline *callee*; that is, the function which was called inline. + /// The *caller* is either `parent`, or else the unit causing the original `Reference`. + callee: InternPool.Index, + /// The source location of the inline call, in the *caller*. + call_src: LazySrcLoc, + /// If not `.none`, a frame which should appear directly below this one. + /// This will be the "parent" inline call; this frame's `callee` is our caller. + parent: InlineReferenceFrame.Index.Optional, + + pub const Index = enum(u32) { + _, + pub fn ptr(idx: Index, zcu: *Zcu) *InlineReferenceFrame { + return &zcu.inline_reference_frames.items[@intFromEnum(idx)]; + } + pub fn toOptional(idx: Index) Optional { + return @enumFromInt(@intFromEnum(idx)); + } + pub const Optional = enum(u32) { + none = std.math.maxInt(u32), + _, + pub fn unwrap(opt: Optional) ?Index { + return switch (opt) { + .none => null, + _ => @enumFromInt(@intFromEnum(opt)), + }; + } + }; + }; }; pub const TypeReference = struct { @@ -3440,12 +3479,28 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { var idx = kv.value; while (idx != std.math.maxInt(u32)) { + const ref = zcu.all_references.items[idx]; zcu.free_references.append(gpa, idx) catch { // This space will be reused eventually, so we need not propagate this error. // Just leak it for now, and let GC reclaim it later on. break :unit_refs; }; - idx = zcu.all_references.items[idx].next; + idx = ref.next; + + var opt_inline_frame = ref.inline_frame; + while (opt_inline_frame.unwrap()) |inline_frame| { + // The same inline frame could be used multiple times by one unit. We need to + // detect this case to avoid adding it to `free_inline_reference_frames` more + // than once. We do that by setting `parent` to itself as a marker. + if (inline_frame.ptr(zcu).parent == inline_frame.toOptional()) break; + zcu.free_inline_reference_frames.append(gpa, inline_frame) catch { + // This space will be reused eventually, so we need not propagate this error. + // Just leak it for now, and let GC reclaim it later on. + break :unit_refs; + }; + opt_inline_frame = inline_frame.ptr(zcu).parent; + inline_frame.ptr(zcu).parent = inline_frame.toOptional(); // signal to code above + } } } @@ -3480,7 +3535,22 @@ pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void { } } -pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void { +pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index { + const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: { + _ = try zcu.inline_reference_frames.addOne(zcu.gpa); + break :idx @enumFromInt(zcu.inline_reference_frames.items.len - 1); + }; + frame_idx.ptr(zcu).* = frame; + return frame_idx; +} + +pub fn addUnitReference( + zcu: *Zcu, + src_unit: AnalUnit, + referenced_unit: AnalUnit, + ref_src: LazySrcLoc, + inline_frame: InlineReferenceFrame.Index.Optional, +) Allocator.Error!void { const gpa = zcu.gpa; zcu.clearCachedResolvedReferences(); @@ -3500,6 +3570,7 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit .referenced = referenced_unit, .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), .src = ref_src, + .inline_frame = inline_frame, }; gop.value_ptr.* = @intCast(ref_idx); @@ -3828,7 +3899,10 @@ pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionT pub const ResolvedReference = struct { referencer: AnalUnit, + /// If `inline_frame` is not `.none`, this is the *deepest* source location in the chain of + /// inline calls. For source locations further up the inline call stack, consult `inline_frame`. src: LazySrcLoc, + inline_frame: InlineReferenceFrame.Index.Optional, }; /// Returns a mapping from an `AnalUnit` to where it is referenced. @@ -4037,6 +4111,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv try unit_queue.put(gpa, ref.referenced, .{ .referencer = unit, .src = ref.src, + .inline_frame = ref.inline_frame, }); } ref_idx = ref.next; @@ -4055,6 +4130,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv try type_queue.put(gpa, ref.referenced, .{ .referencer = unit, .src = ref.src, + .inline_frame = .none, }); } ref_idx = ref.next; -- 2.54.0 From 429672705090f073adedb885057a4603eaf66c95 Mon Sep 17 00:00:00 2001 From: mlugg Date: Sat, 10 May 2025 18:22:43 +0100 Subject: [PATCH 3/5] Sema: improve "called from here" notes To an average user, it may be unclear why these notes are not just in the reference trace; that's because they are more important, because they are inline calls through which comptime values may propagate. There are now 3 possible wordings for this note: * "called at comptime here" * "called inline here" * "generic function instantiated here" An alternative could be these wordings: * "while analyzing comptime call here" * "while analyzing inline call here" * "while analyzing generic instantiation here" I'm not sure which is better -- but this commit is certainly better than status quo. --- src/Sema.zig | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index d267dcdb473ec9f0565c70b29d8c57a93bb4eaed..41453d2bba3c01c85fec9ada4589e35e1f035c3c 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -444,13 +444,19 @@ pub const Block = struct { pub const Inlining = struct { call_block: *Block, call_src: LazySrcLoc, - has_comptime_args: bool, func: InternPool.Index, - comptime_result: Air.Inst.Ref, - merges: Merges, + /// Populated lazily by `refFrame`. ref_frame: Zcu.InlineReferenceFrame.Index.Optional = .none, + /// If `true`, the following fields are `undefined`. This doesn't represent a true inline + /// call, but rather a generic call analyzing the instantiation's generic type bodies. + is_generic_instantiation: bool, + + has_comptime_args: bool, + comptime_result: Air.Inst.Ref, + merges: Merges, + fn refFrame(inlining: *Inlining, zcu: *Zcu) Allocator.Error!Zcu.InlineReferenceFrame.Index { if (inlining.ref_frame == .none) { inlining.ref_frame = (try zcu.addInlineReferenceFrame(.{ @@ -2604,12 +2610,12 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg if (block) |start_block| { var block_it = start_block; while (block_it.inlining) |inlining| { - try sema.errNote( - inlining.call_src, - err_msg, - "called from here", - .{}, - ); + const note_str = note: { + if (inlining.is_generic_instantiation) break :note "generic function instantiated here"; + if (inlining.call_block.isComptime()) break :note "called at comptime here"; + break :note "called inline here"; + }; + try sema.errNote(inlining.call_src, err_msg, "{s}", .{note_str}); block_it = inlining.call_block; } } @@ -7736,9 +7742,10 @@ fn analyzeCall( .call_block = block, .call_src = call_src, .func = func_val.?.toIntern(), - .has_comptime_args = false, // unused by error reporting - .comptime_result = .none, // unused by error reporting - .merges = undefined, // unused because we'll never `return` + .is_generic_instantiation = true, // this allows the following fields to be `undefined` + .has_comptime_args = undefined, + .comptime_result = undefined, + .merges = undefined, } else undefined; // This is the block in which we evaluate generic function components: that is, generic parameter @@ -8216,10 +8223,11 @@ fn analyzeCall( var inlining: Block.Inlining = .{ .call_block = block, .call_src = call_src, + .func = func_val.?.toIntern(), + .is_generic_instantiation = false, .has_comptime_args = for (args) |a| { if (try sema.isComptimeKnown(a)) break true; } else false, - .func = func_val.?.toIntern(), .comptime_result = undefined, .merges = .{ .block_inst = block_inst, @@ -8250,7 +8258,10 @@ fn analyzeCall( if (!inlining.has_comptime_args) { var block_it = block; while (block_it.inlining) |parent_inlining| { - if (!parent_inlining.has_comptime_args and parent_inlining.func == func_val.?.toIntern()) { + if (!parent_inlining.is_generic_instantiation and + !parent_inlining.has_comptime_args and + parent_inlining.func == func_val.?.toIntern()) + { return sema.fail(block, call_src, "inline call is recursive", .{}); } block_it = parent_inlining.call_block; @@ -19454,6 +19465,7 @@ fn analyzeRet( }; if (block.inlining) |inlining| { + assert(!inlining.is_generic_instantiation); // can't `return` in a generic param/ret ty expr if (block.isComptime()) { const ret_val = try sema.resolveConstValue(block, operand_src, operand, null); inlining.comptime_result = operand; -- 2.54.0 From 16481c8ef347f7fc5ffdc4636cf904b335a6dc09 Mon Sep 17 00:00:00 2001 From: mlugg Date: Fri, 16 May 2025 13:27:52 +0100 Subject: [PATCH 4/5] cases: update to new "called from here" notes --- .../add_overflow_in_function_evaluation.zig | 4 +--- .../compile_errors/closure_get_depends_on_failed_decl.zig | 4 +--- .../compile_errors/compile_time_division_by_zero.zig | 2 +- test/cases/compile_errors/comptime_try_non_error.zig | 4 +--- .../compile_errors/comptime_var_referenced_by_type.zig | 2 +- ...onstant_inside_comptime_function_has_compile_error.zig | 3 +-- ...or_in_comptime_call_in_container_level_initializer.zig | 4 +--- ...unction_instantiation_inherits_parent_branch_quota.zig | 4 ++-- ...tantiation_failure_in_generic_function_return_type.zig | 4 +--- .../compile_errors/missing_main_fn_in_executable.zig | 5 ++--- .../missing_struct_field_in_fn_called_at_comptime.zig | 4 +--- .../mul_overflow_in_function_evaluation.zig | 4 +--- .../negation_overflow_in_function_evaluation.zig | 4 +--- .../non-comptime-parameter-used-as-array-size.zig | 2 +- test/cases/compile_errors/private_main_fn.zig | 5 ++--- test/cases/compile_errors/recursive_inline_fn.zig | 8 ++++---- .../referring_to_a_struct_that_is_invalid.zig | 4 +--- ...rcion_error_in_generic_fn_called_from_non_fn_scope.zig | 4 +--- .../runtime_operation_in_comptime_scope.zig | 2 +- .../compile_errors/sema_src_used_after_inline_call.zig | 4 +--- .../compile_errors/stack_usage_in_naked_function.zig | 3 +-- .../compile_errors/store_to_comptime_var_through_call.zig | 2 +- .../sub_overflow_in_function_evaluation.zig | 4 +--- .../compile_errors/unreachable_executed_at_comptime.zig | 4 +--- 24 files changed, 30 insertions(+), 60 deletions(-) diff --git a/test/cases/compile_errors/add_overflow_in_function_evaluation.zig b/test/cases/compile_errors/add_overflow_in_function_evaluation.zig index ef1a016711619400e97018fbf70de15239ab350b..ccb9f531c9a9e9ed54ab4b5498c27deaf01966f0 100644 --- a/test/cases/compile_errors/add_overflow_in_function_evaluation.zig +++ b/test/cases/compile_errors/add_overflow_in_function_evaluation.zig @@ -8,8 +8,6 @@ export fn entry() usize { } // error -// backend=stage2 -// target=native // // :3:14: error: overflow of integer type 'u16' with value '65540' -// :1:14: note: called from here +// :1:14: note: called at comptime here diff --git a/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig b/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig index 43993eca3c0f4cccb82c503b8b88998bde0b2d1b..82abf039681ffaab68e4d26e088ed1d548e92f54 100644 --- a/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig +++ b/test/cases/compile_errors/closure_get_depends_on_failed_decl.zig @@ -18,9 +18,7 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :11:5: error: expected 0 argument(s), found 1 // :1:12: note: function declared here -// :17:19: note: called from here +// :17:19: note: called inline here diff --git a/test/cases/compile_errors/compile_time_division_by_zero.zig b/test/cases/compile_errors/compile_time_division_by_zero.zig index 6fabf55b3323b20db4cb53d93f742ed85e5466ec..e1f05e26b2a560481c19e913514a98df25b4cf90 100644 --- a/test/cases/compile_errors/compile_time_division_by_zero.zig +++ b/test/cases/compile_errors/compile_time_division_by_zero.zig @@ -10,4 +10,4 @@ export fn entry() usize { // error // // :3:16: error: division by zero here causes illegal behavior -// :1:14: note: called from here +// :1:14: note: called at comptime here diff --git a/test/cases/compile_errors/comptime_try_non_error.zig b/test/cases/compile_errors/comptime_try_non_error.zig index 935148414ccfd5e1d702066ac48a3f3a1e97170c..8d61df6e9ad451f3f541e9fbf9d509e44ba9abfb 100644 --- a/test/cases/compile_errors/comptime_try_non_error.zig +++ b/test/cases/compile_errors/comptime_try_non_error.zig @@ -11,8 +11,6 @@ pub fn bar() u8 { } // error -// backend=stage2 -// target=native // // :6:12: error: expected error union type, found 'u8' -// :2:8: note: called from here +// :2:8: note: called at comptime here diff --git a/test/cases/compile_errors/comptime_var_referenced_by_type.zig b/test/cases/compile_errors/comptime_var_referenced_by_type.zig index b9b0c756a91ae99930e3cf2f13abea4797b59e43..1f1ba8318c13e82cc8041ee393ca8bb2aed89e23 100644 --- a/test/cases/compile_errors/comptime_var_referenced_by_type.zig +++ b/test/cases/compile_errors/comptime_var_referenced_by_type.zig @@ -22,4 +22,4 @@ comptime { // // :7:16: error: captured value contains reference to comptime var // :16:30: note: 'wrapper.ptr' points to comptime var declared here -// :17:29: note: called from here +// :17:29: note: called at comptime here diff --git a/test/cases/compile_errors/constant_inside_comptime_function_has_compile_error.zig b/test/cases/compile_errors/constant_inside_comptime_function_has_compile_error.zig index 2afe5c4630f9eaf9fe9884f484c62a91c89071b3..ffc4486bc2ec2ba5fb11ae4b1cf246d725b4e537 100644 --- a/test/cases/compile_errors/constant_inside_comptime_function_has_compile_error.zig +++ b/test/cases/compile_errors/constant_inside_comptime_function_has_compile_error.zig @@ -15,9 +15,8 @@ export fn entry() void { } // error -// target=native // // :4:5: error: unreachable code // :4:25: note: control flow is diverted here // :4:25: error: aoeu -// :1:36: note: called from here +// :1:36: note: called at comptime here diff --git a/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig b/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig index 9b8b35ad605a4d748d519bfcbb86319dace9ea49..597dc5e66fd37f1808a727b3dbdbd7fb32b1de82 100644 --- a/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig +++ b/test/cases/compile_errors/error_in_comptime_call_in_container_level_initializer.zig @@ -15,8 +15,6 @@ pub export fn entry() void { } // error -// backend=stage2 -// target=native // // :9:48: error: caught unexpected error 'InvalidVersion' // :?:?: note: error returned here @@ -24,4 +22,4 @@ pub export fn entry() void { // :?:?: note: error returned here // :?:?: note: error returned here // :?:?: note: error returned here -// :12:37: note: called from here +// :12:37: note: called at comptime here diff --git a/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig b/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig index 4db27f0620e60766122563695dc41959d56e8e0f..89202fea0fa839fbea12afcd7a07aacc9503946c 100644 --- a/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig +++ b/test/cases/compile_errors/generic_function_instantiation_inherits_parent_branch_quota.zig @@ -25,5 +25,5 @@ fn Type(comptime n: usize) type { // // :21:16: error: evaluation exceeded 1001 backwards branches // :21:16: note: use @setEvalBranchQuota() to raise the branch limit from 1001 -// :16:34: note: called from here -// :8:15: note: called from here +// :16:34: note: called at comptime here +// :8:15: note: generic function instantiated here diff --git a/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig b/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig index 4316b6fc79224e14e8607ef332c0e477648e8921..96d8077085219e1353a7193e629f2b75a1629f2d 100644 --- a/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig +++ b/test/cases/compile_errors/generic_instantiation_failure_in_generic_function_return_type.zig @@ -36,8 +36,6 @@ pub fn is(comptime id: std.builtin.TypeId) TraitFn { } // error -// backend=stage2 -// target=native // // :8:48: error: expected type 'type', found 'bool' -// :5:21: note: called from here +// :5:21: note: generic function instantiated here diff --git a/test/cases/compile_errors/missing_main_fn_in_executable.zig b/test/cases/compile_errors/missing_main_fn_in_executable.zig index 75d5ef352fb38f342f30e42efb32b1f03f051cf4..56e87f7283cda752084a5f59b51c5b95893b02cc 100644 --- a/test/cases/compile_errors/missing_main_fn_in_executable.zig +++ b/test/cases/compile_errors/missing_main_fn_in_executable.zig @@ -1,9 +1,8 @@ // error -// backend=stage2 // target=x86_64-linux // output_mode=Exe // // : error: root source file struct 'tmp' has no member named 'main' // : note: struct declared here -// : note: called from here -// : note: called from here +// : note: called inline here +// : note: called inline here diff --git a/test/cases/compile_errors/missing_struct_field_in_fn_called_at_comptime.zig b/test/cases/compile_errors/missing_struct_field_in_fn_called_at_comptime.zig index aaded91209c24a6aeb534a402006031197558914..539c08afbe3d198371df3fc14fa9a956720148ed 100644 --- a/test/cases/compile_errors/missing_struct_field_in_fn_called_at_comptime.zig +++ b/test/cases/compile_errors/missing_struct_field_in_fn_called_at_comptime.zig @@ -10,9 +10,7 @@ comptime { } // error -// backend=stage2 -// target=native // // :5:17: error: missing struct field: b // :1:11: note: struct declared here -// :9:15: note: called from here +// :9:15: note: called at comptime here diff --git a/test/cases/compile_errors/mul_overflow_in_function_evaluation.zig b/test/cases/compile_errors/mul_overflow_in_function_evaluation.zig index c484df75408339592bfcb50f0bc722de5b065b3b..350f2e787035512e72ef853135b49ae2b4e52ee2 100644 --- a/test/cases/compile_errors/mul_overflow_in_function_evaluation.zig +++ b/test/cases/compile_errors/mul_overflow_in_function_evaluation.zig @@ -8,8 +8,6 @@ export fn entry() usize { } // error -// backend=stage2 -// target=native // // :3:14: error: overflow of integer type 'u16' with value '1800000' -// :1:14: note: called from here +// :1:14: note: called at comptime here diff --git a/test/cases/compile_errors/negation_overflow_in_function_evaluation.zig b/test/cases/compile_errors/negation_overflow_in_function_evaluation.zig index 208f761005197db7aff4fc241158108a64b08a74..3329dcd9dbf56ce8e2f9b6288a3a2006db31b412 100644 --- a/test/cases/compile_errors/negation_overflow_in_function_evaluation.zig +++ b/test/cases/compile_errors/negation_overflow_in_function_evaluation.zig @@ -8,8 +8,6 @@ export fn entry() usize { } // error -// backend=stage2 -// target=native // // :3:12: error: overflow of integer type 'i8' with value '128' -// :1:14: note: called from here +// :1:14: note: called at comptime here diff --git a/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig b/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig index 65b2886d076e0d552eb25063273d7d6d42ddce3d..ba9806deedb101dcbaf15353af7c97f051813435 100644 --- a/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig +++ b/test/cases/compile_errors/non-comptime-parameter-used-as-array-size.zig @@ -11,4 +11,4 @@ fn makeLlamas(count: usize) [count]u8 {} // // :8:30: error: unable to resolve comptime value // :8:30: note: array length must be comptime-known -// :2:31: note: called from here +// :2:31: note: generic function instantiated here diff --git a/test/cases/compile_errors/private_main_fn.zig b/test/cases/compile_errors/private_main_fn.zig index d02f41ae9ebf62dd87ba92eb34c0fd5fe91aeb65..0e85de9f0f43f69bd5fe897e49d3d40f63d8db88 100644 --- a/test/cases/compile_errors/private_main_fn.zig +++ b/test/cases/compile_errors/private_main_fn.zig @@ -1,11 +1,10 @@ fn main() void {} // error -// backend=stage2 // target=x86_64-linux // output_mode=Exe // // : error: 'main' is not marked 'pub' // :1:1: note: declared here -// : note: called from here -// : note: called from here +// : note: called inline here +// : note: called inline here diff --git a/test/cases/compile_errors/recursive_inline_fn.zig b/test/cases/compile_errors/recursive_inline_fn.zig index 7f96ad670962a02cd2429e1b6ac50e22aa9a3761..d7b2fb3dedebd4bab302671f5cd9666c44ba9dfc 100644 --- a/test/cases/compile_errors/recursive_inline_fn.zig +++ b/test/cases/compile_errors/recursive_inline_fn.zig @@ -31,8 +31,8 @@ pub export fn entry2() void { // error // // :5:27: error: inline call is recursive -// :12:12: note: called from here +// :12:12: note: called inline here // :24:10: error: inline call is recursive -// :20:10: note: called from here -// :16:11: note: called from here -// :28:10: note: called from here +// :20:10: note: called inline here +// :16:11: note: called inline here +// :28:10: note: called inline here diff --git a/test/cases/compile_errors/referring_to_a_struct_that_is_invalid.zig b/test/cases/compile_errors/referring_to_a_struct_that_is_invalid.zig index 946ead995429b13a2b838dc9d6326c967e706eab..4fd76792c47e2e98ac569a02d61d44886d9dc57e 100644 --- a/test/cases/compile_errors/referring_to_a_struct_that_is_invalid.zig +++ b/test/cases/compile_errors/referring_to_a_struct_that_is_invalid.zig @@ -11,8 +11,6 @@ fn assert(ok: bool) void { } // error -// backend=stage2 -// target=native // // :10:14: error: reached unreachable code -// :6:20: note: called from here +// :6:20: note: called at comptime here diff --git a/test/cases/compile_errors/ret_coercion_error_in_generic_fn_called_from_non_fn_scope.zig b/test/cases/compile_errors/ret_coercion_error_in_generic_fn_called_from_non_fn_scope.zig index ba17172b42b7dd72518cdd2e55b99b4b2f48bbd9..afb1e52310036c32f414b64c98bd8a94faa05a0b 100644 --- a/test/cases/compile_errors/ret_coercion_error_in_generic_fn_called_from_non_fn_scope.zig +++ b/test/cases/compile_errors/ret_coercion_error_in_generic_fn_called_from_non_fn_scope.zig @@ -6,9 +6,7 @@ comptime { } // error -// backend=stage2 -// target=native // // :2:12: error: expected type 'fn () void', found 'type' // :1:10: note: function return type declared here -// :5:12: note: called from here +// :5:12: note: called at comptime here diff --git a/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig index e3576c179b52364556efdea6cbd94eda6263f3c8..73220b0ba4e1de7273b2bb2c7b85ef232d225596 100644 --- a/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig +++ b/test/cases/compile_errors/runtime_operation_in_comptime_scope.zig @@ -30,7 +30,7 @@ var rt: u32 = undefined; // :10:12: note: call to function with comptime-only return type 'type' is evaluated at comptime // :13:10: note: return type declared here // :10:12: note: types are not available at runtime -// :2:8: note: called from here +// :2:8: note: called inline here // :19:8: error: unable to evaluate comptime expression // :19:5: note: operation is runtime due to this operand // :6:8: note: called at comptime from here diff --git a/test/cases/compile_errors/sema_src_used_after_inline_call.zig b/test/cases/compile_errors/sema_src_used_after_inline_call.zig index 4e3f31e41031a9f2af7644423808a2bee8d3f493..0678113322996ea85fc15fdfd7a6467a5d23f7f1 100644 --- a/test/cases/compile_errors/sema_src_used_after_inline_call.zig +++ b/test/cases/compile_errors/sema_src_used_after_inline_call.zig @@ -18,9 +18,7 @@ export fn entry() void { } // error -// backend=stage2 -// target=native // // :13:30: error: expected type 'u32', found 'i32' // :13:30: note: unsigned 32-bit int cannot represent all possible signed 32-bit values -// :17:33: note: called from here +// :17:33: note: called inline here diff --git a/test/cases/compile_errors/stack_usage_in_naked_function.zig b/test/cases/compile_errors/stack_usage_in_naked_function.zig index 2b6f7df9a131a0aef1319f7e738dbcdaad77ed18..aee0ea595283445ec33e34006fc188909108453e 100644 --- a/test/cases/compile_errors/stack_usage_in_naked_function.zig +++ b/test/cases/compile_errors/stack_usage_in_naked_function.zig @@ -36,10 +36,9 @@ export fn d() callconv(.naked) noreturn { } // error -// backend=stage2 // // :2:5: error: local variable in naked function // :10:5: error: local variable in naked function // :23:5: error: local variable in naked function // :30:13: error: local variable in naked function -// :35:12: note: called from here +// :35:12: note: called inline here diff --git a/test/cases/compile_errors/store_to_comptime_var_through_call.zig b/test/cases/compile_errors/store_to_comptime_var_through_call.zig index 0fb1246e31c36a88d4c9d9691ca78b8120418c87..5c812d5eacce17387eb65bfce935641d2b034e6f 100644 --- a/test/cases/compile_errors/store_to_comptime_var_through_call.zig +++ b/test/cases/compile_errors/store_to_comptime_var_through_call.zig @@ -12,4 +12,4 @@ fn incr(x: *comptime_int) void { // // :8:9: error: store to comptime variable depends on runtime condition // :3:9: note: runtime condition here -// :4:22: note: called from here +// :4:22: note: called at comptime here diff --git a/test/cases/compile_errors/sub_overflow_in_function_evaluation.zig b/test/cases/compile_errors/sub_overflow_in_function_evaluation.zig index 651ef34bdcd6feacae0508345192300ac3e1e74d..6949e874278aff57275af12d172959d5139d8606 100644 --- a/test/cases/compile_errors/sub_overflow_in_function_evaluation.zig +++ b/test/cases/compile_errors/sub_overflow_in_function_evaluation.zig @@ -8,8 +8,6 @@ export fn entry() usize { } // error -// backend=stage2 -// target=native // // :3:14: error: overflow of integer type 'u16' with value '-10' -// :1:14: note: called from here +// :1:14: note: called at comptime here diff --git a/test/cases/compile_errors/unreachable_executed_at_comptime.zig b/test/cases/compile_errors/unreachable_executed_at_comptime.zig index 5131a3362dbbe48f7a6f8e0117c1dc33fa797c58..6d2e53413685778a9fa61396cab5b6acdd2e9ad3 100644 --- a/test/cases/compile_errors/unreachable_executed_at_comptime.zig +++ b/test/cases/compile_errors/unreachable_executed_at_comptime.zig @@ -9,8 +9,6 @@ export fn entry() void { } // error -// backend=stage2 -// target=native // // :4:9: error: reached unreachable code -// :8:21: note: called from here +// :8:21: note: called at comptime here -- 2.54.0 From 46d7e808dcef3c9f9200d6cc1ed4e3a787ba054d Mon Sep 17 00:00:00 2001 From: mlugg Date: Fri, 16 May 2025 13:37:30 +0100 Subject: [PATCH 5/5] build runner: don't incorrectly omit reference traces It's incorrect to ever set `include_reference_trace` here, because the compiler has already given or not given reference traces depending on the `-freference-trace` option propagated to the compiler process by `std.Build.Step.Compile`. Perhaps in future we could make the compiler always return the reference trace when communicating over the compiler protocol; that'd be more versatile than the current behavior, because the build runner could, for instance, show a reference trace on-demand without having to even invoke the compiler. That seems really useful, since the reference trace is *often* unnecessary noise, but *sometimes* essential. However, we don't live in that world right now, so passing the option here doesn't make sense. Resolves: #23415 --- lib/compiler/build_runner.zig | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/compiler/build_runner.zig b/lib/compiler/build_runner.zig index 668c60361f51a7468deedcbb65d58dbbc74b4e34..e2b86836098cebee0c20f415a39ca0af443d88c0 100644 --- a/lib/compiler/build_runner.zig +++ b/lib/compiler/build_runner.zig @@ -750,7 +750,7 @@ fn runStepNames( if (run.prominent_compile_errors and total_compile_errors > 0) { for (step_stack.keys()) |s| { if (s.result_error_bundle.errorMessageCount() > 0) { - s.result_error_bundle.renderToStdErr(.{ .ttyconf = ttyconf, .include_reference_trace = (b.reference_trace orelse 0) > 0 }); + s.result_error_bundle.renderToStdErr(.{ .ttyconf = ttyconf }); } } @@ -1129,11 +1129,7 @@ fn workerMakeOneStep( defer std.debug.unlockStdErr(); const gpa = b.allocator; - const options: std.zig.ErrorBundle.RenderOptions = .{ - .ttyconf = run.ttyconf, - .include_reference_trace = (b.reference_trace orelse 0) > 0, - }; - printErrorMessages(gpa, s, options, run.stderr, run.prominent_compile_errors) catch {}; + printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {}; } handle_result: { -- 2.54.0