Commit 2047a6b82d

Andrew Kelley <andrew@ziglang.org>
2023-12-16 08:39:36
fix remaining compile errors except one
1 parent 4629708
src/arch/x86_64/CodeGen.zig
@@ -800,19 +800,20 @@ pub fn generate(
 ) CodeGenError!Result {
     const comp = bin_file.comp;
     const gpa = comp.gpa;
-    const mod = comp.module.?;
-    const func = mod.funcInfo(func_index);
-    const fn_owner_decl = mod.declPtr(func.owner_decl);
+    const zcu = comp.module.?;
+    const func = zcu.funcInfo(func_index);
+    const fn_owner_decl = zcu.declPtr(func.owner_decl);
     assert(fn_owner_decl.has_tv);
     const fn_type = fn_owner_decl.ty;
-    const namespace = mod.namespacePtr(fn_owner_decl.src_namespace);
-    const target = namespace.file_scope.mod.resolved_target.result;
+    const namespace = zcu.namespacePtr(fn_owner_decl.src_namespace);
+    const mod = namespace.file_scope.mod;
 
     var function = Self{
         .gpa = gpa,
         .air = air,
         .liveness = liveness,
-        .target = target,
+        .target = &mod.resolved_target.result,
+        .mod = mod,
         .bin_file = bin_file,
         .debug_output = debug_output,
         .owner = .{ .func_index = func_index },
@@ -843,7 +844,7 @@ pub fn generate(
 
     wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
 
-    const ip = &mod.intern_pool;
+    const ip = &zcu.intern_pool;
 
     try function.frame_allocs.resize(gpa, FrameIndex.named_count);
     function.frame_allocs.set(
@@ -858,7 +859,7 @@ pub fn generate(
         FrameAlloc.init(.{ .size = 0, .alignment = .@"1" }),
     );
 
-    const fn_info = mod.typeToFunc(fn_type).?;
+    const fn_info = zcu.typeToFunc(fn_type).?;
     const cc = abi.resolveCallingConvention(fn_info.cc, function.target.*);
     var call_info = function.resolveCallingConventionValues(fn_info, &.{}, .args_frame) catch |err| switch (err) {
         error.CodegenFail => return Result{ .fail = function.err_msg.? },
@@ -877,14 +878,14 @@ pub fn generate(
     function.args = call_info.args;
     function.ret_mcv = call_info.return_value;
     function.frame_allocs.set(@intFromEnum(FrameIndex.ret_addr), FrameAlloc.init(.{
-        .size = Type.usize.abiSize(mod),
-        .alignment = Type.usize.abiAlignment(mod).min(call_info.stack_align),
+        .size = Type.usize.abiSize(zcu),
+        .alignment = Type.usize.abiAlignment(zcu).min(call_info.stack_align),
     }));
     function.frame_allocs.set(@intFromEnum(FrameIndex.base_ptr), FrameAlloc.init(.{
-        .size = Type.usize.abiSize(mod),
+        .size = Type.usize.abiSize(zcu),
         .alignment = Alignment.min(
             call_info.stack_align,
-            Alignment.fromNonzeroByteUnits(target.stackAlignment()),
+            Alignment.fromNonzeroByteUnits(function.target.stackAlignment()),
         ),
     }));
     function.frame_allocs.set(
@@ -927,6 +928,9 @@ pub fn generate(
             .mir = mir,
             .cc = cc,
             .src_loc = src_loc,
+            .output_mode = comp.config.output_mode,
+            .link_mode = comp.config.link_mode,
+            .pic = mod.pic,
         },
         .debug_output = debug_output,
         .code = code,
@@ -970,16 +974,14 @@ pub fn generateLazy(
 ) CodeGenError!Result {
     const comp = bin_file.comp;
     const gpa = comp.gpa;
-    const zcu = comp.module.?;
-    const decl_index = lazy_sym.ty.getOwnerDecl(zcu);
-    const decl = zcu.declPtr(decl_index);
-    const namespace = zcu.namespacePtr(decl.src_namespace);
-    const target = namespace.file_scope.mod.resolved_target.result;
+    // This function is for generating global code, so we use the root module.
+    const mod = comp.root_mod;
     var function = Self{
         .gpa = gpa,
         .air = undefined,
         .liveness = undefined,
-        .target = target,
+        .target = &mod.resolved_target.result,
+        .mod = mod,
         .bin_file = bin_file,
         .debug_output = debug_output,
         .owner = .{ .lazy_sym = lazy_sym },
@@ -1020,6 +1022,9 @@ pub fn generateLazy(
             .mir = mir,
             .cc = abi.resolveCallingConvention(.Unspecified, function.target.*),
             .src_loc = src_loc,
+            .output_mode = comp.config.output_mode,
+            .link_mode = comp.config.link_mode,
+            .pic = mod.pic,
         },
         .debug_output = debug_output,
         .code = code,
@@ -1104,6 +1109,8 @@ fn formatWipMir(
     _: std.fmt.FormatOptions,
     writer: anytype,
 ) @TypeOf(writer).Error!void {
+    const comp = data.self.bin_file.comp;
+    const mod = comp.root_mod;
     var lower = Lower{
         .bin_file = data.self.bin_file,
         .allocator = data.self.gpa,
@@ -1114,6 +1121,9 @@ fn formatWipMir(
         },
         .cc = .Unspecified,
         .src_loc = data.self.src_loc,
+        .output_mode = comp.config.output_mode,
+        .link_mode = comp.config.link_mode,
+        .pic = mod.pic,
     };
     var first = true;
     for ((lower.lowerMir(data.inst) catch |err| switch (err) {
src/codegen/llvm.zig
@@ -1168,7 +1168,7 @@ pub const Object = struct {
         pre_ir_path: ?[]const u8,
         pre_bc_path: ?[]const u8,
         bin_path: ?[*:0]const u8,
-        emit_asm: ?[*:0]const u8,
+        asm_path: ?[*:0]const u8,
         post_ir_path: ?[*:0]const u8,
         post_bc_path: ?[*:0]const u8,
 
src/link/Coff/lld.zig
@@ -21,7 +21,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
     const tracy = trace(@src());
     defer tracy.end();
 
-    var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
+    const gpa = comp.gpa;
+    var arena_allocator = std.heap.ArenaAllocator.init(gpa);
     defer arena_allocator.deinit();
     const arena = arena_allocator.allocator();
 
@@ -30,7 +31,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
 
     // If there is no Zig code to compile, then we should skip flushing the output file because it
     // will not be part of the linker line anyway.
-    const module_obj_path: ?[]const u8 = if (self.base.comp.module != null) blk: {
+    const module_obj_path: ?[]const u8 = if (comp.module != null) blk: {
         try self.flushModule(comp, prog_node);
 
         if (fs.path.dirname(full_out_path)) |dirname| {
@@ -45,12 +46,12 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
     sub_prog_node.context.refresh();
     defer sub_prog_node.end();
 
-    const is_lib = self.base.comp.config.output_mode == .Lib;
-    const is_dyn_lib = self.base.comp.config.link_mode == .Dynamic and is_lib;
-    const is_exe_or_dyn_lib = is_dyn_lib or self.base.comp.config.output_mode == .Exe;
+    const is_lib = comp.config.output_mode == .Lib;
+    const is_dyn_lib = comp.config.link_mode == .Dynamic and is_lib;
+    const is_exe_or_dyn_lib = is_dyn_lib or comp.config.output_mode == .Exe;
     const link_in_crt = comp.config.link_libc and is_exe_or_dyn_lib;
-    const target = self.base.comp.root_mod.resolved_target.result;
-    const optimize_mode = self.base.comp.root_mod.optimize_mode;
+    const target = comp.root_mod.resolved_target.result;
+    const optimize_mode = comp.root_mod.optimize_mode;
 
     // See link/Elf.zig for comments on how this mechanism works.
     const id_symlink_basename = "lld.id";
@@ -85,8 +86,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
         man.hash.addListOfBytes(self.lib_dirs);
         man.hash.add(comp.skip_linker_dependencies);
         if (comp.config.link_libc) {
-            man.hash.add(self.base.comp.libc_installation != null);
-            if (self.base.comp.libc_installation) |libc_installation| {
+            man.hash.add(comp.libc_installation != null);
+            if (comp.libc_installation) |libc_installation| {
                 man.hash.addBytes(libc_installation.crt_dir.?);
                 if (target.abi == .msvc) {
                     man.hash.addBytes(libc_installation.msvc_lib_dir.?);
@@ -94,7 +95,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
                 }
             }
         }
-        try link.hashAddSystemLibs(&man, self.base.comp.system_libs);
+        try link.hashAddSystemLibs(&man, comp.system_libs);
         man.hash.addListOfBytes(self.base.force_undefined_symbols.keys());
         man.hash.addOptional(self.subsystem);
         man.hash.add(comp.config.is_test);
@@ -136,7 +137,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
         };
     }
 
-    if (self.base.comp.config.output_mode == .Obj) {
+    if (comp.config.output_mode == .Obj) {
         // LLD's COFF driver does not support the equivalent of `-r` so we do a simple file copy
         // here. TODO: think carefully about how we can avoid this redundant operation when doing
         // build-obj. See also the corresponding TODO in linkAsArchive.
@@ -161,7 +162,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
         }
     } else {
         // Create an LLD command line and invoke it.
-        var argv = std.ArrayList([]const u8).init(self.base.allocator);
+        var argv = std.ArrayList([]const u8).init(gpa);
         defer argv.deinit();
         // We will invoke ourselves as a child process to gain access to LLD.
         // This is necessary because LLD does not behave properly as a library -
@@ -192,7 +193,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
                 .ReleaseFast, .ReleaseSafe => try argv.append("-OPT:lldlto=3"),
             }
         }
-        if (self.base.comp.config.output_mode == .Exe) {
+        if (comp.config.output_mode == .Exe) {
             try argv.append(try allocPrint(arena, "-STACK:{d}", .{self.base.stack_size}));
         }
         try argv.append(try std.fmt.allocPrint(arena, "-BASE:{d}", .{self.image_base}));
@@ -242,7 +243,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
         }
 
         if (comp.config.link_libc) {
-            if (self.base.comp.libc_installation) |libc_installation| {
+            if (comp.libc_installation) |libc_installation| {
                 try argv.append(try allocPrint(arena, "-LIBPATH:{s}", .{libc_installation.crt_dir.?}));
 
                 if (target.abi == .msvc) {
@@ -287,7 +288,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
             if (self.subsystem) |explicit| break :blk explicit;
             switch (target.os.tag) {
                 .windows => {
-                    if (self.base.comp.module) |module| {
+                    if (comp.module) |module| {
                         if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
                             break :blk null;
                         if (module.stage1_flags.have_c_main or comp.config.is_test or
@@ -415,13 +416,13 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
                         try argv.append(try comp.get_libc_crt_file(arena, "uuid.lib"));
 
                         for (mingw.always_link_libs) |name| {
-                            if (!self.base.comp.system_libs.contains(name)) {
+                            if (!comp.system_libs.contains(name)) {
                                 const lib_basename = try allocPrint(arena, "{s}.lib", .{name});
                                 try argv.append(try comp.get_libc_crt_file(arena, lib_basename));
                             }
                         }
                     } else {
-                        const lib_str = switch (self.base.comp.config.link_mode) {
+                        const lib_str = switch (comp.config.link_mode) {
                             .Dynamic => "",
                             .Static => "lib",
                         };
@@ -429,7 +430,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
                             .Debug => "d",
                             else => "",
                         };
-                        switch (self.base.comp.config.link_mode) {
+                        switch (comp.config.link_mode) {
                             .Static => try argv.append(try allocPrint(arena, "libcmt{s}.lib", .{d_str})),
                             .Dynamic => try argv.append(try allocPrint(arena, "msvcrt{s}.lib", .{d_str})),
                         }
@@ -448,7 +449,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
                 } else {
                     try argv.append("-NODEFAULTLIB");
                     if (!is_lib and comp.config.entry == null) {
-                        if (self.base.comp.module) |module| {
+                        if (comp.module) |module| {
                             if (module.stage1_flags.have_winmain_crt_startup) {
                                 try argv.append("-ENTRY:WinMainCRTStartup");
                             } else {
@@ -485,8 +486,8 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
             if (comp.compiler_rt_lib) |lib| try argv.append(lib.full_object_path);
         }
 
-        try argv.ensureUnusedCapacity(self.base.comp.system_libs.count());
-        for (self.base.comp.system_libs.keys()) |key| {
+        try argv.ensureUnusedCapacity(comp.system_libs.count());
+        for (comp.system_libs.keys()) |key| {
             const lib_basename = try allocPrint(arena, "{s}.lib", .{key});
             if (comp.crt_files.get(lib_basename)) |crt_file| {
                 argv.appendAssumeCapacity(crt_file.full_object_path);
@@ -512,7 +513,7 @@ pub fn linkWithLLD(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
             return error.DllImportLibraryNotFound;
         }
 
-        if (self.base.comp.verbose_link) {
+        if (comp.verbose_link) {
             // Skip over our own name so that the LLD linker name is the first argv item.
             Compilation.dump_argv(argv.items[1..]);
         }
src/link/Elf/Atom.zig
@@ -377,8 +377,8 @@ pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
 }
 
 pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype) !void {
-    const is_static = elf_file.isStatic();
-    const is_dyn_lib = elf_file.isDynLib();
+    const is_static = elf_file.base.isStatic();
+    const is_dyn_lib = elf_file.base.isDynLib();
     const file_ptr = self.file(elf_file).?;
     const rels = self.relocs(elf_file);
     var i: usize = 0;
@@ -660,7 +660,7 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
 
 fn outputType(elf_file: *Elf) u2 {
     const comp = elf_file.base.comp;
-    assert(!elf_file.isRelocatable());
+    assert(!elf_file.base.isRelocatable());
     return switch (elf_file.base.comp.config.output_mode) {
         .Obj => unreachable,
         .Lib => 0,
src/link/Elf/eh_frame.zig
@@ -271,7 +271,7 @@ pub fn calcEhFrameSize(elf_file: *Elf) !usize {
         }
     }
 
-    if (!elf_file.isRelocatable()) {
+    if (!elf_file.base.isRelocatable()) {
         offset += 4; // NULL terminator
     }
 
src/link/Elf/Object.zig
@@ -250,7 +250,7 @@ fn addAtom(self: *Object, shdr: ElfShdr, shndx: u16, elf_file: *Elf) error{OutOf
 fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMemory}!u16 {
     const name = blk: {
         const name = self.getString(shdr.sh_name);
-        if (elf_file.isRelocatable()) break :blk name;
+        if (elf_file.base.isRelocatable()) break :blk name;
         if (shdr.sh_flags & elf.SHF_MERGE != 0) break :blk name;
         const sh_name_prefixes: []const [:0]const u8 = &.{
             ".text",       ".data.rel.ro", ".data", ".rodata", ".bss.rel.ro",       ".bss",
@@ -278,7 +278,7 @@ fn initOutputSection(self: Object, elf_file: *Elf, shdr: ElfShdr) error{OutOfMem
     };
     const flags = blk: {
         var flags = shdr.sh_flags;
-        if (!elf_file.isRelocatable()) {
+        if (!elf_file.base.isRelocatable()) {
             flags &= ~@as(u64, elf.SHF_COMPRESSED | elf.SHF_GROUP | elf.SHF_GNU_RETAIN);
         }
         break :blk switch (@"type") {
@@ -520,7 +520,7 @@ pub fn claimUnresolved(self: *Object, elf_file: *Elf) void {
         }
 
         const is_import = blk: {
-            if (!elf_file.isDynLib()) break :blk false;
+            if (!elf_file.base.isDynLib()) break :blk false;
             const vis = @as(elf.STV, @enumFromInt(esym.st_other));
             if (vis == .HIDDEN) break :blk false;
             break :blk true;
src/link/Elf/ZigObject.zig
@@ -370,7 +370,7 @@ pub fn claimUnresolved(self: ZigObject, elf_file: *Elf) void {
         }
 
         const is_import = blk: {
-            if (!elf_file.isDynLib()) break :blk false;
+            if (!elf_file.base.isDynLib()) break :blk false;
             const vis = @as(elf.STV, @enumFromInt(esym.st_other));
             if (vis == .HIDDEN) break :blk false;
             break :blk true;
src/link/MachO/dead_strip.zig
@@ -1,7 +1,8 @@
 //! An algorithm for dead stripping of unreferenced Atoms.
 
 pub fn gcAtoms(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     var arena = std.heap.ArenaAllocator.init(gpa);
     defer arena.deinit();
src/link/MachO/eh_frame.zig
@@ -1,5 +1,6 @@
 pub fn scanRelocs(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     for (macho_file.objects.items, 0..) |*object, object_id| {
         var cies = std.AutoHashMap(u32, void).init(gpa);
@@ -37,7 +38,8 @@ pub fn calcSectionSize(macho_file: *MachO, unwind_info: *const UnwindInfo) error
 
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     var size: u32 = 0;
 
     for (macho_file.objects.items, 0..) |*object, object_id| {
@@ -89,7 +91,8 @@ pub fn write(macho_file: *MachO, unwind_info: *UnwindInfo) !void {
 
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     var eh_records = std.AutoArrayHashMap(u32, EhFrameRecord(true)).init(gpa);
     defer {
src/link/MachO/load_commands.zig
@@ -63,7 +63,7 @@ fn calcLCsSize(m: *MachO, ctx: CalcLCsSizeCtx, assume_max_path_len: bool) !u32 {
     }
     // LC_RPATH
     {
-        var it = RpathIterator.init(gpa, m.rpath_list);
+        var it = RpathIterator.init(gpa, m.base.rpath_list);
         defer it.deinit();
         while (try it.next()) |rpath| {
             sizeofcmds += calcInstallNameLen(
@@ -189,17 +189,20 @@ fn writeDylibLC(ctx: WriteDylibLCCtx, lc_writer: anytype) !void {
     }
 }
 
-pub fn writeDylibIdLC(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void {
-    assert(options.output_mode == .Lib and options.link_mode == .Dynamic);
-    const emit = options.emit.?;
-    const install_name = options.install_name orelse try emit.directory.join(gpa, &.{emit.sub_path});
-    defer if (options.install_name == null) gpa.free(install_name);
-    const curr = options.version orelse std.SemanticVersion{
+pub fn writeDylibIdLC(macho_file: *MachO, lc_writer: anytype) !void {
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
+    assert(comp.config.output_mode == .Lib and comp.config.link_mode == .Dynamic);
+    const emit = macho_file.base.emit;
+    const install_name = macho_file.install_name orelse
+        try emit.directory.join(gpa, &.{emit.sub_path});
+    defer if (macho_file.install_name == null) gpa.free(install_name);
+    const curr = comp.version orelse std.SemanticVersion{
         .major = 1,
         .minor = 0,
         .patch = 0,
     };
-    const compat = options.compatibility_version orelse std.SemanticVersion{
+    const compat = macho_file.compatibility_version orelse std.SemanticVersion{
         .major = 1,
         .minor = 0,
         .patch = 0,
@@ -237,8 +240,11 @@ const RpathIterator = struct {
     }
 };
 
-pub fn writeRpathLCs(gpa: Allocator, options: *const link.Options, lc_writer: anytype) !void {
-    var it = RpathIterator.init(gpa, options.rpath_list);
+pub fn writeRpathLCs(macho_file: *MachO, lc_writer: anytype) !void {
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
+
+    var it = RpathIterator.init(gpa, macho_file.base.rpath_list);
     defer it.deinit();
 
     while (try it.next()) |rpath| {
@@ -467,13 +473,14 @@ pub inline fn appleVersionToSemanticVersion(version: u32) std.SemanticVersion {
     };
 }
 
-pub fn inferSdkVersion(gpa: Allocator, comp: *const Compilation) ?std.SemanticVersion {
+pub fn inferSdkVersion(macho_file: *MachO) ?std.SemanticVersion {
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
+
     var arena_allocator = std.heap.ArenaAllocator.init(gpa);
     defer arena_allocator.deinit();
     const arena = arena_allocator.allocator();
 
-    const macho_file = comp.bin_file.cast(MachO).?;
-
     const sdk_layout = macho_file.sdk_layout orelse return null;
     const sdk_dir = switch (sdk_layout) {
         .sdk => comp.sysroot.?,
src/link/MachO/Object.zig
@@ -342,19 +342,22 @@ pub const SplitIntoAtomsError = error{
 };
 
 pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) SplitIntoAtomsError!void {
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     log.debug("splitting object({d}, {s}) into atoms", .{ object_id, self.name });
 
     try self.splitRegularSections(macho_file, object_id);
     try self.parseEhFrameSection(macho_file, object_id);
     try self.parseUnwindInfo(macho_file, object_id);
-    try self.parseDataInCode(macho_file.base.allocator);
+    try self.parseDataInCode(gpa);
 }
 
 /// Splits input regular sections into Atoms.
 /// If the Object was compiled with `MH_SUBSECTIONS_VIA_SYMBOLS`, splits section
 /// into subsections where each subsection then represents an Atom.
 pub fn splitRegularSections(self: *Object, macho_file: *MachO, object_id: u32) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
 
     const sections = self.getSourceSections();
@@ -555,7 +558,8 @@ fn createAtomFromSubsection(
     alignment: Alignment,
     out_sect_id: u8,
 ) !Atom.Index {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const atom_index = try macho_file.createAtom(sym_index, .{
         .size = size,
         .alignment = alignment,
@@ -671,7 +675,8 @@ fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void
 
     log.debug("parsing __TEXT,__eh_frame section", .{});
 
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     if (macho_file.eh_frame_section_index == null) {
         macho_file.eh_frame_section_index = try macho_file.initSection("__TEXT", "__eh_frame", .{});
@@ -767,7 +772,8 @@ fn parseEhFrameSection(self: *Object, macho_file: *MachO, object_id: u32) !void
 }
 
 fn parseUnwindInfo(self: *Object, macho_file: *MachO, object_id: u32) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
     const sect_id = self.unwind_info_sect_id orelse {
src/link/MachO/thunks.zig
@@ -68,7 +68,8 @@ pub fn createThunks(macho_file: *MachO, sect_id: u8) !void {
     const header = &macho_file.sections.items(.header)[sect_id];
     if (header.size == 0) return;
 
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const first_atom_index = macho_file.sections.items(.first_atom_index)[sect_id].?;
 
     header.size = 0;
@@ -245,7 +246,8 @@ fn scanRelocs(
             macho_file.getSymbol(target).n_value,
         });
 
-        const gpa = macho_file.base.allocator;
+        const comp = macho_file.base.comp;
+        const gpa = comp.gpa;
         const target_sym = macho_file.getSymbol(target);
         const thunk = &macho_file.thunks.items[thunk_index];
 
src/link/MachO/zld.zig
@@ -15,7 +15,7 @@ pub fn linkWithZld(
     const arena = arena_allocator.allocator();
 
     const directory = emit.directory; // Just an alias to make it shorter to type.
-    const full_out_path = try directory.join(arena, &[_][]const u8{emit.?.sub_path});
+    const full_out_path = try directory.join(arena, &[_][]const u8{emit.sub_path});
     const opt_zcu = macho_file.base.comp.module;
 
     // If there is no Zig code to compile, then we should skip flushing the output file because it
@@ -71,14 +71,14 @@ pub fn linkWithZld(
         // We can skip hashing libc and libc++ components that we are in charge of building from Zig
         // installation sources because they are always a product of the compiler version + target information.
         man.hash.add(stack_size);
-        man.hash.addOptional(macho_file.pagezero_vmsize);
-        man.hash.addOptional(macho_file.headerpad_size);
+        man.hash.add(macho_file.pagezero_vmsize);
+        man.hash.add(macho_file.headerpad_size);
         man.hash.add(macho_file.headerpad_max_install_names);
         man.hash.add(macho_file.base.gc_sections);
         man.hash.add(macho_file.dead_strip_dylibs);
         man.hash.add(macho_file.base.comp.root_mod.strip);
         try MachO.hashAddFrameworks(&man, macho_file.frameworks);
-        man.hash.addListOfBytes(macho_file.rpath_list);
+        man.hash.addListOfBytes(macho_file.base.rpath_list);
         if (is_dyn_lib) {
             man.hash.addOptionalBytes(macho_file.install_name);
             man.hash.addOptional(comp.version);
@@ -151,7 +151,7 @@ pub fn linkWithZld(
             try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
         }
     } else {
-        const sub_path = emit.?.sub_path;
+        const sub_path = emit.sub_path;
 
         const old_file = macho_file.base.file; // TODO is this needed at all?
         defer macho_file.base.file = old_file;
@@ -241,7 +241,7 @@ pub fn linkWithZld(
                 try argv.append(@tagName(platform.os_tag));
                 try argv.append(try std.fmt.allocPrint(arena, "{}", .{platform.version}));
 
-                const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp);
+                const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(macho_file);
                 if (sdk_version) |ver| {
                     try argv.append(try std.fmt.allocPrint(arena, "{d}.{d}", .{ ver.major, ver.minor }));
                 } else {
@@ -254,13 +254,13 @@ pub fn linkWithZld(
                 try argv.append(syslibroot);
             }
 
-            for (macho_file.rpath_list) |rpath| {
+            for (macho_file.base.rpath_list) |rpath| {
                 try argv.append("-rpath");
                 try argv.append(rpath);
             }
 
             try argv.appendSlice(&.{
-                "-pagezero_size",  try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_size}),
+                "-pagezero_size",  try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.pagezero_vmsize}),
                 "-headerpad_size", try std.fmt.allocPrint(arena, "0x{x}", .{macho_file.headerpad_size}),
             });
 
@@ -558,7 +558,7 @@ pub fn linkWithZld(
         });
         {
             const platform = Platform.fromTarget(target);
-            const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp);
+            const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(macho_file);
             if (platform.isBuildVersionCompatible()) {
                 try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer);
             } else {
@@ -609,7 +609,8 @@ pub fn linkWithZld(
 }
 
 fn createSegments(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const page_size = MachO.getPageSize(target.cpu.arch);
     const aligned_pagezero_vmsize = mem.alignBackward(u64, macho_file.pagezero_vmsize, page_size);
@@ -683,7 +684,8 @@ fn createSegments(macho_file: *MachO) !void {
 }
 
 fn writeAtoms(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const slice = macho_file.sections.slice();
 
     for (slice.items(.first_atom_index), 0..) |first_atom_index, sect_id| {
@@ -758,7 +760,8 @@ fn writeDyldPrivateAtom(macho_file: *MachO) !void {
 fn writeThunks(macho_file: *MachO) !void {
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     assert(target.cpu.arch == .aarch64);
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     const sect_id = macho_file.text_section_index orelse return;
     const header = macho_file.sections.items(.header)[sect_id];
@@ -778,7 +781,8 @@ fn writeThunks(macho_file: *MachO) !void {
 }
 
 fn writePointerEntries(macho_file: *MachO, sect_id: u8, table: anytype) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const header = macho_file.sections.items(.header)[sect_id];
     const capacity = math.cast(usize, header.size) orelse return error.Overflow;
     var buffer = try std.ArrayList(u8).initCapacity(gpa, capacity);
@@ -792,7 +796,8 @@ fn writePointerEntries(macho_file: *MachO, sect_id: u8, table: anytype) !void {
 }
 
 fn writeStubs(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
     const stubs_header = macho_file.sections.items(.header)[macho_file.stubs_section_index.?];
@@ -815,7 +820,8 @@ fn writeStubs(macho_file: *MachO) !void {
 }
 
 fn writeStubHelpers(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
     const stub_helper_header = macho_file.sections.items(.header)[macho_file.stub_helper_section_index.?];
@@ -859,7 +865,8 @@ fn writeStubHelpers(macho_file: *MachO) !void {
 }
 
 fn writeLaSymbolPtrs(macho_file: *MachO) !void {
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
     const target = macho_file.base.comp.root_mod.resolved_target.result;
     const cpu_arch = target.cpu.arch;
     const la_symbol_ptr_header = macho_file.sections.items(.header)[macho_file.la_symbol_ptr_section_index.?];
@@ -892,7 +899,8 @@ fn pruneAndSortSections(macho_file: *MachO) !void {
         }
     };
 
-    const gpa = macho_file.base.allocator;
+    const comp = macho_file.base.comp;
+    const gpa = comp.gpa;
 
     var entries = try std.ArrayList(Entry).initCapacity(gpa, macho_file.sections.slice().len);
     defer entries.deinit();
src/link/Wasm/Object.zig
@@ -883,6 +883,8 @@ fn assertEnd(reader: anytype) !void {
 
 /// Parses an object file into atoms, for code and data sections
 pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32, wasm: *Wasm) !Atom.Index {
+    const comp = wasm.base.comp;
+    const gpa = comp.gpa;
     const symbol = &object.symtable[symbol_index];
     const relocatable_data: RelocatableData = switch (symbol.tag) {
         .function => object.relocatable_data.get(.code).?[symbol.index - object.importedCountByKind(.function)],
@@ -900,7 +902,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
     };
     const final_index = try wasm.getMatchingSegment(object_index, symbol_index);
     const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
-    const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
+    const atom = try wasm.managed_atoms.addOne(gpa);
     atom.* = Atom.empty;
     try wasm.appendAtomAtIndex(final_index, atom_index);
 
@@ -910,7 +912,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
     atom.alignment = relocatable_data.getAlignment(object);
     atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
     atom.original_offset = relocatable_data.offset;
-    try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom_index);
+    try wasm.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);
     const segment: *Wasm.Segment = &wasm.segments.items[final_index];
     if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
         segment.alignment = segment.alignment.max(atom.alignment);
@@ -927,7 +929,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
                 .R_WASM_TABLE_INDEX_SLEB,
                 .R_WASM_TABLE_INDEX_SLEB64,
                 => {
-                    try wasm.function_table.put(wasm.base.allocator, .{
+                    try wasm.function_table.put(gpa, .{
                         .file = object_index,
                         .index = reloc.index,
                     }, 0);
@@ -938,7 +940,7 @@ pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32
                     const sym = object.symtable[reloc.index];
                     if (sym.tag != .global) {
                         try wasm.got_symbols.append(
-                            wasm.base.allocator,
+                            gpa,
                             .{ .file = object_index, .index = reloc.index },
                         );
                     }
src/link/C.zig
@@ -135,6 +135,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj),
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 16777216,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = file,
src/link/Coff.zig
@@ -14,9 +14,10 @@ nxcompat: bool,
 dynamicbase: bool,
 /// TODO this and minor_subsystem_version should be combined into one property and left as
 /// default or populated together. They should not be separate fields.
-major_subsystem_version: u32,
-minor_subsystem_version: u32,
+major_subsystem_version: u16,
+minor_subsystem_version: u16,
 lib_dirs: []const []const u8,
+entry_addr: ?u32,
 
 ptr_width: PtrWidth,
 page_size: u32,
@@ -238,7 +239,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*Coff {
-    if (build_options.only_c) unreachable;
     const target = comp.root_mod.resolved_target.result;
     assert(target.ofmt == .coff);
 
@@ -390,6 +390,7 @@ pub fn createEmpty(
             .emit = emit,
             .stack_size = options.stack_size orelse 16777216,
             .gc_sections = options.gc_sections orelse (optimize_mode != .Debug),
+            .print_gc_sections = options.print_gc_sections,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
             .disable_lld_caching = options.disable_lld_caching,
@@ -422,6 +423,8 @@ pub fn createEmpty(
         .major_subsystem_version = options.major_subsystem_version orelse 6,
         .minor_subsystem_version = options.minor_subsystem_version orelse 0,
         .lib_dirs = options.lib_dirs,
+        .entry_addr = math.cast(u32, options.entry_addr orelse 0) orelse
+            return error.EntryAddressTooBig,
     };
 
     const use_llvm = comp.config.use_llvm;
@@ -2329,8 +2332,8 @@ fn writeHeader(self: *Coff) !void {
                 .minor_operating_system_version = 0,
                 .major_image_version = 0,
                 .minor_image_version = 0,
-                .major_subsystem_version = self.major_subsystem_version,
-                .minor_subsystem_version = self.minor_subsystem_version,
+                .major_subsystem_version = @intCast(self.major_subsystem_version),
+                .minor_subsystem_version = @intCast(self.minor_subsystem_version),
                 .win32_version_value = 0,
                 .size_of_image = size_of_image,
                 .size_of_headers = size_of_headers,
@@ -2342,7 +2345,7 @@ fn writeHeader(self: *Coff) !void {
                 .size_of_heap_reserve = default_size_of_heap_reserve,
                 .size_of_heap_commit = default_size_of_heap_commit,
                 .loader_flags = 0,
-                .number_of_rva_and_sizes = @as(u32, @intCast(self.data_directories.len)),
+                .number_of_rva_and_sizes = @intCast(self.data_directories.len),
             };
             writer.writeAll(mem.asBytes(&opt_header)) catch unreachable;
         },
src/link/Dwarf.zig
@@ -1745,6 +1745,7 @@ pub fn freeDecl(self: *Dwarf, decl_index: InternPool.DeclIndex) void {
 }
 
 pub fn writeDbgAbbrev(self: *Dwarf) !void {
+    const gpa = self.allocator;
     // These are LEB encoded but since the values are all less than 127
     // we can simply append these bytes.
     // zig fmt: off
@@ -1887,7 +1888,7 @@ pub fn writeDbgAbbrev(self: *Dwarf) !void {
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
             const debug_abbrev = &wasm_file.getAtomPtr(wasm_file.debug_abbrev_atom.?).code;
-            try debug_abbrev.resize(wasm_file.base.allocator, needed_size);
+            try debug_abbrev.resize(gpa, needed_size);
             debug_abbrev.items[0..abbrev_buf.len].* = abbrev_buf;
         },
         else => unreachable,
@@ -2236,6 +2237,7 @@ fn writeDbgInfoNopsToArrayList(
 
 pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
     const comp = self.bin_file.comp;
+    const gpa = comp.gpa;
     const target = comp.root_mod.resolved_target.result;
     const target_endian = target.cpu.arch.endian();
     const ptr_width_bytes = self.ptrWidthBytes();
@@ -2301,7 +2303,7 @@ pub fn writeDbgAranges(self: *Dwarf, addr: u64, size: u64) !void {
         .wasm => {
             const wasm_file = self.bin_file.cast(File.Wasm).?;
             const debug_ranges = &wasm_file.getAtomPtr(wasm_file.debug_ranges_atom.?).code;
-            try debug_ranges.resize(wasm_file.base.allocator, needed_size);
+            try debug_ranges.resize(gpa, needed_size);
             @memcpy(debug_ranges.items[0..di_buf.items.len], di_buf.items);
         },
         else => unreachable,
src/link/Elf.zig
@@ -230,7 +230,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*Elf {
-    if (build_options.only_c) unreachable;
     const target = comp.root_mod.resolved_target.result;
     assert(target.ofmt == .elf);
 
@@ -380,6 +379,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj),
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 16777216,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse !is_native_os,
             .file = null,
@@ -1175,7 +1175,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
                 const lib_name = flag["-l".len..];
 
                 success: {
-                    if (!self.isStatic()) {
+                    if (!self.base.isStatic()) {
                         if (try self.accessLibPath(&test_path, &checked_paths, lc.crt_dir.?, lib_name, .Dynamic))
                             break :success;
                     }
@@ -1664,7 +1664,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
             try argv.append(p);
         }
     } else {
-        if (!self.isStatic()) {
+        if (!self.base.isStatic()) {
             if (target.dynamic_linker.get()) |path| {
                 try argv.append("-dynamic-linker");
                 try argv.append(path);
@@ -1742,7 +1742,7 @@ fn dumpArgv(self: *Elf, comp: *Compilation) !void {
             try argv.append("now");
         }
 
-        if (self.isStatic()) {
+        if (self.base.isStatic()) {
             try argv.append("-static");
         } else if (self.base.isDynLib()) {
             try argv.append("-shared");
@@ -2023,7 +2023,7 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
                 // TODO I think technically we should re-use the mechanism used by the frontend here.
                 // Maybe we should hoist search-strategy all the way here?
                 for (self.lib_dirs) |lib_dir| {
-                    if (!self.isStatic()) {
+                    if (!self.base.isStatic()) {
                         if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic))
                             break :success;
                     }
@@ -3598,7 +3598,7 @@ fn initSyntheticSections(self: *Elf) !void {
         // In this case, if we do generate .interp section and segment, we will get
         // a segfault in the dynamic linker trying to load a binary that is static
         // and doesn't contain .dynamic section.
-        if (self.isStatic() and !comp.config.pie) break :blk false;
+        if (self.base.isStatic() and !comp.config.pie) break :blk false;
         break :blk target.dynamic_linker.get() != null;
     };
     if (needs_interp) {
src/link/MachO.zig
@@ -155,6 +155,7 @@ frameworks: []const Framework,
 install_name: ?[]const u8,
 /// Path to entitlements file.
 entitlements: ?[]const u8,
+compatibility_version: ?std.SemanticVersion,
 
 /// When adding a new field, remember to update `hashAddFrameworks`.
 pub const Framework = struct {
@@ -185,7 +186,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*MachO {
-    if (build_options.only_c) unreachable;
     const target = comp.root_mod.resolved_target.result;
     const use_lld = build_options.have_llvm and comp.config.use_lld;
     const use_llvm = comp.config.use_llvm;
@@ -295,6 +295,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse (optimize_mode != .Debug),
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 16777216,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
@@ -315,6 +316,7 @@ pub fn createEmpty(
         .frameworks = options.frameworks,
         .install_name = options.install_name,
         .entitlements = options.entitlements,
+        .compatibility_version = options.compatibility_version,
     };
 
     if (use_llvm and comp.module != null) {
@@ -632,7 +634,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
     });
     {
         const platform = Platform.fromTarget(target);
-        const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(arena, comp);
+        const sdk_version: ?std.SemanticVersion = load_commands.inferSdkVersion(self);
         if (platform.isBuildVersionCompatible()) {
             try load_commands.writeBuildVersionLC(platform, sdk_version, lc_writer);
         } else if (platform.isVersionMinCompatible()) {
@@ -2237,10 +2239,10 @@ fn allocateGlobal(self: *MachO) !u32 {
     return index;
 }
 
-pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
-    if (self.got_table.lookup.contains(target)) return;
+pub fn addGotEntry(self: *MachO, reloc_target: SymbolWithLoc) !void {
+    if (self.got_table.lookup.contains(reloc_target)) return;
     const gpa = self.base.comp.gpa;
-    const got_index = try self.got_table.allocateEntry(gpa, target);
+    const got_index = try self.got_table.allocateEntry(gpa, reloc_target);
     if (self.got_section_index == null) {
         self.got_section_index = try self.initSection("__DATA_CONST", "__got", .{
             .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
@@ -2249,20 +2251,22 @@ pub fn addGotEntry(self: *MachO, target: SymbolWithLoc) !void {
     if (self.mode == .incremental) {
         try self.writeOffsetTableEntry(got_index);
         self.got_table_count_dirty = true;
-        self.markRelocsDirtyByTarget(target);
+        self.markRelocsDirtyByTarget(reloc_target);
     }
 }
 
-pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
-    if (self.stub_table.lookup.contains(target)) return;
-    const gpa = self.base.comp.gpa;
-    const stub_index = try self.stub_table.allocateEntry(gpa, target);
+pub fn addStubEntry(self: *MachO, reloc_target: SymbolWithLoc) !void {
+    if (self.stub_table.lookup.contains(reloc_target)) return;
+    const comp = self.base.comp;
+    const gpa = comp.gpa;
+    const cpu_arch = comp.root_mod.resolved_target.result.cpu.arch;
+    const stub_index = try self.stub_table.allocateEntry(gpa, reloc_target);
     if (self.stubs_section_index == null) {
         self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{
             .flags = macho.S_SYMBOL_STUBS |
                 macho.S_ATTR_PURE_INSTRUCTIONS |
                 macho.S_ATTR_SOME_INSTRUCTIONS,
-            .reserved2 = stubs.stubSize(target.cpu.arch),
+            .reserved2 = stubs.stubSize(cpu_arch),
         });
         self.stub_helper_section_index = try self.initSection("__TEXT", "__stub_helper", .{
             .flags = macho.S_REGULAR |
@@ -2276,14 +2280,14 @@ pub fn addStubEntry(self: *MachO, target: SymbolWithLoc) !void {
     if (self.mode == .incremental) {
         try self.writeStubTableEntry(stub_index);
         self.stub_table_count_dirty = true;
-        self.markRelocsDirtyByTarget(target);
+        self.markRelocsDirtyByTarget(reloc_target);
     }
 }
 
-pub fn addTlvPtrEntry(self: *MachO, target: SymbolWithLoc) !void {
-    if (self.tlv_ptr_table.lookup.contains(target)) return;
+pub fn addTlvPtrEntry(self: *MachO, reloc_target: SymbolWithLoc) !void {
+    if (self.tlv_ptr_table.lookup.contains(reloc_target)) return;
     const gpa = self.base.comp.gpa;
-    _ = try self.tlv_ptr_table.allocateEntry(gpa, target);
+    _ = try self.tlv_ptr_table.allocateEntry(gpa, reloc_target);
     if (self.tlv_ptr_section_index == null) {
         self.tlv_ptr_section_index = try self.initSection("__DATA", "__thread_ptrs", .{
             .flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
src/link/NvPtx.zig
@@ -31,8 +31,6 @@ pub fn createEmpty(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*NvPtx {
-    if (build_options.only_c) unreachable;
-
     const target = comp.root_mod.resolved_target.result;
     const use_lld = build_options.have_llvm and comp.config.use_lld;
     const use_llvm = comp.config.use_llvm;
@@ -55,6 +53,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse false,
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 0,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
src/link/Plan9.zig
@@ -318,6 +318,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse (optimize_mode != .Debug and output_mode != .Obj),
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 16777216,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
@@ -1314,8 +1315,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*Plan9 {
-    if (build_options.only_c) unreachable;
-
     const target = comp.root_mod.resolved_target.result;
     const use_lld = build_options.have_llvm and comp.config.use_lld;
     const use_llvm = comp.config.use_llvm;
@@ -1525,7 +1524,13 @@ pub fn getDeclVAddr(
     return undefined;
 }
 
-pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+pub fn lowerAnonDecl(
+    self: *Plan9,
+    decl_val: InternPool.Index,
+    explicit_alignment: InternPool.Alignment,
+    src_loc: Module.SrcLoc,
+) !codegen.Result {
+    _ = explicit_alignment;
     // This is basically the same as lowerUnnamedConst.
     // example:
     // const ty = mod.intern_pool.typeOf(decl_val).toType();
src/link/SpirV.zig
@@ -24,7 +24,6 @@ const SpirV = @This();
 
 const std = @import("std");
 const Allocator = std.mem.Allocator;
-const ArenaAllocator = std.heap.ArenaAllocator;
 const assert = std.debug.assert;
 const log = std.log.scoped(.link);
 
@@ -65,6 +64,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse false,
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse 0,
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
@@ -98,8 +98,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*SpirV {
-    if (build_options.only_c) unreachable;
-
     const target = comp.root_mod.resolved_target.result;
     const use_lld = build_options.have_llvm and comp.config.use_lld;
     const use_llvm = comp.config.use_llvm;
@@ -194,7 +192,9 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
 
     const spv = &self.object.spv;
 
+    const gpa = comp.gpa;
     const target = comp.getTarget();
+
     try writeCapabilities(spv, target);
     try writeMemoryModel(spv, target);
 
@@ -214,11 +214,11 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
         // name if it contains no strange characters is nice for debugging. URI encoding fits the bill.
         // We're using : as separator, which is a reserved character.
 
-        const escaped_name = try std.Uri.escapeString(self.base.allocator, name);
-        defer self.base.allocator.free(escaped_name);
+        const escaped_name = try std.Uri.escapeString(gpa, name);
+        defer gpa.free(escaped_name);
         try error_info.writer().print(":{s}", .{escaped_name});
     }
-    try spv.sections.debug_strings.emit(spv.gpa, .OpSourceExtension, .{
+    try spv.sections.debug_strings.emit(gpa, .OpSourceExtension, .{
         .extension = error_info.items,
     });
 
@@ -226,6 +226,7 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No
 }
 
 fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
+    const gpa = spv.gpa;
     // TODO: Integrate with a hypothetical feature system
     const caps: []const spec.Capability = switch (target.os.tag) {
         .opencl => &.{ .Kernel, .Addresses, .Int8, .Int16, .Int64, .Float64, .Float16, .GenericPointer },
@@ -235,13 +236,15 @@ fn writeCapabilities(spv: *SpvModule, target: std.Target) !void {
     };
 
     for (caps) |cap| {
-        try spv.sections.capabilities.emit(spv.gpa, .OpCapability, .{
+        try spv.sections.capabilities.emit(gpa, .OpCapability, .{
             .capability = cap,
         });
     }
 }
 
 fn writeMemoryModel(spv: *SpvModule, target: std.Target) !void {
+    const gpa = spv.gpa;
+
     const addressing_model = switch (target.os.tag) {
         .opencl => switch (target.cpu.arch) {
             .spirv32 => spec.AddressingModel.Physical32,
@@ -260,7 +263,7 @@ fn writeMemoryModel(spv: *SpvModule, target: std.Target) !void {
     };
 
     // TODO: Put this in a proper section.
-    try spv.sections.extensions.emit(spv.gpa, .OpMemoryModel, .{
+    try spv.sections.extensions.emit(gpa, .OpMemoryModel, .{
         .addressing_model = addressing_model,
         .memory_model = memory_model,
     });
src/link/Wasm.zig
@@ -378,7 +378,6 @@ pub fn open(
     emit: Compilation.Emit,
     options: link.File.OpenOptions,
 ) !*Wasm {
-    if (build_options.only_c) unreachable;
     const gpa = comp.gpa;
     const target = comp.root_mod.resolved_target.result;
     assert(target.ofmt == .wasm);
@@ -549,6 +548,7 @@ pub fn createEmpty(
             .comp = comp,
             .emit = emit,
             .gc_sections = options.gc_sections orelse (output_mode != .Obj),
+            .print_gc_sections = options.print_gc_sections,
             .stack_size = options.stack_size orelse std.wasm.page_size * 16, // 1MB
             .allow_shlib_undefined = options.allow_shlib_undefined orelse false,
             .file = null,
@@ -1893,7 +1893,12 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
     return target_symbol_index;
 }
 
-pub fn deleteDeclExport(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
+pub fn deleteDeclExport(
+    wasm: *Wasm,
+    decl_index: InternPool.DeclIndex,
+    name: InternPool.NullTerminatedString,
+) void {
+    _ = name;
     if (wasm.llvm_object) |_| return;
     const atom_index = wasm.decls.get(decl_index) orelse return;
     const sym_index = wasm.getAtom(atom_index).sym_index;
src/Compilation.zig
@@ -229,7 +229,7 @@ pub const Emit = struct {
 
     /// Returns the full path to `basename` if it were in the same directory as the
     /// `Emit` sub_path.
-    pub fn basenamePath(emit: Emit, arena: Allocator, basename: [:0]const u8) ![:0]const u8 {
+    pub fn basenamePath(emit: Emit, arena: Allocator, basename: []const u8) ![:0]const u8 {
         const full_path = if (emit.directory.path) |p|
             try std.fs.path.join(arena, &[_][]const u8{ p, emit.sub_path })
         else
@@ -238,7 +238,7 @@ pub const Emit = struct {
         if (std.fs.path.dirname(full_path)) |dirname| {
             return try std.fs.path.joinZ(arena, &.{ dirname, basename });
         } else {
-            return basename;
+            return try arena.dupeZ(u8, basename);
         }
     }
 };
@@ -1038,8 +1038,8 @@ pub const InitOptions = struct {
     linker_compress_debug_sections: ?link.File.Elf.CompressDebugSections = null,
     linker_module_definition_file: ?[]const u8 = null,
     linker_sort_section: ?link.File.Elf.SortSection = null,
-    major_subsystem_version: ?u32 = null,
-    minor_subsystem_version: ?u32 = null,
+    major_subsystem_version: ?u16 = null,
+    minor_subsystem_version: ?u16 = null,
     clang_passthrough_mode: bool = false,
     verbose_cc: bool = false,
     verbose_link: bool = false,
src/link.zig
@@ -61,6 +61,7 @@ pub const File = struct {
     intermediary_basename: ?[]const u8 = null,
     disable_lld_caching: bool,
     gc_sections: bool,
+    print_gc_sections: bool,
     build_id: std.zig.BuildId,
     rpath_list: []const []const u8,
     /// List of symbols forced as undefined in the symbol table
@@ -114,8 +115,8 @@ pub const File = struct {
         disable_lld_caching: bool,
         hash_style: Elf.HashStyle,
         sort_section: ?Elf.SortSection,
-        major_subsystem_version: ?u32,
-        minor_subsystem_version: ?u32,
+        major_subsystem_version: ?u16,
+        minor_subsystem_version: ?u16,
         gc_sections: ?bool,
         allow_shlib_undefined: ?bool,
         subsystem: ?std.Target.SubSystem,
@@ -181,9 +182,15 @@ pub const File = struct {
         emit: Compilation.Emit,
         options: OpenOptions,
     ) !*File {
-        switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
-            inline else => |tag| {
-                const ptr = try tag.Type().open(arena, comp, emit, options);
+        const tag = Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt);
+        switch (tag) {
+            .c => {
+                const ptr = try C.open(arena, comp, emit, options);
+                return &ptr.base;
+            },
+            inline else => |t| {
+                if (build_options.only_c) unreachable;
+                const ptr = try t.Type().open(arena, comp, emit, options);
                 return &ptr.base;
             },
         }
@@ -195,9 +202,15 @@ pub const File = struct {
         emit: Compilation.Emit,
         options: OpenOptions,
     ) !*File {
-        switch (Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt)) {
-            inline else => |tag| {
-                const ptr = try tag.Type().createEmpty(arena, comp, emit, options);
+        const tag = Tag.fromObjectFormat(comp.root_mod.resolved_target.result.ofmt);
+        switch (tag) {
+            .c => {
+                const ptr = try C.createEmpty(arena, comp, emit, options);
+                return &ptr.base;
+            },
+            inline else => |t| {
+                if (build_options.only_c) unreachable;
+                const ptr = try t.Type().createEmpty(arena, comp, emit, options);
                 return &ptr.base;
             },
         }
@@ -360,16 +373,12 @@ pub const File = struct {
     pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: InternPool.DeclIndex) UpdateDeclError!u32 {
         if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
-            // zig fmt: off
-            .coff  => return @fieldParentPtr(Coff,  "base", base).lowerUnnamedConst(tv, decl_index),
-            .elf   => return @fieldParentPtr(Elf,   "base", base).lowerUnnamedConst(tv, decl_index),
-            .macho => return @fieldParentPtr(MachO, "base", base).lowerUnnamedConst(tv, decl_index),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerUnnamedConst(tv, decl_index),
             .spirv => unreachable,
-            .c     => unreachable,
-            .wasm  => return @fieldParentPtr(Wasm,  "base", base).lowerUnnamedConst(tv, decl_index),
+            .c => unreachable,
             .nvptx => unreachable,
-            // zig fmt: on
+            inline else => |t| {
+                return @fieldParentPtr(t.Type(), "base", base).lowerUnnamedConst(tv, decl_index);
+            },
         }
     }
 
@@ -382,16 +391,13 @@ pub const File = struct {
         if (build_options.only_c) @compileError("unreachable");
         log.debug("getGlobalSymbol '{s}' (expected in '{?s}')", .{ name, lib_name });
         switch (base.tag) {
-            // zig fmt: off
-            .coff  => return @fieldParentPtr(Coff, "base", base).getGlobalSymbol(name, lib_name),
-            .elf   => return @fieldParentPtr(Elf, "base", base).getGlobalSymbol(name, lib_name),
-            .macho => return @fieldParentPtr(MachO, "base", base).getGlobalSymbol(name, lib_name),
             .plan9 => unreachable,
             .spirv => unreachable,
-            .c     => unreachable,
-            .wasm  => return @fieldParentPtr(Wasm,  "base", base).getGlobalSymbol(name, lib_name),
+            .c => unreachable,
             .nvptx => unreachable,
-            // zig fmt: on
+            inline else => |t| {
+                return @fieldParentPtr(t.Type(), "base", base).getGlobalSymbol(name, lib_name);
+            },
         }
     }
 
@@ -399,59 +405,48 @@ pub const File = struct {
     pub fn updateDecl(base: *File, module: *Module, decl_index: InternPool.DeclIndex) UpdateDeclError!void {
         const decl = module.declPtr(decl_index);
         assert(decl.has_tv);
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index);
-        }
         switch (base.tag) {
-            // zig fmt: off
-            .coff  => return @fieldParentPtr(Coff,  "base", base).updateDecl(module, decl_index),
-            .elf   => return @fieldParentPtr(Elf,   "base", base).updateDecl(module, decl_index),
-            .macho => return @fieldParentPtr(MachO, "base", base).updateDecl(module, decl_index),
-            .c     => return @fieldParentPtr(C,     "base", base).updateDecl(module, decl_index),
-            .wasm  => return @fieldParentPtr(Wasm,  "base", base).updateDecl(module, decl_index),
-            .spirv => return @fieldParentPtr(SpirV, "base", base).updateDecl(module, decl_index),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDecl(module, decl_index),
-            .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDecl(module, decl_index),
-            // zig fmt: on
+            .c => {
+                return @fieldParentPtr(C, "base", base).updateDecl(module, decl_index);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                return @fieldParentPtr(tag.Type(), "base", base).updateDecl(module, decl_index);
+            },
         }
     }
 
     /// May be called before or after updateExports for any given Decl.
-    pub fn updateFunc(base: *File, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) UpdateDeclError!void {
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness);
-        }
+    pub fn updateFunc(
+        base: *File,
+        module: *Module,
+        func_index: InternPool.Index,
+        air: Air,
+        liveness: Liveness,
+    ) UpdateDeclError!void {
         switch (base.tag) {
-            // zig fmt: off
-            .coff  => return @fieldParentPtr(Coff,  "base", base).updateFunc(module, func_index, air, liveness),
-            .elf   => return @fieldParentPtr(Elf,   "base", base).updateFunc(module, func_index, air, liveness),
-            .macho => return @fieldParentPtr(MachO, "base", base).updateFunc(module, func_index, air, liveness),
-            .c     => return @fieldParentPtr(C,     "base", base).updateFunc(module, func_index, air, liveness),
-            .wasm  => return @fieldParentPtr(Wasm,  "base", base).updateFunc(module, func_index, air, liveness),
-            .spirv => return @fieldParentPtr(SpirV, "base", base).updateFunc(module, func_index, air, liveness),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).updateFunc(module, func_index, air, liveness),
-            .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateFunc(module, func_index, air, liveness),
-            // zig fmt: on
+            .c => {
+                return @fieldParentPtr(C, "base", base).updateFunc(module, func_index, air, liveness);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                return @fieldParentPtr(tag.Type(), "base", base).updateFunc(module, func_index, air, liveness);
+            },
         }
     }
 
     pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: InternPool.DeclIndex) UpdateDeclError!void {
         const decl = module.declPtr(decl_index);
         assert(decl.has_tv);
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index);
-        }
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl_index),
-            .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl_index),
-            .macho => return @fieldParentPtr(MachO, "base", base).updateDeclLineNumber(module, decl_index),
-            .c => return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index),
-            .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclLineNumber(module, decl_index),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclLineNumber(module, decl_index),
             .spirv, .nvptx => {},
+            .c => {
+                return @fieldParentPtr(C, "base", base).updateDeclLineNumber(module, decl_index);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                return @fieldParentPtr(tag.Type(), "base", base).updateDeclLineNumber(module, decl_index);
+            },
         }
     }
 
@@ -477,44 +472,11 @@ pub const File = struct {
             base.misc_errors.deinit(gpa);
         }
         switch (base.tag) {
-            .coff => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(Coff, "base", base);
-                parent.deinit();
-            },
-            .elf => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(Elf, "base", base);
-                parent.deinit();
-            },
-            .macho => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(MachO, "base", base);
-                parent.deinit();
-            },
-            .c => {
-                const parent = @fieldParentPtr(C, "base", base);
-                parent.deinit();
-            },
-            .wasm => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(Wasm, "base", base);
-                parent.deinit();
-            },
-            .spirv => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(SpirV, "base", base);
-                parent.deinit();
-            },
-            .plan9 => {
-                if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(Plan9, "base", base);
-                parent.deinit();
-            },
-            .nvptx => {
+            .c => @fieldParentPtr(C, "base", base).deinit(),
+
+            inline else => |tag| {
                 if (build_options.only_c) unreachable;
-                const parent = @fieldParentPtr(NvPtx, "base", base);
-                parent.deinit();
+                @fieldParentPtr(tag.Type(), "base", base).deinit();
             },
         }
     }
@@ -619,51 +581,36 @@ pub const File = struct {
             return base.linkAsArchive(comp, prog_node);
         }
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).flush(comp, prog_node),
-            .elf => return @fieldParentPtr(Elf, "base", base).flush(comp, prog_node),
-            .macho => return @fieldParentPtr(MachO, "base", base).flush(comp, prog_node),
-            .c => return @fieldParentPtr(C, "base", base).flush(comp, prog_node),
-            .wasm => return @fieldParentPtr(Wasm, "base", base).flush(comp, prog_node),
-            .spirv => return @fieldParentPtr(SpirV, "base", base).flush(comp, prog_node),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).flush(comp, prog_node),
-            .nvptx => return @fieldParentPtr(NvPtx, "base", base).flush(comp, prog_node),
+            inline else => |tag| {
+                return @fieldParentPtr(tag.Type(), "base", base).flush(comp, prog_node);
+            },
         }
     }
 
     /// Commit pending changes and write headers. Works based on `effectiveOutputMode`
     /// rather than final output mode.
     pub fn flushModule(base: *File, comp: *Compilation, prog_node: *std.Progress.Node) FlushError!void {
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node);
-        }
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).flushModule(comp, prog_node),
-            .elf => return @fieldParentPtr(Elf, "base", base).flushModule(comp, prog_node),
-            .macho => return @fieldParentPtr(MachO, "base", base).flushModule(comp, prog_node),
-            .c => return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node),
-            .wasm => return @fieldParentPtr(Wasm, "base", base).flushModule(comp, prog_node),
-            .spirv => return @fieldParentPtr(SpirV, "base", base).flushModule(comp, prog_node),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).flushModule(comp, prog_node),
-            .nvptx => return @fieldParentPtr(NvPtx, "base", base).flushModule(comp, prog_node),
+            .c => {
+                return @fieldParentPtr(C, "base", base).flushModule(comp, prog_node);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                return @fieldParentPtr(tag.Type(), "base", base).flushModule(comp, prog_node);
+            },
         }
     }
 
     /// Called when a Decl is deleted from the Module.
     pub fn freeDecl(base: *File, decl_index: InternPool.DeclIndex) void {
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).freeDecl(decl_index);
-        }
         switch (base.tag) {
-            .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl_index),
-            .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl_index),
-            .macho => @fieldParentPtr(MachO, "base", base).freeDecl(decl_index),
-            .c => @fieldParentPtr(C, "base", base).freeDecl(decl_index),
-            .wasm => @fieldParentPtr(Wasm, "base", base).freeDecl(decl_index),
-            .spirv => @fieldParentPtr(SpirV, "base", base).freeDecl(decl_index),
-            .plan9 => @fieldParentPtr(Plan9, "base", base).freeDecl(decl_index),
-            .nvptx => @fieldParentPtr(NvPtx, "base", base).freeDecl(decl_index),
+            .c => {
+                @fieldParentPtr(C, "base", base).freeDecl(decl_index);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                @fieldParentPtr(tag.Type(), "base", base).freeDecl(decl_index);
+            },
         }
     }
 
@@ -682,19 +629,14 @@ pub const File = struct {
         exported: Module.Exported,
         exports: []const *Module.Export,
     ) UpdateExportsError!void {
-        if (build_options.only_c) {
-            assert(base.tag == .c);
-            return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports);
-        }
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).updateExports(module, exported, exports),
-            .elf => return @fieldParentPtr(Elf, "base", base).updateExports(module, exported, exports),
-            .macho => return @fieldParentPtr(MachO, "base", base).updateExports(module, exported, exports),
-            .c => return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports),
-            .wasm => return @fieldParentPtr(Wasm, "base", base).updateExports(module, exported, exports),
-            .spirv => return @fieldParentPtr(SpirV, "base", base).updateExports(module, exported, exports),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).updateExports(module, exported, exports),
-            .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateExports(module, exported, exports),
+            .c => {
+                return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports);
+            },
+            inline else => |tag| {
+                if (build_options.only_c) unreachable;
+                return @fieldParentPtr(tag.Type(), "base", base).updateExports(module, exported, exports);
+            },
         }
     }
 
@@ -711,60 +653,64 @@ pub const File = struct {
     /// May be called before or after updateFunc/updateDecl therefore it is up to the linker to allocate
     /// the block/atom.
     pub fn getDeclVAddr(base: *File, decl_index: InternPool.DeclIndex, reloc_info: RelocInfo) !u64 {
-        if (build_options.only_c) unreachable;
+        if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl_index, reloc_info),
-            .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl_index, reloc_info),
-            .macho => return @fieldParentPtr(MachO, "base", base).getDeclVAddr(decl_index, reloc_info),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).getDeclVAddr(decl_index, reloc_info),
             .c => unreachable,
-            .wasm => return @fieldParentPtr(Wasm, "base", base).getDeclVAddr(decl_index, reloc_info),
             .spirv => unreachable,
             .nvptx => unreachable,
+            inline else => |tag| {
+                return @fieldParentPtr(tag.Type(), "base", base).getDeclVAddr(decl_index, reloc_info);
+            },
         }
     }
 
     pub const LowerResult = @import("codegen.zig").Result;
 
-    pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, decl_align: InternPool.Alignment, src_loc: Module.SrcLoc) !LowerResult {
-        if (build_options.only_c) unreachable;
+    pub fn lowerAnonDecl(
+        base: *File,
+        decl_val: InternPool.Index,
+        decl_align: InternPool.Alignment,
+        src_loc: Module.SrcLoc,
+    ) !LowerResult {
+        if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc),
-            .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc),
-            .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc),
             .c => unreachable,
-            .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, decl_align, src_loc),
             .spirv => unreachable,
             .nvptx => unreachable,
+            inline else => |tag| {
+                return @fieldParentPtr(tag.Type(), "base", base).lowerAnonDecl(decl_val, decl_align, src_loc);
+            },
         }
     }
 
     pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
-        if (build_options.only_c) unreachable;
+        if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
-            .elf => return @fieldParentPtr(Elf, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
-            .macho => return @fieldParentPtr(MachO, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
-            .plan9 => return @fieldParentPtr(Plan9, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
             .c => unreachable,
-            .wasm => return @fieldParentPtr(Wasm, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
             .spirv => unreachable,
             .nvptx => unreachable,
+            inline else => |tag| {
+                return @fieldParentPtr(tag.Type(), "base", base).getAnonDeclVAddr(decl_val, reloc_info);
+            },
         }
     }
 
-    pub fn deleteDeclExport(base: *File, decl_index: InternPool.DeclIndex, name: InternPool.NullTerminatedString) !void {
-        if (build_options.only_c) unreachable;
+    pub fn deleteDeclExport(
+        base: *File,
+        decl_index: InternPool.DeclIndex,
+        name: InternPool.NullTerminatedString,
+    ) !void {
+        if (build_options.only_c) @compileError("unreachable");
         switch (base.tag) {
-            .coff => return @fieldParentPtr(Coff, "base", base).deleteDeclExport(decl_index, name),
-            .elf => return @fieldParentPtr(Elf, "base", base).deleteDeclExport(decl_index, name),
-            .macho => return @fieldParentPtr(MachO, "base", base).deleteDeclExport(decl_index, name),
-            .plan9 => {},
-            .c => {},
-            .wasm => return @fieldParentPtr(Wasm, "base", base).deleteDeclExport(decl_index),
-            .spirv => {},
-            .nvptx => {},
+            .plan9,
+            .c,
+            .spirv,
+            .nvptx,
+            => {},
+
+            inline else => |tag| {
+                return @fieldParentPtr(tag.Type(), "base", base).deleteDeclExport(decl_index, name);
+            },
         }
     }
 
@@ -1049,7 +995,7 @@ pub const File = struct {
         base: File,
         arena: Allocator,
         opt_loc: ?Compilation.EmitLoc,
-    ) Allocator.Error!?[*:0]u8 {
+    ) Allocator.Error!?[*:0]const u8 {
         const loc = opt_loc orelse return null;
         const slice = if (loc.directory) |directory|
             try directory.joinZ(arena, &.{loc.basename})
@@ -1071,7 +1017,7 @@ pub const File = struct {
         sub_prog_node.context.refresh();
         defer sub_prog_node.end();
 
-        try llvm_object.emit(comp, .{
+        try llvm_object.emit(.{
             .pre_ir_path = comp.verbose_llvm_ir,
             .pre_bc_path = comp.verbose_llvm_bc,
             .bin_path = try base.resolveEmitLoc(arena, .{
@@ -1079,8 +1025,8 @@ pub const File = struct {
                 .basename = base.intermediary_basename.?,
             }),
             .asm_path = try base.resolveEmitLoc(arena, comp.emit_asm),
-            .post_llvm_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir),
-            .post_llvm_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc),
+            .post_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir),
+            .post_bc_path = try base.resolveEmitLoc(arena, comp.emit_llvm_bc),
 
             .is_debug = comp.root_mod.optimize_mode == .Debug,
             .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
src/main.zig
@@ -874,8 +874,8 @@ fn buildOutputType(
     var override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
     var clang_preprocessor_mode: Compilation.ClangPreprocessorMode = .no;
     var subsystem: ?std.Target.SubSystem = null;
-    var major_subsystem_version: ?u32 = null;
-    var minor_subsystem_version: ?u32 = null;
+    var major_subsystem_version: ?u16 = null;
+    var minor_subsystem_version: ?u16 = null;
     var enable_link_snapshots: bool = false;
     var debug_incremental: bool = false;
     var install_name: ?[]const u8 = null;
@@ -2321,21 +2321,17 @@ fn buildOutputType(
                     _ = linker_args_it.nextOrFatal();
                 } else if (mem.eql(u8, arg, "--major-subsystem-version")) {
                     const major = linker_args_it.nextOrFatal();
-                    major_subsystem_version = std.fmt.parseUnsigned(
-                        u32,
-                        major,
-                        10,
-                    ) catch |err| {
-                        fatal("unable to parse major subsystem version '{s}': {s}", .{ major, @errorName(err) });
+                    major_subsystem_version = std.fmt.parseUnsigned(u16, major, 10) catch |err| {
+                        fatal("unable to parse major subsystem version '{s}': {s}", .{
+                            major, @errorName(err),
+                        });
                     };
                 } else if (mem.eql(u8, arg, "--minor-subsystem-version")) {
                     const minor = linker_args_it.nextOrFatal();
-                    minor_subsystem_version = std.fmt.parseUnsigned(
-                        u32,
-                        minor,
-                        10,
-                    ) catch |err| {
-                        fatal("unable to parse minor subsystem version '{s}': {s}", .{ minor, @errorName(err) });
+                    minor_subsystem_version = std.fmt.parseUnsigned(u16, minor, 10) catch |err| {
+                        fatal("unable to parse minor subsystem version '{s}': {s}", .{
+                            minor, @errorName(err),
+                        });
                     };
                 } else if (mem.eql(u8, arg, "-framework")) {
                     try frameworks.put(arena, linker_args_it.nextOrFatal(), .{});
src/Module.zig
@@ -4309,14 +4309,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
     decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
     decl.zir_decl_index = @enumFromInt(decl_sub_index);
     if (decl.getOwnedFunction(mod) != null) {
-        switch (comp.bin_file.tag) {
-            .coff, .elf, .macho, .plan9 => {
-                // TODO Look into detecting when this would be unnecessary by storing enough state
-                // in `Decl` to notice that the line number did not change.
-                comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
-            },
-            .c, .wasm, .spirv, .nvptx => {},
-        }
+        // TODO Look into detecting when this would be unnecessary by storing enough state
+        // in `Decl` to notice that the line number did not change.
+        comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
     }
 }
 
src/Sema.zig
@@ -20043,7 +20043,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
 
     if (sema.owner_func_index != .none and
         ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn and
-        mod.ownerModule().error_tracing and
+        block.ownerModule().error_tracing and
         mod.backendSupportsFeature(.error_return_trace))
     {
         return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);