Commit f7143e18e3

Andrew Kelley <andrew@ziglang.org>
2024-02-27 04:35:26
move Zcu.LazySrcLoc to std.zig.LazySrcLoc
Part of an effort to ship more of the compiler in source form.
1 parent 4e2570b
lib/std/zig.zig
@@ -315,6 +315,379 @@ pub fn serializeCpuAlloc(ally: Allocator, cpu: std.Target.Cpu) Allocator.Error![
     return buffer.toOwnedSlice();
 }
 
+pub const DeclIndex = enum(u32) {
+    _,
+
+    pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
+        return @enumFromInt(@intFromEnum(i));
+    }
+};
+
+pub const OptionalDeclIndex = enum(u32) {
+    none = std.math.maxInt(u32),
+    _,
+
+    pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
+        return @enumFromInt(@intFromEnum(oi orelse return .none));
+    }
+
+    pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
+        if (oi == .none) return null;
+        return @enumFromInt(@intFromEnum(oi));
+    }
+};
+
+/// Resolving a source location into a byte offset may require doing work
+/// that we would rather not do unless the error actually occurs.
+/// Therefore we need a data structure that contains the information necessary
+/// to lazily produce a `SrcLoc` as required.
+/// Most of the offsets in this data structure are relative to the containing Decl.
+/// This makes the source location resolve properly even when a Decl gets
+/// shifted up or down in the file, as long as the Decl's contents itself
+/// do not change.
+pub const LazySrcLoc = union(enum) {
+    /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
+    /// that all code paths which would need to resolve the source location are
+    /// unreachable. If you are debugging this tag incorrectly being this value,
+    /// look into using reverse-continue with a memory watchpoint to see where the
+    /// value is being set to this tag.
+    unneeded,
+    /// Means the source location points to an entire file; not any particular
+    /// location within the file. `file_scope` union field will be active.
+    entire_file,
+    /// The source location points to a byte offset within a source file,
+    /// offset from 0. The source file is determined contextually.
+    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
+    byte_abs: u32,
+    /// The source location points to a token within a source file,
+    /// offset from 0. The source file is determined contextually.
+    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
+    token_abs: u32,
+    /// The source location points to an AST node within a source file,
+    /// offset from 0. The source file is determined contextually.
+    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
+    node_abs: u32,
+    /// The source location points to a byte offset within a source file,
+    /// offset from the byte offset of the Decl within the file.
+    /// The Decl is determined contextually.
+    byte_offset: u32,
+    /// This data is the offset into the token list from the Decl token.
+    /// The Decl is determined contextually.
+    token_offset: u32,
+    /// The source location points to an AST node, which is this value offset
+    /// from its containing Decl node AST index.
+    /// The Decl is determined contextually.
+    node_offset: TracedOffset,
+    /// The source location points to the main token of an AST node, found
+    /// by taking this AST node index offset from the containing Decl AST node.
+    /// The Decl is determined contextually.
+    node_offset_main_token: i32,
+    /// The source location points to the beginning of a struct initializer.
+    /// The Decl is determined contextually.
+    node_offset_initializer: i32,
+    /// The source location points to a variable declaration type expression,
+    /// found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a variable declaration AST node. Next, navigate
+    /// to the type expression.
+    /// The Decl is determined contextually.
+    node_offset_var_decl_ty: i32,
+    /// The source location points to the alignment expression of a var decl.
+    /// The Decl is determined contextually.
+    node_offset_var_decl_align: i32,
+    /// The source location points to the linksection expression of a var decl.
+    /// The Decl is determined contextually.
+    node_offset_var_decl_section: i32,
+    /// The source location points to the addrspace expression of a var decl.
+    /// The Decl is determined contextually.
+    node_offset_var_decl_addrspace: i32,
+    /// The source location points to the initializer of a var decl.
+    /// The Decl is determined contextually.
+    node_offset_var_decl_init: i32,
+    /// The source location points to the first parameter of a builtin
+    /// function call, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a builtin call AST node. Next, navigate
+    /// to the first parameter.
+    /// The Decl is determined contextually.
+    node_offset_builtin_call_arg0: i32,
+    /// Same as `node_offset_builtin_call_arg0` except arg index 1.
+    node_offset_builtin_call_arg1: i32,
+    node_offset_builtin_call_arg2: i32,
+    node_offset_builtin_call_arg3: i32,
+    node_offset_builtin_call_arg4: i32,
+    node_offset_builtin_call_arg5: i32,
+    /// Like `node_offset_builtin_call_arg0` but recurses through arbitrarily many calls
+    /// to pointer cast builtins.
+    node_offset_ptrcast_operand: i32,
+    /// The source location points to the index expression of an array access
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to an array access AST node. Next, navigate
+    /// to the index expression.
+    /// The Decl is determined contextually.
+    node_offset_array_access_index: i32,
+    /// The source location points to the LHS of a slice expression
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a slice AST node. Next, navigate
+    /// to the sentinel expression.
+    /// The Decl is determined contextually.
+    node_offset_slice_ptr: i32,
+    /// The source location points to start expression of a slice expression
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a slice AST node. Next, navigate
+    /// to the sentinel expression.
+    /// The Decl is determined contextually.
+    node_offset_slice_start: i32,
+    /// The source location points to the end expression of a slice
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a slice AST node. Next, navigate
+    /// to the sentinel expression.
+    /// The Decl is determined contextually.
+    node_offset_slice_end: i32,
+    /// The source location points to the sentinel expression of a slice
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a slice AST node. Next, navigate
+    /// to the sentinel expression.
+    /// The Decl is determined contextually.
+    node_offset_slice_sentinel: i32,
+    /// The source location points to the callee expression of a function
+    /// call expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function call AST node. Next, navigate
+    /// to the callee expression.
+    /// The Decl is determined contextually.
+    node_offset_call_func: i32,
+    /// The payload is offset from the containing Decl AST node.
+    /// The source location points to the field name of:
+    ///  * a field access expression (`a.b`), or
+    ///  * the callee of a method call (`a.b()`)
+    /// The Decl is determined contextually.
+    node_offset_field_name: i32,
+    /// The payload is offset from the containing Decl AST node.
+    /// The source location points to the field name of the operand ("b" node)
+    /// of a field initialization expression (`.a = b`)
+    /// The Decl is determined contextually.
+    node_offset_field_name_init: i32,
+    /// The source location points to the pointer of a pointer deref expression,
+    /// found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a pointer deref AST node. Next, navigate
+    /// to the pointer expression.
+    /// The Decl is determined contextually.
+    node_offset_deref_ptr: i32,
+    /// The source location points to the assembly source code of an inline assembly
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to inline assembly AST node. Next, navigate
+    /// to the asm template source code.
+    /// The Decl is determined contextually.
+    node_offset_asm_source: i32,
+    /// The source location points to the return type of an inline assembly
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to inline assembly AST node. Next, navigate
+    /// to the return type expression.
+    /// The Decl is determined contextually.
+    node_offset_asm_ret_ty: i32,
+    /// The source location points to the condition expression of an if
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to an if expression AST node. Next, navigate
+    /// to the condition expression.
+    /// The Decl is determined contextually.
+    node_offset_if_cond: i32,
+    /// The source location points to a binary expression, such as `a + b`, found
+    /// by taking this AST node index offset from the containing Decl AST node.
+    /// The Decl is determined contextually.
+    node_offset_bin_op: i32,
+    /// The source location points to the LHS of a binary expression, found
+    /// by taking this AST node index offset from the containing Decl AST node,
+    /// which points to a binary expression AST node. Next, navigate to the LHS.
+    /// The Decl is determined contextually.
+    node_offset_bin_lhs: i32,
+    /// The source location points to the RHS of a binary expression, found
+    /// by taking this AST node index offset from the containing Decl AST node,
+    /// which points to a binary expression AST node. Next, navigate to the RHS.
+    /// The Decl is determined contextually.
+    node_offset_bin_rhs: i32,
+    /// The source location points to the operand of a switch expression, found
+    /// by taking this AST node index offset from the containing Decl AST node,
+    /// which points to a switch expression AST node. Next, navigate to the operand.
+    /// The Decl is determined contextually.
+    node_offset_switch_operand: i32,
+    /// The source location points to the else/`_` prong of a switch expression, found
+    /// by taking this AST node index offset from the containing Decl AST node,
+    /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
+    /// The Decl is determined contextually.
+    node_offset_switch_special_prong: i32,
+    /// The source location points to all the ranges of a switch expression, found
+    /// by taking this AST node index offset from the containing Decl AST node,
+    /// which points to a switch expression AST node. Next, navigate to any of the
+    /// range nodes. The error applies to all of them.
+    /// The Decl is determined contextually.
+    node_offset_switch_range: i32,
+    /// The source location points to the capture of a switch_prong.
+    /// The Decl is determined contextually.
+    node_offset_switch_prong_capture: i32,
+    /// The source location points to the tag capture of a switch_prong.
+    /// The Decl is determined contextually.
+    node_offset_switch_prong_tag_capture: i32,
+    /// The source location points to the align expr of a function type
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function type AST node. Next, navigate to
+    /// the calling convention node.
+    /// The Decl is determined contextually.
+    node_offset_fn_type_align: i32,
+    /// The source location points to the addrspace expr of a function type
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function type AST node. Next, navigate to
+    /// the calling convention node.
+    /// The Decl is determined contextually.
+    node_offset_fn_type_addrspace: i32,
+    /// The source location points to the linksection expr of a function type
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function type AST node. Next, navigate to
+    /// the calling convention node.
+    /// The Decl is determined contextually.
+    node_offset_fn_type_section: i32,
+    /// The source location points to the calling convention of a function type
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function type AST node. Next, navigate to
+    /// the calling convention node.
+    /// The Decl is determined contextually.
+    node_offset_fn_type_cc: i32,
+    /// The source location points to the return type of a function type
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function type AST node. Next, navigate to
+    /// the return type node.
+    /// The Decl is determined contextually.
+    node_offset_fn_type_ret_ty: i32,
+    node_offset_param: i32,
+    token_offset_param: i32,
+    /// The source location points to the type expression of an `anyframe->T`
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
+    /// to the type expression.
+    /// The Decl is determined contextually.
+    node_offset_anyframe_type: i32,
+    /// The source location points to the string literal of `extern "foo"`, found
+    /// by taking this AST node index offset from the containing
+    /// Decl AST node, which points to a function prototype or variable declaration
+    /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
+    /// The Decl is determined contextually.
+    node_offset_lib_name: i32,
+    /// The source location points to the len expression of an `[N:S]T`
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
+    /// to the len expression.
+    /// The Decl is determined contextually.
+    node_offset_array_type_len: i32,
+    /// The source location points to the sentinel expression of an `[N:S]T`
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
+    /// to the sentinel expression.
+    /// The Decl is determined contextually.
+    node_offset_array_type_sentinel: i32,
+    /// The source location points to the elem expression of an `[N:S]T`
+    /// expression, found by taking this AST node index offset from the containing
+    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
+    /// to the elem expression.
+    /// The Decl is determined contextually.
+    node_offset_array_type_elem: i32,
+    /// The source location points to the operand of an unary expression.
+    /// The Decl is determined contextually.
+    node_offset_un_op: i32,
+    /// The source location points to the elem type of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_elem: i32,
+    /// The source location points to the sentinel of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_sentinel: i32,
+    /// The source location points to the align expr of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_align: i32,
+    /// The source location points to the addrspace expr of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_addrspace: i32,
+    /// The source location points to the bit-offset of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_bitoffset: i32,
+    /// The source location points to the host size of a pointer.
+    /// The Decl is determined contextually.
+    node_offset_ptr_hostsize: i32,
+    /// The source location points to the tag type of an union or an enum.
+    /// The Decl is determined contextually.
+    node_offset_container_tag: i32,
+    /// The source location points to the default value of a field.
+    /// The Decl is determined contextually.
+    node_offset_field_default: i32,
+    /// The source location points to the type of an array or struct initializer.
+    /// The Decl is determined contextually.
+    node_offset_init_ty: i32,
+    /// The source location points to the LHS of an assignment.
+    /// The Decl is determined contextually.
+    node_offset_store_ptr: i32,
+    /// The source location points to the RHS of an assignment.
+    /// The Decl is determined contextually.
+    node_offset_store_operand: i32,
+    /// The source location points to the operand of a `return` statement, or
+    /// the `return` itself if there is no explicit operand.
+    /// The Decl is determined contextually.
+    node_offset_return_operand: i32,
+    /// The source location points to a for loop input.
+    /// The Decl is determined contextually.
+    for_input: struct {
+        /// Points to the for loop AST node.
+        for_node_offset: i32,
+        /// Picks one of the inputs from the condition.
+        input_index: u32,
+    },
+    /// The source location points to one of the captures of a for loop, found
+    /// by taking this AST node index offset from the containing
+    /// Decl AST node, which points to one of the input nodes of a for loop.
+    /// Next, navigate to the corresponding capture.
+    /// The Decl is determined contextually.
+    for_capture_from_input: i32,
+    /// The source location points to the argument node of a function call.
+    call_arg: struct {
+        decl: DeclIndex,
+        /// Points to the function call AST node.
+        call_node_offset: i32,
+        /// The index of the argument the source location points to.
+        arg_index: u32,
+    },
+    fn_proto_param: struct {
+        decl: DeclIndex,
+        /// Points to the function prototype AST node.
+        fn_proto_node_offset: i32,
+        /// The index of the parameter the source location points to.
+        param_index: u32,
+    },
+    array_cat_lhs: ArrayCat,
+    array_cat_rhs: ArrayCat,
+
+    const ArrayCat = struct {
+        /// Points to the array concat AST node.
+        array_cat_offset: i32,
+        /// The index of the element the source location points to.
+        elem_index: u32,
+    };
+
+    pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
+
+    noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
+        var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
+        result.node_offset.trace.addAddr(@returnAddress(), "init");
+        return result;
+    }
+
+    fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
+        return .{ .node_offset = .{ .x = node_offset } };
+    }
+
+    /// This wraps a simple integer in debug builds so that later on we can find out
+    /// where in semantic analysis the value got set.
+    pub const TracedOffset = struct {
+        x: i32,
+        trace: std.debug.Trace = .{},
+
+        const want_tracing = false;
+    };
+};
+
 const std = @import("std.zig");
 const tokenizer = @import("zig/tokenizer.zig");
 const assert = std.debug.assert;
src/arch/wasm/CodeGen.zig
@@ -16,7 +16,7 @@ const Decl = Module.Decl;
 const Type = @import("../../type.zig").Type;
 const Value = @import("../../Value.zig");
 const Compilation = @import("../../Compilation.zig");
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 const link = @import("../../link.zig");
 const TypedValue = @import("../../TypedValue.zig");
 const Air = @import("../../Air.zig");
@@ -767,8 +767,7 @@ pub fn deinit(func: *CodeGen) void {
 /// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
 fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
     const mod = func.bin_file.base.comp.module.?;
-    const src = LazySrcLoc.nodeOffset(0);
-    const src_loc = src.toSrcLoc(func.decl, mod);
+    const src_loc = func.decl.srcLoc(mod);
     func.err_msg = try Module.ErrorMsg.create(func.gpa, src_loc, fmt, args);
     return error.CodegenFail;
 }
src/codegen/c.zig
@@ -13,7 +13,7 @@ const TypedValue = @import("../TypedValue.zig");
 const C = link.File.C;
 const Decl = Module.Decl;
 const trace = @import("../tracy.zig").trace;
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
 const InternPool = @import("../InternPool.zig");
@@ -570,8 +570,7 @@ pub const DeclGen = struct {
         const mod = dg.module;
         const decl_index = dg.pass.decl;
         const decl = mod.declPtr(decl_index);
-        const src = LazySrcLoc.nodeOffset(0);
-        const src_loc = src.toSrcLoc(decl, mod);
+        const src_loc = decl.srcLoc(mod);
         dg.error_msg = try Module.ErrorMsg.create(dg.gpa, src_loc, format, args);
         return error.AnalysisFail;
     }
src/codegen/llvm.zig
@@ -23,7 +23,7 @@ const Air = @import("../Air.zig");
 const Liveness = @import("../Liveness.zig");
 const Value = @import("../Value.zig");
 const Type = @import("../type.zig").Type;
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 const x86_64_abi = @import("../arch/x86_64/abi.zig");
 const wasm_c_abi = @import("../arch/wasm/abi.zig");
 const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
@@ -4686,7 +4686,7 @@ pub const DeclGen = struct {
         const o = dg.object;
         const gpa = o.gpa;
         const mod = o.module;
-        const src_loc = LazySrcLoc.nodeOffset(0).toSrcLoc(dg.decl, mod);
+        const src_loc = dg.decl.srcLoc(mod);
         dg.err_msg = try Module.ErrorMsg.create(gpa, src_loc, "TODO (LLVM): " ++ format, args);
         return error.CodegenFail;
     }
src/codegen/spirv.zig
@@ -8,7 +8,7 @@ const Module = @import("../Module.zig");
 const Decl = Module.Decl;
 const Type = @import("../type.zig").Type;
 const Value = @import("../Value.zig");
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 const Air = @import("../Air.zig");
 const Zir = @import("../Zir.zig");
 const Liveness = @import("../Liveness.zig");
@@ -413,8 +413,7 @@ const DeclGen = struct {
     pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
         @setCold(true);
         const mod = self.module;
-        const src = LazySrcLoc.nodeOffset(0);
-        const src_loc = src.toSrcLoc(self.module.declPtr(self.decl_index), mod);
+        const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
         assert(self.error_msg == null);
         self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
         return error.CodegenFail;
@@ -5270,8 +5269,7 @@ const DeclGen = struct {
                 // TODO: Translate proper error locations.
                 assert(as.errors.items.len != 0);
                 assert(self.error_msg == null);
-                const loc = LazySrcLoc.nodeOffset(0);
-                const src_loc = loc.toSrcLoc(self.module.declPtr(self.decl_index), mod);
+                const src_loc = self.module.declPtr(self.decl_index).srcLoc(mod);
                 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
                 const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
 
src/InternPool.zig
@@ -383,27 +383,8 @@ pub const RuntimeIndex = enum(u32) {
     }
 };
 
-pub const DeclIndex = enum(u32) {
-    _,
-
-    pub fn toOptional(i: DeclIndex) OptionalDeclIndex {
-        return @enumFromInt(@intFromEnum(i));
-    }
-};
-
-pub const OptionalDeclIndex = enum(u32) {
-    none = std.math.maxInt(u32),
-    _,
-
-    pub fn init(oi: ?DeclIndex) OptionalDeclIndex {
-        return @enumFromInt(@intFromEnum(oi orelse return .none));
-    }
-
-    pub fn unwrap(oi: OptionalDeclIndex) ?DeclIndex {
-        if (oi == .none) return null;
-        return @enumFromInt(@intFromEnum(oi));
-    }
-};
+pub const DeclIndex = std.zig.DeclIndex;
+pub const OptionalDeclIndex = std.zig.OptionalDeclIndex;
 
 pub const NamespaceIndex = enum(u32) {
     _,
src/Module.zig
@@ -13,6 +13,7 @@ const BigIntConst = std.math.big.int.Const;
 const BigIntMutable = std.math.big.int.Mutable;
 const Target = std.Target;
 const Ast = std.zig.Ast;
+const LazySrcLoc = std.zig.LazySrcLoc;
 
 /// Deprecated, use `Zcu`.
 const Module = Zcu;
@@ -664,6 +665,101 @@ pub const Decl = struct {
         if (decl.alignment != .none) return decl.alignment;
         return decl.ty.abiAlignment(zcu);
     }
+
+    /// Upgrade a `LazySrcLoc` to a `SrcLoc` based on the `Decl` provided.
+    pub fn toSrcLoc(decl: *Decl, lazy: LazySrcLoc, mod: *Module) SrcLoc {
+        return switch (lazy) {
+            .unneeded,
+            .entire_file,
+            .byte_abs,
+            .token_abs,
+            .node_abs,
+            => .{
+                .file_scope = decl.getFileScope(mod),
+                .parent_decl_node = 0,
+                .lazy = lazy,
+            },
+
+            .byte_offset,
+            .token_offset,
+            .node_offset,
+            .node_offset_main_token,
+            .node_offset_initializer,
+            .node_offset_var_decl_ty,
+            .node_offset_var_decl_align,
+            .node_offset_var_decl_section,
+            .node_offset_var_decl_addrspace,
+            .node_offset_var_decl_init,
+            .node_offset_builtin_call_arg0,
+            .node_offset_builtin_call_arg1,
+            .node_offset_builtin_call_arg2,
+            .node_offset_builtin_call_arg3,
+            .node_offset_builtin_call_arg4,
+            .node_offset_builtin_call_arg5,
+            .node_offset_ptrcast_operand,
+            .node_offset_array_access_index,
+            .node_offset_slice_ptr,
+            .node_offset_slice_start,
+            .node_offset_slice_end,
+            .node_offset_slice_sentinel,
+            .node_offset_call_func,
+            .node_offset_field_name,
+            .node_offset_field_name_init,
+            .node_offset_deref_ptr,
+            .node_offset_asm_source,
+            .node_offset_asm_ret_ty,
+            .node_offset_if_cond,
+            .node_offset_bin_op,
+            .node_offset_bin_lhs,
+            .node_offset_bin_rhs,
+            .node_offset_switch_operand,
+            .node_offset_switch_special_prong,
+            .node_offset_switch_range,
+            .node_offset_switch_prong_capture,
+            .node_offset_switch_prong_tag_capture,
+            .node_offset_fn_type_align,
+            .node_offset_fn_type_addrspace,
+            .node_offset_fn_type_section,
+            .node_offset_fn_type_cc,
+            .node_offset_fn_type_ret_ty,
+            .node_offset_param,
+            .token_offset_param,
+            .node_offset_anyframe_type,
+            .node_offset_lib_name,
+            .node_offset_array_type_len,
+            .node_offset_array_type_sentinel,
+            .node_offset_array_type_elem,
+            .node_offset_un_op,
+            .node_offset_ptr_elem,
+            .node_offset_ptr_sentinel,
+            .node_offset_ptr_align,
+            .node_offset_ptr_addrspace,
+            .node_offset_ptr_bitoffset,
+            .node_offset_ptr_hostsize,
+            .node_offset_container_tag,
+            .node_offset_field_default,
+            .node_offset_init_ty,
+            .node_offset_store_ptr,
+            .node_offset_store_operand,
+            .node_offset_return_operand,
+            .for_input,
+            .for_capture_from_input,
+            .array_cat_lhs,
+            .array_cat_rhs,
+            => .{
+                .file_scope = decl.getFileScope(mod),
+                .parent_decl_node = decl.src_node,
+                .lazy = lazy,
+            },
+            inline .call_arg,
+            .fn_proto_param,
+            => |x| .{
+                .file_scope = decl.getFileScope(mod),
+                .parent_decl_node = mod.declPtr(x.decl).src_node,
+                .lazy = lazy,
+            },
+        };
+    }
 };
 
 /// This state is attached to every Decl when Module emit_h is non-null.
@@ -1951,452 +2047,6 @@ pub const SrcLoc = struct {
     }
 };
 
-/// This wraps a simple integer in debug builds so that later on we can find out
-/// where in semantic analysis the value got set.
-const TracedOffset = struct {
-    x: i32,
-    trace: std.debug.Trace = .{},
-
-    const want_tracing = build_options.value_tracing;
-};
-
-/// Resolving a source location into a byte offset may require doing work
-/// that we would rather not do unless the error actually occurs.
-/// Therefore we need a data structure that contains the information necessary
-/// to lazily produce a `SrcLoc` as required.
-/// Most of the offsets in this data structure are relative to the containing Decl.
-/// This makes the source location resolve properly even when a Decl gets
-/// shifted up or down in the file, as long as the Decl's contents itself
-/// do not change.
-pub const LazySrcLoc = union(enum) {
-    /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
-    /// that all code paths which would need to resolve the source location are
-    /// unreachable. If you are debugging this tag incorrectly being this value,
-    /// look into using reverse-continue with a memory watchpoint to see where the
-    /// value is being set to this tag.
-    unneeded,
-    /// Means the source location points to an entire file; not any particular
-    /// location within the file. `file_scope` union field will be active.
-    entire_file,
-    /// The source location points to a byte offset within a source file,
-    /// offset from 0. The source file is determined contextually.
-    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
-    byte_abs: u32,
-    /// The source location points to a token within a source file,
-    /// offset from 0. The source file is determined contextually.
-    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
-    token_abs: u32,
-    /// The source location points to an AST node within a source file,
-    /// offset from 0. The source file is determined contextually.
-    /// Inside a `SrcLoc`, the `file_scope` union field will be active.
-    node_abs: u32,
-    /// The source location points to a byte offset within a source file,
-    /// offset from the byte offset of the Decl within the file.
-    /// The Decl is determined contextually.
-    byte_offset: u32,
-    /// This data is the offset into the token list from the Decl token.
-    /// The Decl is determined contextually.
-    token_offset: u32,
-    /// The source location points to an AST node, which is this value offset
-    /// from its containing Decl node AST index.
-    /// The Decl is determined contextually.
-    node_offset: TracedOffset,
-    /// The source location points to the main token of an AST node, found
-    /// by taking this AST node index offset from the containing Decl AST node.
-    /// The Decl is determined contextually.
-    node_offset_main_token: i32,
-    /// The source location points to the beginning of a struct initializer.
-    /// The Decl is determined contextually.
-    node_offset_initializer: i32,
-    /// The source location points to a variable declaration type expression,
-    /// found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a variable declaration AST node. Next, navigate
-    /// to the type expression.
-    /// The Decl is determined contextually.
-    node_offset_var_decl_ty: i32,
-    /// The source location points to the alignment expression of a var decl.
-    /// The Decl is determined contextually.
-    node_offset_var_decl_align: i32,
-    /// The source location points to the linksection expression of a var decl.
-    /// The Decl is determined contextually.
-    node_offset_var_decl_section: i32,
-    /// The source location points to the addrspace expression of a var decl.
-    /// The Decl is determined contextually.
-    node_offset_var_decl_addrspace: i32,
-    /// The source location points to the initializer of a var decl.
-    /// The Decl is determined contextually.
-    node_offset_var_decl_init: i32,
-    /// The source location points to the first parameter of a builtin
-    /// function call, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a builtin call AST node. Next, navigate
-    /// to the first parameter.
-    /// The Decl is determined contextually.
-    node_offset_builtin_call_arg0: i32,
-    /// Same as `node_offset_builtin_call_arg0` except arg index 1.
-    node_offset_builtin_call_arg1: i32,
-    node_offset_builtin_call_arg2: i32,
-    node_offset_builtin_call_arg3: i32,
-    node_offset_builtin_call_arg4: i32,
-    node_offset_builtin_call_arg5: i32,
-    /// Like `node_offset_builtin_call_arg0` but recurses through arbitrarily many calls
-    /// to pointer cast builtins.
-    node_offset_ptrcast_operand: i32,
-    /// The source location points to the index expression of an array access
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to an array access AST node. Next, navigate
-    /// to the index expression.
-    /// The Decl is determined contextually.
-    node_offset_array_access_index: i32,
-    /// The source location points to the LHS of a slice expression
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a slice AST node. Next, navigate
-    /// to the sentinel expression.
-    /// The Decl is determined contextually.
-    node_offset_slice_ptr: i32,
-    /// The source location points to start expression of a slice expression
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a slice AST node. Next, navigate
-    /// to the sentinel expression.
-    /// The Decl is determined contextually.
-    node_offset_slice_start: i32,
-    /// The source location points to the end expression of a slice
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a slice AST node. Next, navigate
-    /// to the sentinel expression.
-    /// The Decl is determined contextually.
-    node_offset_slice_end: i32,
-    /// The source location points to the sentinel expression of a slice
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a slice AST node. Next, navigate
-    /// to the sentinel expression.
-    /// The Decl is determined contextually.
-    node_offset_slice_sentinel: i32,
-    /// The source location points to the callee expression of a function
-    /// call expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function call AST node. Next, navigate
-    /// to the callee expression.
-    /// The Decl is determined contextually.
-    node_offset_call_func: i32,
-    /// The payload is offset from the containing Decl AST node.
-    /// The source location points to the field name of:
-    ///  * a field access expression (`a.b`), or
-    ///  * the callee of a method call (`a.b()`)
-    /// The Decl is determined contextually.
-    node_offset_field_name: i32,
-    /// The payload is offset from the containing Decl AST node.
-    /// The source location points to the field name of the operand ("b" node)
-    /// of a field initialization expression (`.a = b`)
-    /// The Decl is determined contextually.
-    node_offset_field_name_init: i32,
-    /// The source location points to the pointer of a pointer deref expression,
-    /// found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a pointer deref AST node. Next, navigate
-    /// to the pointer expression.
-    /// The Decl is determined contextually.
-    node_offset_deref_ptr: i32,
-    /// The source location points to the assembly source code of an inline assembly
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to inline assembly AST node. Next, navigate
-    /// to the asm template source code.
-    /// The Decl is determined contextually.
-    node_offset_asm_source: i32,
-    /// The source location points to the return type of an inline assembly
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to inline assembly AST node. Next, navigate
-    /// to the return type expression.
-    /// The Decl is determined contextually.
-    node_offset_asm_ret_ty: i32,
-    /// The source location points to the condition expression of an if
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to an if expression AST node. Next, navigate
-    /// to the condition expression.
-    /// The Decl is determined contextually.
-    node_offset_if_cond: i32,
-    /// The source location points to a binary expression, such as `a + b`, found
-    /// by taking this AST node index offset from the containing Decl AST node.
-    /// The Decl is determined contextually.
-    node_offset_bin_op: i32,
-    /// The source location points to the LHS of a binary expression, found
-    /// by taking this AST node index offset from the containing Decl AST node,
-    /// which points to a binary expression AST node. Next, navigate to the LHS.
-    /// The Decl is determined contextually.
-    node_offset_bin_lhs: i32,
-    /// The source location points to the RHS of a binary expression, found
-    /// by taking this AST node index offset from the containing Decl AST node,
-    /// which points to a binary expression AST node. Next, navigate to the RHS.
-    /// The Decl is determined contextually.
-    node_offset_bin_rhs: i32,
-    /// The source location points to the operand of a switch expression, found
-    /// by taking this AST node index offset from the containing Decl AST node,
-    /// which points to a switch expression AST node. Next, navigate to the operand.
-    /// The Decl is determined contextually.
-    node_offset_switch_operand: i32,
-    /// The source location points to the else/`_` prong of a switch expression, found
-    /// by taking this AST node index offset from the containing Decl AST node,
-    /// which points to a switch expression AST node. Next, navigate to the else/`_` prong.
-    /// The Decl is determined contextually.
-    node_offset_switch_special_prong: i32,
-    /// The source location points to all the ranges of a switch expression, found
-    /// by taking this AST node index offset from the containing Decl AST node,
-    /// which points to a switch expression AST node. Next, navigate to any of the
-    /// range nodes. The error applies to all of them.
-    /// The Decl is determined contextually.
-    node_offset_switch_range: i32,
-    /// The source location points to the capture of a switch_prong.
-    /// The Decl is determined contextually.
-    node_offset_switch_prong_capture: i32,
-    /// The source location points to the tag capture of a switch_prong.
-    /// The Decl is determined contextually.
-    node_offset_switch_prong_tag_capture: i32,
-    /// The source location points to the align expr of a function type
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function type AST node. Next, navigate to
-    /// the calling convention node.
-    /// The Decl is determined contextually.
-    node_offset_fn_type_align: i32,
-    /// The source location points to the addrspace expr of a function type
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function type AST node. Next, navigate to
-    /// the calling convention node.
-    /// The Decl is determined contextually.
-    node_offset_fn_type_addrspace: i32,
-    /// The source location points to the linksection expr of a function type
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function type AST node. Next, navigate to
-    /// the calling convention node.
-    /// The Decl is determined contextually.
-    node_offset_fn_type_section: i32,
-    /// The source location points to the calling convention of a function type
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function type AST node. Next, navigate to
-    /// the calling convention node.
-    /// The Decl is determined contextually.
-    node_offset_fn_type_cc: i32,
-    /// The source location points to the return type of a function type
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function type AST node. Next, navigate to
-    /// the return type node.
-    /// The Decl is determined contextually.
-    node_offset_fn_type_ret_ty: i32,
-    node_offset_param: i32,
-    token_offset_param: i32,
-    /// The source location points to the type expression of an `anyframe->T`
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a `anyframe->T` expression AST node. Next, navigate
-    /// to the type expression.
-    /// The Decl is determined contextually.
-    node_offset_anyframe_type: i32,
-    /// The source location points to the string literal of `extern "foo"`, found
-    /// by taking this AST node index offset from the containing
-    /// Decl AST node, which points to a function prototype or variable declaration
-    /// expression AST node. Next, navigate to the string literal of the `extern "foo"`.
-    /// The Decl is determined contextually.
-    node_offset_lib_name: i32,
-    /// The source location points to the len expression of an `[N:S]T`
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
-    /// to the len expression.
-    /// The Decl is determined contextually.
-    node_offset_array_type_len: i32,
-    /// The source location points to the sentinel expression of an `[N:S]T`
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
-    /// to the sentinel expression.
-    /// The Decl is determined contextually.
-    node_offset_array_type_sentinel: i32,
-    /// The source location points to the elem expression of an `[N:S]T`
-    /// expression, found by taking this AST node index offset from the containing
-    /// Decl AST node, which points to an `[N:S]T` expression AST node. Next, navigate
-    /// to the elem expression.
-    /// The Decl is determined contextually.
-    node_offset_array_type_elem: i32,
-    /// The source location points to the operand of an unary expression.
-    /// The Decl is determined contextually.
-    node_offset_un_op: i32,
-    /// The source location points to the elem type of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_elem: i32,
-    /// The source location points to the sentinel of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_sentinel: i32,
-    /// The source location points to the align expr of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_align: i32,
-    /// The source location points to the addrspace expr of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_addrspace: i32,
-    /// The source location points to the bit-offset of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_bitoffset: i32,
-    /// The source location points to the host size of a pointer.
-    /// The Decl is determined contextually.
-    node_offset_ptr_hostsize: i32,
-    /// The source location points to the tag type of an union or an enum.
-    /// The Decl is determined contextually.
-    node_offset_container_tag: i32,
-    /// The source location points to the default value of a field.
-    /// The Decl is determined contextually.
-    node_offset_field_default: i32,
-    /// The source location points to the type of an array or struct initializer.
-    /// The Decl is determined contextually.
-    node_offset_init_ty: i32,
-    /// The source location points to the LHS of an assignment.
-    /// The Decl is determined contextually.
-    node_offset_store_ptr: i32,
-    /// The source location points to the RHS of an assignment.
-    /// The Decl is determined contextually.
-    node_offset_store_operand: i32,
-    /// The source location points to the operand of a `return` statement, or
-    /// the `return` itself if there is no explicit operand.
-    /// The Decl is determined contextually.
-    node_offset_return_operand: i32,
-    /// The source location points to a for loop input.
-    /// The Decl is determined contextually.
-    for_input: struct {
-        /// Points to the for loop AST node.
-        for_node_offset: i32,
-        /// Picks one of the inputs from the condition.
-        input_index: u32,
-    },
-    /// The source location points to one of the captures of a for loop, found
-    /// by taking this AST node index offset from the containing
-    /// Decl AST node, which points to one of the input nodes of a for loop.
-    /// Next, navigate to the corresponding capture.
-    /// The Decl is determined contextually.
-    for_capture_from_input: i32,
-    /// The source location points to the argument node of a function call.
-    call_arg: struct {
-        decl: Decl.Index,
-        /// Points to the function call AST node.
-        call_node_offset: i32,
-        /// The index of the argument the source location points to.
-        arg_index: u32,
-    },
-    fn_proto_param: struct {
-        decl: Decl.Index,
-        /// Points to the function prototype AST node.
-        fn_proto_node_offset: i32,
-        /// The index of the parameter the source location points to.
-        param_index: u32,
-    },
-    array_cat_lhs: ArrayCat,
-    array_cat_rhs: ArrayCat,
-
-    const ArrayCat = struct {
-        /// Points to the array concat AST node.
-        array_cat_offset: i32,
-        /// The index of the element the source location points to.
-        elem_index: u32,
-    };
-
-    pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease;
-
-    noinline fn nodeOffsetDebug(node_offset: i32) LazySrcLoc {
-        var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } };
-        result.node_offset.trace.addAddr(@returnAddress(), "init");
-        return result;
-    }
-
-    fn nodeOffsetRelease(node_offset: i32) LazySrcLoc {
-        return .{ .node_offset = .{ .x = node_offset } };
-    }
-
-    /// Upgrade to a `SrcLoc` based on the `Decl` provided.
-    pub fn toSrcLoc(lazy: LazySrcLoc, decl: *Decl, mod: *Module) SrcLoc {
-        return switch (lazy) {
-            .unneeded,
-            .entire_file,
-            .byte_abs,
-            .token_abs,
-            .node_abs,
-            => .{
-                .file_scope = decl.getFileScope(mod),
-                .parent_decl_node = 0,
-                .lazy = lazy,
-            },
-
-            .byte_offset,
-            .token_offset,
-            .node_offset,
-            .node_offset_main_token,
-            .node_offset_initializer,
-            .node_offset_var_decl_ty,
-            .node_offset_var_decl_align,
-            .node_offset_var_decl_section,
-            .node_offset_var_decl_addrspace,
-            .node_offset_var_decl_init,
-            .node_offset_builtin_call_arg0,
-            .node_offset_builtin_call_arg1,
-            .node_offset_builtin_call_arg2,
-            .node_offset_builtin_call_arg3,
-            .node_offset_builtin_call_arg4,
-            .node_offset_builtin_call_arg5,
-            .node_offset_ptrcast_operand,
-            .node_offset_array_access_index,
-            .node_offset_slice_ptr,
-            .node_offset_slice_start,
-            .node_offset_slice_end,
-            .node_offset_slice_sentinel,
-            .node_offset_call_func,
-            .node_offset_field_name,
-            .node_offset_field_name_init,
-            .node_offset_deref_ptr,
-            .node_offset_asm_source,
-            .node_offset_asm_ret_ty,
-            .node_offset_if_cond,
-            .node_offset_bin_op,
-            .node_offset_bin_lhs,
-            .node_offset_bin_rhs,
-            .node_offset_switch_operand,
-            .node_offset_switch_special_prong,
-            .node_offset_switch_range,
-            .node_offset_switch_prong_capture,
-            .node_offset_switch_prong_tag_capture,
-            .node_offset_fn_type_align,
-            .node_offset_fn_type_addrspace,
-            .node_offset_fn_type_section,
-            .node_offset_fn_type_cc,
-            .node_offset_fn_type_ret_ty,
-            .node_offset_param,
-            .token_offset_param,
-            .node_offset_anyframe_type,
-            .node_offset_lib_name,
-            .node_offset_array_type_len,
-            .node_offset_array_type_sentinel,
-            .node_offset_array_type_elem,
-            .node_offset_un_op,
-            .node_offset_ptr_elem,
-            .node_offset_ptr_sentinel,
-            .node_offset_ptr_align,
-            .node_offset_ptr_addrspace,
-            .node_offset_ptr_bitoffset,
-            .node_offset_ptr_hostsize,
-            .node_offset_container_tag,
-            .node_offset_field_default,
-            .node_offset_init_ty,
-            .node_offset_store_ptr,
-            .node_offset_store_operand,
-            .node_offset_return_operand,
-            .for_input,
-            .for_capture_from_input,
-            .array_cat_lhs,
-            .array_cat_rhs,
-            => .{
-                .file_scope = decl.getFileScope(mod),
-                .parent_decl_node = decl.src_node,
-                .lazy = lazy,
-            },
-            inline .call_arg,
-            .fn_proto_param,
-            => |x| .{
-                .file_scope = decl.getFileScope(mod),
-                .parent_decl_node = mod.declPtr(x.decl).src_node,
-                .lazy = lazy,
-            },
-        };
-    }
-};
-
 pub const SemaError = error{ OutOfMemory, AnalysisFail };
 pub const CompileError = error{
     OutOfMemory,
src/print_zir.zig
@@ -7,7 +7,7 @@ const InternPool = @import("InternPool.zig");
 
 const Zir = @import("Zir.zig");
 const Module = @import("Module.zig");
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 
 /// Write human-readable, debug formatted ZIR code to a file.
 pub fn renderAsTextToFile(
src/Sema.zig
@@ -156,7 +156,7 @@ const CompileError = Module.CompileError;
 const SemaError = Module.SemaError;
 const Decl = Module.Decl;
 const CaptureScope = Module.CaptureScope;
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 const RangeSet = @import("RangeSet.zig");
 const target_util = @import("target.zig");
 const Package = @import("Package.zig");
@@ -397,7 +397,7 @@ pub const Block = struct {
                         break :blk src_loc;
                     } else blk: {
                         const src_decl = mod.declPtr(rt.block.src_decl);
-                        break :blk rt.func_src.toSrcLoc(src_decl, mod);
+                        break :blk src_decl.toSrcLoc(rt.func_src, mod);
                     };
                     if (rt.return_ty.isGenericPoison()) {
                         return mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
@@ -2421,7 +2421,7 @@ fn errNote(
 ) error{OutOfMemory}!void {
     const mod = sema.mod;
     const src_decl = mod.declPtr(block.src_decl);
-    return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args);
+    return mod.errNoteNonLazy(src_decl.toSrcLoc(src, mod), parent, format, args);
 }
 
 fn addFieldErrNote(
@@ -2478,7 +2478,7 @@ fn errMsg(
     const mod = sema.mod;
     if (src == .unneeded) return error.NeededSourceLocation;
     const src_decl = mod.declPtr(block.src_decl);
-    return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args);
+    return Module.ErrorMsg.create(sema.gpa, src_decl.toSrcLoc(src, mod), format, args);
 }
 
 pub fn fail(
@@ -2556,7 +2556,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg)
                     const decl = mod.declPtr(ref.referencer);
                     try reference_stack.append(.{
                         .decl = decl.name,
-                        .src_loc = ref.src.toSrcLoc(decl, mod),
+                        .src_loc = decl.toSrcLoc(ref.src, mod),
                     });
                 }
                 referenced_by = ref.referencer;
@@ -2599,7 +2599,7 @@ fn reparentOwnedErrorMsg(
 ) !void {
     const mod = sema.mod;
     const src_decl = mod.declPtr(block.src_decl);
-    const resolved_src = src.toSrcLoc(src_decl, mod);
+    const resolved_src = src_decl.toSrcLoc(src, mod);
     const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
 
     const orig_notes = msg.notes.len;
@@ -5252,7 +5252,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
             errdefer msg.destroy(sema.gpa);
 
             const src_decl = mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty);
+            try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), elem_ty);
             break :msg msg;
         };
         return sema.failWithOwnedErrorMsg(block, msg);
@@ -5716,7 +5716,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
     var child_block = parent_block.makeSubBlock();
     child_block.label = &label;
     child_block.runtime_cond = null;
-    child_block.runtime_loop = src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
+    child_block.runtime_loop = mod.declPtr(child_block.src_decl).toSrcLoc(src, mod);
     child_block.runtime_index.increment();
     const merges = &child_block.label.?.merges;
 
@@ -6058,7 +6058,7 @@ fn analyzeBlockBody(
             try mod.errNoteNonLazy(runtime_src, msg, "runtime control flow here", .{});
 
             const child_src_decl = mod.declPtr(child_block.src_decl);
-            try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty);
+            try sema.explainWhyTypeIsComptime(msg, child_src_decl.toSrcLoc(type_src, mod), resolved_ty);
 
             break :msg msg;
         };
@@ -6213,7 +6213,7 @@ pub fn analyzeExport(
             errdefer msg.destroy(gpa);
 
             const src_decl = mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
+            try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), exported_decl.ty, .other);
 
             try sema.addDeclaredHereNote(msg, exported_decl.ty);
             break :msg msg;
@@ -8082,7 +8082,7 @@ fn instantiateGenericCall(
                     };
                     try child_sema.errNote(&child_block, param_src, msg, "declared here", .{});
                     const src_decl = mod.declPtr(block.src_decl);
-                    try sema.explainWhyTypeIsComptime(msg, arg_src.toSrcLoc(src_decl, mod), arg_ty);
+                    try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(arg_src, mod), arg_ty);
                     break :msg msg;
                 }),
 
@@ -9387,7 +9387,7 @@ fn funcCommon(
                 errdefer msg.destroy(sema.gpa);
 
                 const src_decl = mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param_ty, .param_ty);
+                try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(param_src, mod), param_ty, .param_ty);
 
                 try sema.addDeclaredHereNote(msg, param_ty);
                 break :msg msg;
@@ -9402,7 +9402,7 @@ fn funcCommon(
                 errdefer msg.destroy(sema.gpa);
 
                 const src_decl = mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param_ty);
+                try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(param_src, mod), param_ty);
 
                 try sema.addDeclaredHereNote(msg, param_ty);
                 break :msg msg;
@@ -9671,7 +9671,7 @@ fn finishFunc(
             errdefer msg.destroy(gpa);
 
             const src_decl = mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty);
+            try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ret_ty_src, mod), return_type, .ret_ty);
 
             try sema.addDeclaredHereNote(msg, return_type);
             break :msg msg;
@@ -9692,7 +9692,7 @@ fn finishFunc(
             "function with comptime-only return type '{}' requires all parameters to be comptime",
             .{return_type.fmt(mod)},
         );
-        try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type);
+        try sema.explainWhyTypeIsComptime(msg, sema.owner_decl.toSrcLoc(ret_ty_src, mod), return_type);
 
         const tags = sema.code.instructions.items(.tag);
         const data = sema.code.instructions.items(.data);
@@ -9965,7 +9965,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
             const msg = try sema.errMsg(block, ptr_src, "comptime-only type '{}' has no pointer address", .{pointee_ty.fmt(mod)});
             errdefer msg.destroy(sema.gpa);
             const src_decl = mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsComptime(msg, ptr_src.toSrcLoc(src_decl, mod), pointee_ty);
+            try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(ptr_src, mod), pointee_ty);
             break :msg msg;
         };
         return sema.failWithOwnedErrorMsg(block, msg);
@@ -11492,7 +11492,7 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
 
     var sub_block = child_block.makeSubBlock();
     sub_block.runtime_loop = null;
-    sub_block.runtime_cond = main_operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
+    sub_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(main_operand_src, mod);
     sub_block.runtime_index.increment();
     defer sub_block.instructions.deinit(gpa);
 
@@ -12227,7 +12227,7 @@ fn analyzeSwitchRuntimeBlock(
 
     var case_block = child_block.makeSubBlock();
     case_block.runtime_loop = null;
-    case_block.runtime_cond = operand_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
+    case_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(operand_src, mod);
     case_block.runtime_index.increment();
     defer case_block.instructions.deinit(gpa);
 
@@ -13663,7 +13663,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
         return sema.fail(block, operand_src, "file path name cannot be empty", .{});
     }
 
-    const src_loc = operand_src.toSrcLoc(mod.declPtr(block.src_decl), mod);
+    const src_loc = mod.declPtr(block.src_decl).toSrcLoc(operand_src, mod);
     const val = mod.embedFile(block.getFileScope(mod), name, src_loc) catch |err| switch (err) {
         error.ImportOutsideModulePath => {
             return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
@@ -18766,7 +18766,7 @@ fn zirBoolBr(
 
     var child_block = parent_block.makeSubBlock();
     child_block.runtime_loop = null;
-    child_block.runtime_cond = lhs_src.toSrcLoc(mod.declPtr(child_block.src_decl), mod);
+    child_block.runtime_cond = mod.declPtr(child_block.src_decl).toSrcLoc(lhs_src, mod);
     child_block.runtime_index.increment();
     defer child_block.instructions.deinit(gpa);
 
@@ -18963,7 +18963,7 @@ fn zirCondbr(
     // instructions array in between using it for the then block and else block.
     var sub_block = parent_block.makeSubBlock();
     sub_block.runtime_loop = null;
-    sub_block.runtime_cond = cond_src.toSrcLoc(mod.declPtr(parent_block.src_decl), mod);
+    sub_block.runtime_cond = mod.declPtr(parent_block.src_decl).toSrcLoc(cond_src, mod);
     sub_block.runtime_index.increment();
     defer sub_block.instructions.deinit(gpa);
 
@@ -19503,7 +19503,7 @@ fn analyzeRet(
 
             if (sema.fn_ret_ty.isError(mod) and ret_val.getErrorName(mod) != .none) {
                 const src_decl = mod.declPtr(block.src_decl);
-                const src_loc = src.toSrcLoc(src_decl, mod);
+                const src_loc = src_decl.toSrcLoc(src, mod);
                 try sema.comptime_err_ret_trace.append(src_loc);
             }
             return error.ComptimeReturn;
@@ -19660,7 +19660,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
                 errdefer msg.destroy(sema.gpa);
 
                 const src_decl = mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other);
+                try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(elem_ty_src, mod), elem_ty, .other);
 
                 try sema.addDeclaredHereNote(msg, elem_ty);
                 break :msg msg;
@@ -21128,7 +21128,7 @@ fn zirReify(
                         errdefer msg.destroy(gpa);
 
                         const src_decl = mod.declPtr(block.src_decl);
-                        try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other);
+                        try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), elem_ty, .other);
 
                         try sema.addDeclaredHereNote(msg, elem_ty);
                         break :msg msg;
@@ -21572,7 +21572,7 @@ fn zirReify(
                         errdefer msg.destroy(gpa);
 
                         const src_decl = mod.declPtr(block.src_decl);
-                        try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
+                        try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
 
                         try sema.addDeclaredHereNote(msg, field_ty);
                         break :msg msg;
@@ -21584,7 +21584,7 @@ fn zirReify(
                         errdefer msg.destroy(gpa);
 
                         const src_decl = mod.declPtr(block.src_decl);
-                        try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
+                        try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
 
                         try sema.addDeclaredHereNote(msg, field_ty);
                         break :msg msg;
@@ -21939,7 +21939,7 @@ fn reifyStruct(
                 errdefer msg.destroy(gpa);
 
                 const src_decl = sema.mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field);
+                try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .struct_field);
 
                 try sema.addDeclaredHereNote(msg, field_ty);
                 break :msg msg;
@@ -21951,7 +21951,7 @@ fn reifyStruct(
                 errdefer msg.destroy(gpa);
 
                 const src_decl = sema.mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
+                try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
 
                 try sema.addDeclaredHereNote(msg, field_ty);
                 break :msg msg;
@@ -22018,7 +22018,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
             errdefer msg.destroy(sema.gpa);
 
             const src_decl = sema.mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty);
+            try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), arg_ty, .param_ty);
 
             try sema.addDeclaredHereNote(msg, arg_ty);
             break :msg msg;
@@ -25859,7 +25859,7 @@ fn zirBuiltinExtern(
             const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
             errdefer msg.destroy(sema.gpa);
             const src_decl = sema.mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other);
+            try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(ty_src, mod), ty, .other);
             break :msg msg;
         };
         return sema.failWithOwnedErrorMsg(block, msg);
@@ -26003,7 +26003,7 @@ fn validateVarType(
                 const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
                 errdefer msg.destroy(sema.gpa);
                 const src_decl = mod.declPtr(block.src_decl);
-                try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
+                try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), var_ty, .other);
                 break :msg msg;
             };
             return sema.failWithOwnedErrorMsg(block, msg);
@@ -26026,7 +26026,7 @@ fn validateVarType(
         errdefer msg.destroy(sema.gpa);
 
         const src_decl = mod.declPtr(block.src_decl);
-        try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty);
+        try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(src, mod), var_ty);
         if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) {
             try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
         }
@@ -28093,7 +28093,7 @@ fn validateRuntimeElemAccess(
             errdefer msg.destroy(sema.gpa);
 
             const src_decl = mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty);
+            try sema.explainWhyTypeIsComptime(msg, src_decl.toSrcLoc(parent_src, mod), parent_ty);
 
             break :msg msg;
         };
@@ -28492,7 +28492,7 @@ const CoerceOpts = struct {
                     .lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
                 };
             }
-            return param_src.toSrcLoc(fn_decl, mod);
+            return fn_decl.toSrcLoc(param_src, mod);
         }
     } = .{},
 };
@@ -29110,7 +29110,7 @@ fn coerceExtra(
 
             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
             const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
-            try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{});
+            try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "'noreturn' declared here", .{});
             break :msg msg;
         };
         return sema.failWithOwnedErrorMsg(block, msg);
@@ -29145,9 +29145,9 @@ fn coerceExtra(
             const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
             const src_decl = mod.funcOwnerDeclPtr(sema.func_index);
             if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
-                try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{});
+                try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function cannot return an error", .{});
             } else {
-                try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{});
+                try mod.errNoteNonLazy(src_decl.toSrcLoc(ret_ty_src, mod), msg, "function return type declared here", .{});
             }
         }
 
@@ -30165,7 +30165,7 @@ fn coerceVarArgParam(
             errdefer msg.destroy(sema.gpa);
 
             const src_decl = sema.mod.declPtr(block.src_decl);
-            try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty);
+            try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(inst_src, mod), coerced_ty, .param_ty);
 
             try sema.addDeclaredHereNote(msg, coerced_ty);
             break :msg msg;
@@ -37180,7 +37180,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
                     });
                     errdefer msg.destroy(sema.gpa);
                     const decl_ptr = mod.declPtr(tag_info.decl);
-                    try mod.errNoteNonLazy(enum_field_src.toSrcLoc(decl_ptr, mod), msg, "enum field here", .{});
+                    try mod.errNoteNonLazy(decl_ptr.toSrcLoc(enum_field_src, mod), msg, "enum field here", .{});
                     break :msg msg;
                 };
                 return sema.failWithOwnedErrorMsg(&block_scope, msg);
src/Zir.zig
@@ -22,7 +22,7 @@ const Ast = std.zig.Ast;
 const InternPool = @import("InternPool.zig");
 const Zir = @This();
 const Module = @import("Module.zig");
-const LazySrcLoc = Module.LazySrcLoc;
+const LazySrcLoc = std.zig.LazySrcLoc;
 
 instructions: std.MultiArrayList(Inst).Slice,
 /// In order to store references to strings in fewer bytes, we copy all