authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-10-14 10:21:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-10-21 10:04:01-07:00
log203bbaee07dfd8e67ea102dbb29afb75be246e53
treea9f4352e17246561d99119cbbb5d4e5198456f07
parentf08a8f0fc217914690a58035291da8bcc7a86e47

main: support multiple non-incremental protocol update messages


5 files changed, 475 insertions(+), 344 deletions(-)

src/Compilation.zig+178-139
...@@ -20,7 +20,6 @@ const link = @import("link.zig");...@@ -20,7 +20,6 @@ const link = @import("link.zig");
20const tracy = @import("tracy.zig");20const tracy = @import("tracy.zig");
21const trace = tracy.trace;21const trace = tracy.trace;
22const build_options = @import("build_options");22const build_options = @import("build_options");
23const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
24const LibCInstallation = std.zig.LibCInstallation;23const LibCInstallation = std.zig.LibCInstallation;
25const glibc = @import("libs/glibc.zig");24const glibc = @import("libs/glibc.zig");
26const musl = @import("libs/musl.zig");25const musl = @import("libs/musl.zig");
...@@ -148,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma...@@ -148,6 +147,7 @@ failed_win32_resources: if (dev.env.supports(.win32_resource)) std.array_hash_ma
148 pub fn values(_: @This()) [0]void {147 pub fn values(_: @This()) [0]void {
149 return .{};148 return .{};
150 }149 }
150 pub fn clearRetainingCapacity(_: @This()) void {}
151 pub fn deinit(_: @This(), _: Allocator) void {}151 pub fn deinit(_: @This(), _: Allocator) void {}
152} = .{},152} = .{},
153153
...@@ -238,8 +238,6 @@ reference_trace: ?u32 = null,...@@ -238,8 +238,6 @@ reference_trace: ?u32 = null,
238/// This mutex guards all `Compilation` mutable state.238/// This mutex guards all `Compilation` mutable state.
239mutex: std.Io.Mutex = .init,239mutex: std.Io.Mutex = .init,
240240
241test_filters: []const []const u8,
242
243link_prog_node: std.Progress.Node = .none,241link_prog_node: std.Progress.Node = .none,
244242
245llvm_opt_bisect_limit: c_int,243llvm_opt_bisect_limit: c_int,
...@@ -1635,28 +1633,11 @@ pub const CreateOptions = struct {...@@ -1635,28 +1633,11 @@ pub const CreateOptions = struct {
1635 };1633 };
1636};1634};
16371635
1638fn addModuleTableToCacheHash(zcu: *Zcu, hash: *Cache.HashHelper) error{ OutOfMemory, Unexpected }!void {
1639 assert(zcu.module_roots.count() != 0); // module_roots is populated
1640
1641 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| {
1642 if (mod == zcu.std_mod) continue; // redundant
1643 if (opt_mod_root_file.unwrap()) |mod_root_file| {
1644 if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant
1645 }
1646 cache_helpers.addModule(hash, mod);
1647 hash.add(mod.root.root);
1648 hash.addBytes(mod.root.sub_path);
1649 hash.addBytes(mod.root_src_path);
1650 hash.addListOfBytes(mod.deps.keys());
1651 }
1652}
1653
1654const RtStrat = enum { none, lib, obj, zcu };1636const RtStrat = enum { none, lib, obj, zcu };
16551637
1656pub const CreateDiagnostic = union(enum) {1638pub const CreateDiagnostic = union(enum) {
1657 export_table_import_table_conflict,1639 export_table_import_table_conflict,
1658 emit_h_without_zcu,1640 emit_h_without_zcu,
1659 illegal_zig_import,
1660 cross_libc_unavailable,1641 cross_libc_unavailable,
1661 find_native_libc: std.zig.LibCInstallation.FindError,1642 find_native_libc: std.zig.LibCInstallation.FindError,
1662 libc_installation_missing_cc_dir,1643 libc_installation_missing_cc_dir,
...@@ -1672,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) {...@@ -1672,7 +1653,6 @@ pub const CreateDiagnostic = union(enum) {
1672 switch (diag) {1653 switch (diag) {
1673 .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"),1654 .export_table_import_table_conflict => try w.writeAll("'--import-table' and '--export-table' cannot be used together"),
1674 .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"),1655 .emit_h_without_zcu => try w.writeAll("cannot emit C header with no Zig source files"),
1675 .illegal_zig_import => try w.writeAll("this compiler implementation does not support importing the root source file of a provided module"),
1676 .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"),1656 .cross_libc_unavailable => try w.writeAll("unable to provide libc for this target"),
1677 .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}),1657 .find_native_libc => |err| try w.print("failed to find libc installation: {t}", .{err}),
1678 .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"),1658 .libc_installation_missing_cc_dir => try w.writeAll("libc installation is missing cc directory"),
...@@ -1720,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1720,7 +1700,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1720 const use_llvm = options.config.use_llvm;1700 const use_llvm = options.config.use_llvm;
1721 const target = &options.root_mod.resolved_target.result;1701 const target = &options.root_mod.resolved_target.result;
17221702
1723 const comp: *Compilation = comp: {1703 const comp = comp: {
1724 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.1704 // We put the `Compilation` itself in the arena. Freeing the arena will free the module.
1725 // It's initialized later after we prepare the initialization options.1705 // It's initialized later after we prepare the initialization options.
1726 const root_name = try arena.dupeSentinel(u8, options.root_name, 0);1706 const root_name = try arena.dupeSentinel(u8, options.root_name, 0);
...@@ -1988,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -1988,7 +1968,7 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
1988 // TODO audit this and make sure everything is in it1968 // TODO audit this and make sure everything is in it
19891969
1990 const comp = try arena.create(Compilation);1970 const comp = try arena.create(Compilation);
1991 const opt_zcu: ?*Zcu = if (have_zcu) blk: {1971 const opt_zcu = if (have_zcu) blk: {
1992 // Pre-open the directory handles for cached ZIR code so that it does not need1972 // Pre-open the directory handles for cached ZIR code so that it does not need
1993 // to redundantly happen for each AstGen operation.1973 // to redundantly happen for each AstGen operation.
1994 const zir_sub_dir = "z";1974 const zir_sub_dir = "z";
...@@ -2041,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2041,19 +2021,95 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2041 zcu.* = .{2021 zcu.* = .{
2042 .gpa = gpa,2022 .gpa = gpa,
2043 .comp = comp,2023 .comp = comp,
2044 .main_mod = main_mod,2024 .llvm_object = null,
2025
2045 .root_mod = options.root_mod,2026 .root_mod = options.root_mod,
2027 .main_mod = main_mod,
2046 .std_mod = std_mod,2028 .std_mod = std_mod,
2029 .sema_prog_node = .none,
2030 .codegen_prog_node = .none,
2031 .pending_codegen_jobs = .init(0),
2032
2033 .cur_sema_prog_node = .none,
2034
2047 .global_zir_cache = global_zir_cache,2035 .global_zir_cache = global_zir_cache,
2048 .local_zir_cache = local_zir_cache,2036 .local_zir_cache = local_zir_cache,
2037
2038 .all_exports = .empty,
2039 .free_exports = .empty,
2040 .single_exports = .empty,
2041 .multi_exports = .empty,
2042
2043 .module_roots = .empty,
2044 .builtin_modules = .empty,
2045
2046 .import_table = .empty,
2047 .alive_files = .empty,
2048 .embed_table = .empty,
2049
2050 .intern_pool = .empty,
2051
2052 .compile_logs = .empty,
2053 .compile_log_lines = .empty,
2054 .free_compile_log_lines = .empty,
2055
2056 .illegal_module_root = null,
2057 .multi_module_err = null,
2058 .failed_imports = .empty,
2059 .failed_files = .empty,
2060 .skip_analysis_this_update = false,
2061 .analysis_in_progress = .empty,
2062 .failed_analysis = .empty,
2063 .transitive_failed_analysis = .empty,
2064 .dependency_loops = .empty,
2065 .dependency_loop_nodes = .empty,
2066 .failed_codegen = .empty,
2067 .failed_types = .empty,
2068 .failed_exports = .empty,
2069
2049 .error_limit = error_limit,2070 .error_limit = error_limit,
2050 .llvm_object = null,2071
2072 .outdated_lock = if (std.debug.runtime_safety) .init,
2073 .potentially_outdated = .empty,
2074 .outdated = .empty,
2075 .outdated_ready = .{
2076 .funcs = .empty,
2077 .other = .empty,
2078 },
2079 .retryable_failures = .empty,
2080
2051 .analysis_roots_buffer = undefined,2081 .analysis_roots_buffer = undefined,
2052 .analysis_roots_len = 0,2082 .analysis_roots_len = 0,
2083 .resolved_references = null,
2084
2085 .test_filters = options.test_filters,
2086 .test_functions = .empty,
2087
2088 .global_assembly = .empty,
2089
2090 .reference_table = .empty,
2091 .all_references = .empty,
2092 .free_references = .empty,
2093
2094 .inline_reference_frames = .empty,
2095 .free_inline_reference_frames = .empty,
2096
2097 .type_reference_table = .empty,
2098 .all_type_references = .empty,
2099 .free_type_references = .empty,
2100
2101 .std_lang_decl_values = .initFill(.none),
2102
2103 .incremental_debug_state = if (build_options.enable_debug_extensions) .init,
2104
2105 .cur_analysis_timer = null,
2106
2053 .codegen_task_pool = try .init(arena),2107 .codegen_task_pool = try .init(arena),
2108
2109 .generation = 0,
2110
2054 .anon_name_counter = 0,2111 .anon_name_counter = 0,
2055 };2112 };
2056 try zcu.init(gpa, io, options.thread_limit);
2057 break :blk zcu;2113 break :blk zcu;
2058 } else blk: {2114 } else blk: {
2059 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu);2115 if (options.emit_h != .no) return diag.fail(.emit_h_without_zcu);
...@@ -2091,7 +2147,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2091,7 +2147,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2091 .reference_trace = options.reference_trace,2147 .reference_trace = options.reference_trace,
2092 .time_report = if (options.time_report) .init else null,2148 .time_report = if (options.time_report) .init else null,
2093 .stack_report = options.stack_report,2149 .stack_report = options.stack_report,
2094 .test_filters = options.test_filters,
2095 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,2150 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
2096 .debug_compile_errors = options.debug_compile_errors,2151 .debug_compile_errors = options.debug_compile_errors,
2097 .debug_incremental = options.debug_incremental,2152 .debug_incremental = options.debug_incremental,
...@@ -2143,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2143,18 +2198,8 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2143 comp.config.any_sanitize_c = any_sanitize_c;2198 comp.config.any_sanitize_c = any_sanitize_c;
2144 comp.config.any_fuzz = any_fuzz;2199 comp.config.any_fuzz = any_fuzz;
21452200
2146 if (opt_zcu) |zcu| {2201 // Initialize the `zcu` after the fields on `comp` have been initialized.
2147 // Finish initializing the `zcu` after the fields on `comp` have been initialized.2202 if (opt_zcu) |zcu| zcu.init();
2148 zcu.initAfterCompilation();
2149
2150 // Populate `zcu.module_roots`.
2151 const active = zcu.acquire();
2152 defer active.release();
2153 active.pt.populateModuleRootTable() catch |err| switch (err) {
2154 error.OutOfMemory => |e| return e,
2155 error.IllegalZigImport => return diag.fail(.illegal_zig_import),
2156 };
2157 }
21582203
2159 const lf_open_opts: link.File.OpenOptions = .{2204 const lf_open_opts: link.File.OpenOptions = .{
2160 .linker_script = options.linker_script,2205 .linker_script = options.linker_script,
...@@ -2250,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2250,20 +2295,10 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2250 hash.add(options.config.is_test);2295 hash.add(options.config.is_test);
2251 hash.addListOfBytes(options.test_filters);2296 hash.addListOfBytes(options.test_filters);
2252 hash.add(options.skip_linker_dependencies);2297 hash.add(options.skip_linker_dependencies);
2253 hash.add(options.emit_h != .no);2298 //hash.add(options.emit_h != .no);
2254 hash.add(error_limit);2299 hash.add(error_limit);
22552300
2256 // Here we put the root source file path name, but *not* with addFile.2301 try comp.addModuleTableToCacheHash(&hash);
2257 // We want the hash to be the same regardless of the contents of the
2258 // source file, because incremental compilation will handle it, but we
2259 // do want to namespace different source file names because they are
2260 // likely different compilations and therefore this would be likely to
2261 // cause cache hits.
2262 if (comp.zcu) |zcu| {
2263 try addModuleTableToCacheHash(zcu, &hash);
2264 } else {
2265 cache_helpers.addModule(&hash, options.root_mod);
2266 }
22672302
2268 // In the case of incremental cache mode, this `artifact_directory`2303 // In the case of incremental cache mode, this `artifact_directory`
2269 // is computed based on a hash of non-linker inputs, and it is where all2304 // is computed based on a hash of non-linker inputs, and it is where all
...@@ -2315,22 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,...@@ -2315,22 +2350,6 @@ pub fn create(gpa: Allocator, arena: Allocator, io: Io, diag: *CreateDiagnostic,
2315 comp.cache_use = .{ .whole = whole };2350 comp.cache_use = .{ .whole = whole };
2316 },2351 },
2317 }2352 }
2318
2319 if (use_llvm and
2320 (comp.emit_bin != null or
2321 comp.emit_asm != null or
2322 comp.emit_llvm_ir != null or
2323 comp.emit_llvm_bc != null or
2324 log_llvm_ir: {
2325 break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
2326 }))
2327 {
2328 if (opt_zcu) |zcu| {
2329 dev.check(.llvm_backend);
2330 zcu.llvm_object = try LlvmObject.create(arena, zcu);
2331 }
2332 }
2333
2334 break :comp comp;2353 break :comp comp;
2335 };2354 };
2336 errdefer comp.destroy();2355 errdefer comp.destroy();
...@@ -2599,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void {...@@ -2599,8 +2618,8 @@ pub fn destroy(comp: *Compilation) void {
2599 }2618 }
2600 comp.win32_resources.deinit(gpa);2619 comp.win32_resources.deinit(gpa);
26012620
2602 for (comp.failed_win32_resources.values()) |*value| {2621 for (comp.failed_win32_resources.values()) |*bundle| {
2603 value.deinit(gpa);2622 bundle.deinit(gpa);
2604 }2623 }
2605 comp.failed_win32_resources.deinit(gpa);2624 comp.failed_win32_resources.deinit(gpa);
26062625
...@@ -2624,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void {...@@ -2624,8 +2643,8 @@ pub fn clearMiscFailures(comp: *Compilation) void {
2624 comp.misc_failures = .{};2643 comp.misc_failures = .{};
2625}2644}
26262645
2627pub fn getTarget(self: *const Compilation) *const Target {2646pub fn getTarget(comp: *const Compilation) *const Target {
2628 return &self.root_mod.resolved_target.result;2647 return &comp.root_mod.resolved_target.result;
2629}2648}
26302649
2631/// Only legal to call when cache mode is incremental and a link file is present.2650/// Only legal to call when cache mode is incremental and a link file is present.
...@@ -2644,6 +2663,18 @@ pub fn hotCodeSwap(...@@ -2644,6 +2663,18 @@ pub fn hotCodeSwap(
2644fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {2663fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2645 const io = comp.io;2664 const io = comp.io;
26462665
2666 if (comp.bin_file) |lf| {
2667 lf.endProgress();
2668 comp.link_prog_node.end();
2669 comp.link_prog_node = .none;
2670 switch (comp.cache_use) {
2671 .none, .whole => {
2672 lf.destroy();
2673 comp.bin_file = null;
2674 },
2675 .incremental => {},
2676 }
2677 }
2647 switch (comp.cache_use) {2678 switch (comp.cache_use) {
2648 .none => |none| {2679 .none => |none| {
2649 if (none.tmp_artifact_directory) |*tmp_dir| {2680 if (none.tmp_artifact_directory) |*tmp_dir| {
...@@ -2660,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2660,17 +2691,14 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2660 // replicated in the output binary (the output instead contains a reference to that2691 // replicated in the output binary (the output instead contains a reference to that
2661 // file which debug tooling can look through). So, in that particular case, we need2692 // file which debug tooling can look through). So, in that particular case, we need
2662 // to keep this directory around so that the output binary can be debugged.2693 // to keep this directory around so that the output binary can be debugged.
2663 if (comp.bin_file != null and comp.getTarget().ofmt == .macho and comp.config.debug_format != .strip) {2694 if (comp.bin_file == null or comp.getTarget().ofmt != .macho or comp.config.debug_format == .strip) {
2664 // We are emitting an unstripped Mach-O binary with the LLVM backend: the ZCU2695 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
2665 // object file must remain on-disk for its debug info.2696 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| {
2666 return;2697 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{
2698 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err,
2699 });
2700 };
2667 }2701 }
2668 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(tmp_dir_rand_int);
2669 comp.dirs.local_cache.handle.deleteTree(io, tmp_dir_sub_path) catch |err| {
2670 log.warn("failed to delete temporary directory '{s}{c}{s}': {t}", .{
2671 comp.dirs.local_cache.path orelse ".", fs.path.sep, tmp_dir_sub_path, err,
2672 });
2673 };
2674 }2702 }
2675 },2703 },
2676 .incremental => return,2704 .incremental => return,
...@@ -2679,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2679,10 +2707,6 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2679 man.deinit();2707 man.deinit();
2680 whole.cache_manifest = null;2708 whole.cache_manifest = null;
2681 }2709 }
2682 if (comp.bin_file) |lf| {
2683 lf.destroy();
2684 comp.bin_file = null;
2685 }
2686 if (whole.tmp_artifact_directory) |*tmp_dir| {2710 if (whole.tmp_artifact_directory) |*tmp_dir| {
2687 tmp_dir.handle.close(io);2711 tmp_dir.handle.close(io);
2688 whole.tmp_artifact_directory = null;2712 whole.tmp_artifact_directory = null;
...@@ -2695,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {...@@ -2695,6 +2719,13 @@ fn cleanupAfterUpdate(comp: *Compilation, tmp_dir_rand_int: u64) void {
2695 }2719 }
2696 },2720 },
2697 }2721 }
2722 assert(!comp.config.incremental); // always uses incremental cache mode
2723 if (comp.zcu) |zcu| {
2724 if (zcu.llvm_object) |llvm_object| {
2725 llvm_object.deinit();
2726 zcu.llvm_object = null;
2727 }
2728 }
2698}2729}
26992730
2700pub const UpdateError = error{2731pub const UpdateError = error{
...@@ -2716,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2716,11 +2747,24 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2716 defer arena_allocator.deinit();2747 defer arena_allocator.deinit();
2717 const arena = arena_allocator.allocator();2748 const arena = arena_allocator.allocator();
27182749
2719 comp.clearMiscFailures();2750 reset: {
2720 comp.last_update_was_cache_hit = false;2751 comp.clearMiscFailures();
2721 if (comp.time_report) |*tr| {2752 comp.last_update_was_cache_hit = false;
2722 tr.deinit(gpa); // this is information about an old update2753 if (comp.time_report) |*tr| {
2723 tr.* = .init;2754 tr.deinit(comp.gpa);
2755 tr.* = .init;
2756 }
2757 if (comp.file_system_inputs) |file_system_inputs| file_system_inputs.clearRetainingCapacity();
2758
2759 if (comp.zcu) |zcu| {
2760 zcu.skip_analysis_this_update = false;
2761 if (zcu.generation > 0) break :reset;
2762 try zcu.reset(arena);
2763 }
2764 for (comp.failed_c_objects.values()) |bundle| bundle.destroy(comp.gpa);
2765 comp.failed_c_objects.clearRetainingCapacity();
2766 for (comp.failed_win32_resources.values()) |*bundle| bundle.deinit(comp.gpa);
2767 comp.failed_win32_resources.clearRetainingCapacity();
2724 }2768 }
27252769
2726 var tmp_dir_rand_int: u64 = undefined;2770 var tmp_dir_rand_int: u64 = undefined;
...@@ -2865,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2865,39 +2909,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2865 if (comp.zcu) |zcu| {2909 if (comp.zcu) |zcu| {
2866 assert(zcu.cur_analysis_timer == null);2910 assert(zcu.cur_analysis_timer == null);
28672911
2868 zcu.skip_analysis_this_update = false;
2869
2870 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate!2912 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate!
2871 for (zcu.embed_table.keys()) |embed_file| {2913 for (zcu.embed_table.keys()) |embed_file| {
2872 try comp.appendFileSystemInput(embed_file.path);2914 try comp.appendFileSystemInput(embed_file.path);
2873 }2915 }
2874
2875 zcu.analysis_roots_len = 0;
2876
2877 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod;
2878 zcu.analysis_roots_len += 1;
2879
2880 // Normally we rely on importing std to in turn import the root source file in the start code.
2881 // However, the main module is distinct from the root module in tests, so that won't happen there.
2882 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) {
2883 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod;
2884 zcu.analysis_roots_len += 1;
2885 }
2886
2887 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2888 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod;
2889 zcu.analysis_roots_len += 1;
2890 }
2891
2892 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2893 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod;
2894 zcu.analysis_roots_len += 1;
2895 }
2896
2897 if (zcu.root_mod.deps.get("zigc")) |zigc_mod| {
2898 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod;
2899 zcu.analysis_roots_len += 1;
2900 }
2901 }2916 }
29022917
2903 // The linker progress node is set up here instead of in `performAllTheWork`, because2918 // The linker progress node is set up here instead of in `performAllTheWork`, because
...@@ -2919,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2919,11 +2934,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2919 comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total);2934 comp.link_prog_node = main_progress_node.start("Linking", initial_estimated_total);
2920 lf.startProgress(comp.link_prog_node);2935 lf.startProgress(comp.link_prog_node);
2921 }2936 }
2922 defer if (comp.bin_file) |lf| {
2923 lf.endProgress();
2924 comp.link_prog_node.end();
2925 comp.link_prog_node = .none;
2926 };
29272937
2928 try comp.performAllTheWork(main_progress_node, arena);2938 try comp.performAllTheWork(main_progress_node, arena);
29292939
...@@ -2969,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2969,7 +2979,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2969 comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err});2979 comp.setMiscFailure(.link_depfile, "writing linker dependency file failed: {t}", .{err});
2970 };2980 };
29712981
2972 if (anyErrors(comp)) {2982 if (comp.anyErrors()) {
2973 // Skip flushing and keep source files loaded for error reporting.2983 // Skip flushing and keep source files loaded for error reporting.
2974 return;2984 return;
2975 }2985 }
...@@ -2983,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2983,7 +2993,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2983 }2993 }
29842994
2985 switch (comp.cache_use) {2995 switch (comp.cache_use) {
2986 .none, .incremental => try flush(comp, arena),2996 .none, .incremental => try comp.flush(arena),
2987 .whole => |whole| {2997 .whole => |whole| {
2988 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);2998 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);
2989 if (comp.parent_whole_cache) |pwc| {2999 if (comp.parent_whole_cache) |pwc| {
...@@ -3064,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -3064,11 +3074,11 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
3064 };3074 };
3065 }3075 }
30663076
3067 try flush(comp, arena);3077 try comp.flush(arena);
30683078
3069 // Calling `flush` may have produced errors, in which case the3079 // Calling `flush` may have produced errors, in which case the
3070 // cache manifest must not be written.3080 // cache manifest must not be written.
3071 if (anyErrors(comp)) return;3081 if (comp.anyErrors()) return;
30723082
3073 // Release the lock and close the file before writing the manifest.3083 // Release the lock and close the file before writing the manifest.
3074 // This avoids the potential of another process getting a cache hit and3084 // This avoids the potential of another process getting a cache hit and
...@@ -3168,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error...@@ -3168,7 +3178,6 @@ fn flush(comp: *Compilation, arena: Allocator) (Io.Cancelable || Allocator.Error
3168 defer tid.release(io);3178 defer tid.release(io);
3169 if (comp.zcu) |zcu| {3179 if (comp.zcu) |zcu| {
3170 if (zcu.llvm_object) |llvm_object| {3180 if (zcu.llvm_object) |llvm_object| {
3171
3172 // Emit the ZCU object from LLVM now; it's required to flush the output file.3181 // Emit the ZCU object from LLVM now; it's required to flush the output file.
3173 // If there's an output file, it wants to decide where the LLVM object goes!3182 // If there's an output file, it wants to decide where the LLVM object goes!
3174 const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0);3183 const sub_prog_node = comp.link_prog_node.start("LLVM Emit Object", 0);
...@@ -3303,23 +3312,42 @@ fn renameTmpIntoCache(...@@ -3303,23 +3312,42 @@ fn renameTmpIntoCache(
3303/// anything from the link cache manifest.3312/// anything from the link cache manifest.
3304pub const link_hash_implementation_version = 14;3313pub const link_hash_implementation_version = 14;
33053314
3306fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {3315fn addModuleTableToCacheHash(comp: *Compilation, hash: *Cache.HashHelper) Allocator.Error!void {
3307 comptime assert(link_hash_implementation_version == 14);3316 const gpa = comp.gpa;
3317 var mods: std.array_hash_map.Auto(*Module, void) = .empty;
3318 defer mods.deinit(gpa);
3319
3320 try mods.putNoClobber(gpa, comp.root_mod, {});
3321 if (comp.zcu) |zcu| try mods.put(gpa, zcu.main_mod, {});
3322
3323 var mod_index: usize = 0;
3324 while (mod_index < mods.count()) : (mod_index += 1) {
3325 const mod = mods.keys()[mod_index];
33083326
3309 if (comp.zcu) |zcu| {
3310 // No need to hash the actual file contents here because it is3327 // No need to hash the actual file contents here because it is
3311 // redundant with the logic in `PerThread.update` which iterates over3328 // redundant with the logic in `PerThread.update` which iterates over
3312 // `zcu.alive_files` and adds those files discovered via `@import` to3329 // `zcu.alive_files` and adds those files discovered via `@import` to
3313 // the whole cache manifest.3330 // the whole cache manifest.
3314 try addModuleTableToCacheHash(zcu, &man.hash);3331 cache_helpers.addModule(hash, mod);
3332 hash.add(mod.root.root);
3333 hash.addBytes(mod.root.sub_path);
3334 hash.addBytes(mod.root_src_path);
3335 hash.addListOfBytes(mod.deps.keys());
33153336
3337 for (mod.deps.values()) |dep_mod| try mods.put(gpa, dep_mod, {});
3338 }
3339}
3340
3341fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void {
3342 comptime assert(link_hash_implementation_version == 14);
3343
3344 try comp.addModuleTableToCacheHash(&man.hash);
3345
3346 if (comp.zcu) |zcu| {
3316 // Synchronize with other matching comments: ZigOnlyHashStuff3347 // Synchronize with other matching comments: ZigOnlyHashStuff
3317 man.hash.addListOfBytes(comp.test_filters);3348 man.hash.addListOfBytes(zcu.test_filters);
3318 man.hash.add(comp.skip_linker_dependencies);
3319 //man.hash.add(zcu.emit_h != .no);3349 //man.hash.add(zcu.emit_h != .no);
3320 man.hash.add(zcu.error_limit);3350 man.hash.add(zcu.error_limit);
3321 } else {
3322 cache_helpers.addModule(&man.hash, comp.root_mod);
3323 }3351 }
33243352
3325 try link.hashInputs(man, comp.link_inputs);3353 try link.hashInputs(man, comp.link_inputs);
...@@ -3788,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void {...@@ -3788,7 +3816,7 @@ fn addBuf(list: *std.array_list.Managed([]const u8), buf: []const u8) void {
3788}3816}
37893817
3790/// This function is temporally single-threaded.3818/// This function is temporally single-threaded.
3791pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {3819pub fn getAllErrorsAlloc(comp: *Compilation) Allocator.Error!ErrorBundle {
3792 const gpa = comp.gpa;3820 const gpa = comp.gpa;
3793 const io = comp.io;3821 const io = comp.io;
37943822
...@@ -3831,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -3831,6 +3859,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
3831 }3859 }
38323860
3833 if (comp.zcu) |zcu| zcu_errors: {3861 if (comp.zcu) |zcu| zcu_errors: {
3862 if (zcu.illegal_module_root) |mod| {
3863 try bundle.addRootErrorMessage(.{
3864 .msg = try bundle.printString(
3865 "this compiler implementation does not support using '{f}/{s}' as the root of module '{s}'",
3866 .{ mod.root.fmt(comp), mod.root_src_path, mod.fully_qualified_name },
3867 ),
3868 .notes_len = 0,
3869 });
3870 }
3834 if (zcu.multi_module_err != null) {3871 if (zcu.multi_module_err != null) {
3835 try zcu.addFileInMultipleModulesError(&bundle);3872 try zcu.addFileInMultipleModulesError(&bundle);
3836 break :zcu_errors;3873 break :zcu_errors;
...@@ -4359,7 +4396,9 @@ fn performAllTheWork(...@@ -4359,7 +4396,9 @@ fn performAllTheWork(
4359 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu);4396 defer if (comp.zcu) |zcu| zcu.codegen_task_pool.cancel(zcu);
4360 if (comp.zcu) |zcu| {4397 if (comp.zcu) |zcu| {
4361 // Regardless of errors, `comp.zcu` needs to update its generation number.4398 // Regardless of errors, `comp.zcu` needs to update its generation number.
4362 defer zcu.generation += 1;4399 defer if (comp.config.incremental) {
4400 zcu.generation += 1;
4401 };
4363 const active = zcu.acquire();4402 const active = zcu.acquire();
4364 defer active.release();4403 defer active.release();
4365 try active.pt.update(main_progress_node, &decl_work_timer);4404 try active.pt.update(main_progress_node, &decl_work_timer);
src/Zcu.zig+250-156
...@@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit;...@@ -40,6 +40,7 @@ const AnalUnit = InternPool.AnalUnit;
40const BuiltinFn = std.zig.BuiltinFn;40const BuiltinFn = std.zig.BuiltinFn;
41const codegen = @import("codegen.zig");41const codegen = @import("codegen.zig");
42const LlvmObject = @import("codegen/llvm.zig").Object;42const LlvmObject = @import("codegen/llvm.zig").Object;
43const debugLogScopeEnabled = @import("main.zig").debugLogScopeEnabled;
43const dev = @import("dev.zig");44const dev = @import("dev.zig");
44const Zoir = std.zig.Zoir;45const Zoir = std.zig.Zoir;
45const ZonGen = std.zig.ZonGen;46const ZonGen = std.zig.ZonGen;
...@@ -69,18 +70,18 @@ root_mod: *Module,...@@ -69,18 +70,18 @@ root_mod: *Module,
69/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.70/// `root_mod` is the test runner, and `main_mod` is the user's source file which has the tests.
70main_mod: *Module,71main_mod: *Module,
71std_mod: *Module,72std_mod: *Module,
72sema_prog_node: std.Progress.Node = .none,73sema_prog_node: std.Progress.Node,
73codegen_prog_node: std.Progress.Node = .none,74codegen_prog_node: std.Progress.Node,
74/// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value75/// The number of codegen jobs which are pending or in-progress. Whichever thread drops this value
75/// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this76/// to 0 is responsible for ending `codegen_prog_node`. While semantic analysis is happening, this
76/// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is77/// value bottoms out at 1 instead of 0, to ensure that it can only drop to 0 after analysis is
77/// completed (since semantic analysis could trigger more codegen work).78/// completed (since semantic analysis could trigger more codegen work).
78pending_codegen_jobs: std.atomic.Value(u32) = .init(0),79pending_codegen_jobs: std.atomic.Value(u32),
7980
80/// This is the progress node *under* `sema_prog_node` which is currently running.81/// This is the progress node *under* `sema_prog_node` which is currently running.
81/// When we have to pause to analyze something else, we just temporarily rename this node.82/// When we have to pause to analyze something else, we just temporarily rename this node.
82/// Eventually, when we thread semantic analysis, we will want one of these per thread.83/// Eventually, when we thread semantic analysis, we will want one of these per thread.
83cur_sema_prog_node: std.Progress.Node = .none,84cur_sema_prog_node: std.Progress.Node,
8485
85/// Used by AstGen worker to load and store ZIR cache.86/// Used by AstGen worker to load and store ZIR cache.
86global_zir_cache: Cache.Directory,87global_zir_cache: Cache.Directory,
...@@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory,...@@ -89,27 +90,26 @@ local_zir_cache: Cache.Directory,
8990
90/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;91/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
91/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.92/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
92all_exports: std.ArrayList(Export) = .empty,93all_exports: std.ArrayList(Export),
93/// This is a list of free indices in `all_exports`. These indices may be reused by exports from94/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
94/// future semantic analysis.95/// future semantic analysis.
95free_exports: std.ArrayList(Export.Index) = .empty,96free_exports: std.ArrayList(Export.Index),
96/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of97/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
97/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`98/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
98/// whose analysis triggered the export.99/// whose analysis triggered the export.
99single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index) = .empty,100single_exports: std.array_hash_map.Auto(AnalUnit, Export.Index),
100/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.101/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
101/// The exports are `all_exports.items[index..][0..len]`.102/// The exports are `all_exports.items[index..][0..len]`.
102multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct {103multi_exports: std.array_hash_map.Auto(AnalUnit, extern struct {
103 index: u32,104 index: u32,
104 len: u32,105 len: u32,
105}) = .empty,106}),
106
107/// Key is the digest returned by `Builtin.hash`; value is the corresponding module.
108builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module) = .empty,
109107
110/// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones.108/// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones.
111/// Modules whose root file is not a Zig or ZON file have the value `.none`.109/// Modules whose root file is not a Zig or ZON file have the value `.none`.
112module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional) = .empty,110module_roots: std.array_hash_map.Auto(*Module, File.Index.Optional),
111/// Key is the digest returned by `Builtin.hash`; value is the corresponding module.
112builtin_modules: std.array_hash_map.Auto(Cache.BinDigest, *Module),
113113
114/// The set of all the Zig source files in the Zig Compilation Unit. Tracked in114/// The set of all the Zig source files in the Zig Compilation Unit. Tracked in
115/// order to iterate over it and check which source files have been modified on115/// order to iterate over it and check which source files have been modified on
...@@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom(...@@ -132,26 +132,14 @@ import_table: std.array_hash_map.Custom(
132 pub const eql = @compileError("all accesses should be through ImportTableAdapter");132 pub const eql = @compileError("all accesses should be through ImportTableAdapter");
133 },133 },
134 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918134 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
135) = .empty,135),
136
137/// The set of all files in `import_table` which are "alive" this update, meaning136/// The set of all files in `import_table` which are "alive" this update, meaning
138/// they are reachable by traversing imports starting from an analysis root. This137/// they are reachable by traversing imports starting from an analysis root. This
139/// is usually all files in `import_table`, but some could be omitted if an incremental138/// is usually all files in `import_table`, but some could be omitted if an incremental
140/// update removes an import, or if a module specified on the CLI is never imported.139/// update removes an import, or if a module specified on the CLI is never imported.
141/// Reconstructed on every update, after AstGen and before Sema.140/// Reconstructed on every update, after AstGen and before Sema.
142/// Value is why the file is alive.141/// Value is why the file is alive.
143alive_files: std.array_hash_map.Auto(File.Index, File.Reference) = .empty,142alive_files: std.array_hash_map.Auto(File.Index, File.Reference),
144
145/// If this is populated, a "file exists in multiple modules" error should be emitted.
146/// This causes file errors to not be shown, because we don't really know which files
147/// should be alive (because the user has messed up their imports somewhere!).
148/// Cleared and recomputed every update, after AstGen and before Sema.
149multi_module_err: ?struct {
150 file: File.Index,
151 modules: [2]*Module,
152 refs: [2]File.Reference,
153} = null,
154
155/// The set of all the files which have been loaded with `@embedFile` in the Module.143/// The set of all the files which have been loaded with `@embedFile` in the Module.
156/// We keep track of this in order to iterate over it and check which files have been144/// We keep track of this in order to iterate over it and check which files have been
157/// modified on the file system when an update is requested, as well as to cache145/// modified on the file system when an update is requested, as well as to cache
...@@ -162,49 +150,19 @@ multi_module_err: ?struct {...@@ -162,49 +150,19 @@ multi_module_err: ?struct {
162///150///
163/// This table owns all of the `*EmbedFile` memory, which is allocated into gpa.151/// This table owns all of the `*EmbedFile` memory, which is allocated into gpa.
164embed_table: std.array_hash_map.Custom(152embed_table: std.array_hash_map.Custom(
165 *EmbedFile,153 EmbedFile,
166 void,154 void,
167 struct {155 struct {
168 pub const hash = @compileError("all accesses should be through EmbedTableAdapter");156 pub const hash = @compileError("all accesses should be through EmbedTableAdapter");
169 pub const eql = @compileError("all accesses should be through EmbedTableAdapter");157 pub const eql = @compileError("all accesses should be through EmbedTableAdapter");
170 },158 },
171 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918159 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
172) = .empty,160),
173161
174/// Stores all Type and Value objects.162/// Stores all Type and Value objects.
175/// The idea is that this will be periodically garbage-collected, but such logic163/// The idea is that this will be periodically garbage-collected, but such logic
176/// is not yet implemented.164/// is not yet implemented.
177intern_pool: InternPool = .empty,165intern_pool: InternPool,
178
179/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
180/// (index 0), and non-`null` for all others.
181analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason) = .empty,
182/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
183failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg) = .empty,
184/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
185transitive_failed_analysis: std.array_hash_map.Auto(
186 AnalUnit,
187 if (build_options.enable_debug_extensions) TransitiveFailureReason else void,
188) = .empty,
189/// This `Nav` succeeded analysis, but failed codegen.
190/// This may be a simple "value" `Nav`, or it may be a function.
191/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
192/// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as
193/// codegen and linking run on a separate thread.
194failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg) = .empty,
195failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg) = .empty,
196
197/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
198/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
199/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
200/// this map simply exists to allow easily iterating all dependency loops exactly once.
201dependency_loops: std.array_hash_map.Auto(AnalUnit, void) = .empty,
202/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
203/// All units in here form loops. To iterate loops, see `dependency_loops`.
204dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct {
205 unit: AnalUnit,
206 reason: DependencyReason,
207}) = .empty,
208166
209/// Keep track of `@compileLog`s per `AnalUnit`.167/// Keep track of `@compileLog`s per `AnalUnit`.
210/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.168/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.
...@@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct {...@@ -220,17 +178,20 @@ compile_logs: std.array_hash_map.Auto(AnalUnit, struct {
220 .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),178 .offset = LazySrcLoc.Offset.nodeOffset(self.node_offset),
221 };179 };
222 }180 }
223}) = .empty,181}),
224compile_log_lines: std.ArrayList(CompileLogLine) = .empty,182compile_log_lines: std.ArrayList(CompileLogLine),
225free_compile_log_lines: std.ArrayList(CompileLogLine.Index) = .empty,183free_compile_log_lines: std.ArrayList(CompileLogLine.Index),
226/// This tracks files which triggered errors when generating AST/ZIR/ZOIR.184
227/// If not `null`, the value is a retryable error (the file status is guaranteed185illegal_module_root: ?*Module,
228/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure`186/// If this is populated, a "file exists in multiple modules" error should be emitted.
229/// or `.success`, and there are ZIR/ZOIR errors which should be printed.187/// This causes file errors to not be shown, because we don't really know which files
230/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source188/// should be alive (because the user has messed up their imports somewhere!).
231/// location is always the entire file. The `[]u8` memory is owned by the map189/// Cleared and recomputed every update, after AstGen and before Sema.
232/// and allocated into `gpa`.190multi_module_err: ?struct {
233failed_files: std.array_hash_map.Auto(File.Index, ?[]u8) = .empty,191 file: File.Index,
192 modules: [2]*Module,
193 refs: [2]File.Reference,
194},
234/// AstGen is not aware of modules, and so cannot determine whether an import195/// AstGen is not aware of modules, and so cannot determine whether an import
235/// string makes sense. That is the job of a traversal after AstGen.196/// string makes sense. That is the job of a traversal after AstGen.
236///197///
...@@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct {...@@ -257,11 +218,48 @@ failed_imports: std.ArrayList(struct {
257 import_string: Zir.NullTerminatedString,218 import_string: Zir.NullTerminatedString,
258 import_token: Ast.TokenIndex,219 import_token: Ast.TokenIndex,
259 kind: enum { file_outside_module_root, illegal_zig_import },220 kind: enum { file_outside_module_root, illegal_zig_import },
260}) = .empty,221}),
261failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg) = .empty,222/// This tracks files which triggered errors when generating AST/ZIR/ZOIR.
262/// If analysis failed due to a cimport error, the corresponding Clang errors223/// If not `null`, the value is a retryable error (the file status is guaranteed
263/// are stored here.224/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure`
264cimport_errors: std.array_hash_map.Auto(AnalUnit, std.zig.ErrorBundle) = .empty,225/// or `.success`, and there are ZIR/ZOIR errors which should be printed.
226/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source
227/// location is always the entire file. The `[]u8` memory is owned by the map
228/// and allocated into `gpa`.
229failed_files: std.array_hash_map.Auto(File.Index, ?[]u8),
230/// If `true`, then semantic analysis must not occur on this update due to AstGen errors.
231/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped.
232/// Reset to `false` at the start of each update in `Compilation.update`.
233skip_analysis_this_update: bool,
234/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
235/// (index 0), and non-`null` for all others.
236analysis_in_progress: std.array_hash_map.Auto(AnalUnit, ?*const DependencyReason),
237/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
238failed_analysis: std.array_hash_map.Auto(AnalUnit, *ErrorMsg),
239/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
240transitive_failed_analysis: std.array_hash_map.Auto(
241 AnalUnit,
242 if (build_options.enable_debug_extensions) TransitiveFailureReason else void,
243),
244/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
245/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
246/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
247/// this map simply exists to allow easily iterating all dependency loops exactly once.
248dependency_loops: std.array_hash_map.Auto(AnalUnit, void),
249/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
250/// All units in here form loops. To iterate loops, see `dependency_loops`.
251dependency_loop_nodes: std.array_hash_map.Auto(AnalUnit, struct {
252 unit: AnalUnit,
253 reason: DependencyReason,
254}),
255/// This `Nav` succeeded analysis, but failed codegen.
256/// This may be a simple "value" `Nav`, or it may be a function.
257/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
258/// While multiple threads are active (most of the time!), this is guarded by `zcu.comp.mutex`, as
259/// codegen and linking run on a separate thread.
260failed_codegen: std.array_hash_map.Auto(InternPool.Nav.Index, *ErrorMsg),
261failed_types: std.array_hash_map.Auto(InternPool.Index, *ErrorMsg),
262failed_exports: std.array_hash_map.Auto(Export.Index, *ErrorMsg),
265263
266/// Maximum amount of distinct error values, set by --error-limit264/// Maximum amount of distinct error values, set by --error-limit
267error_limit: ErrorInt,265error_limit: ErrorInt,
...@@ -269,14 +267,14 @@ error_limit: ErrorInt,...@@ -269,14 +267,14 @@ error_limit: ErrorInt,
269/// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock267/// In safe builds, `Type.assertHasLayout` may be called cross-thread, so this lock
270/// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the268/// guards accesses to `outdated` and `potentially_outdated`. In unsafe builds, the
271/// lock is not needed and is compiled out.269/// lock is not needed and is compiled out.
272outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void = if (std.debug.runtime_safety) .init,270outdated_lock: if (std.debug.runtime_safety) std.Io.RwLock else void,
273/// Value is the number of PO dependencies of this AnalUnit.271/// Value is the number of PO dependencies of this AnalUnit.
274/// This value will decrease as we perform semantic analysis to learn what is outdated.272/// This value will decrease as we perform semantic analysis to learn what is outdated.
275/// If any of these PO deps is outdated, this value will be moved to `outdated`.273/// If any of these PO deps is outdated, this value will be moved to `outdated`.
276potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty,274potentially_outdated: std.array_hash_map.Auto(AnalUnit, u32),
277/// Value is the number of PO dependencies of this AnalUnit.275/// Value is the number of PO dependencies of this AnalUnit.
278/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.276/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
279outdated: std.array_hash_map.Auto(AnalUnit, u32) = .empty,277outdated: std.array_hash_map.Auto(AnalUnit, u32),
280/// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0.278/// This is the set of all `AnalUnit`s in `outdated` whose PO dependency count is 0.
281/// Such `AnalUnit`s are ready for immediate re-analysis.279/// Such `AnalUnit`s are ready for immediate re-analysis.
282/// See `findOutdatedToAnalyze` for details.280/// See `findOutdatedToAnalyze` for details.
...@@ -286,69 +284,64 @@ outdated_ready: struct {...@@ -286,69 +284,64 @@ outdated_ready: struct {
286 funcs: std.array_hash_map.Auto(InternPool.Index, void),284 funcs: std.array_hash_map.Auto(InternPool.Index, void),
287 /// Does not contain `.func` units.285 /// Does not contain `.func` units.
288 other: std.array_hash_map.Auto(AnalUnit, void),286 other: std.array_hash_map.Auto(AnalUnit, void),
289} = .{ .funcs = .empty, .other = .empty },287},
290/// This contains a list of AnalUnit whose analysis or codegen failed, but the288/// This contains a list of AnalUnit whose analysis or codegen failed, but the
291/// failure was something like running out of disk space, and trying again may289/// failure was something like running out of disk space, and trying again may
292/// succeed. On the next update, we will flush this list, marking all members of290/// succeed. On the next update, we will flush this list, marking all members of
293/// it as outdated.291/// it as outdated.
294retryable_failures: std.ArrayList(AnalUnit) = .empty,292retryable_failures: std.ArrayList(AnalUnit),
295293
296/// These are the modules which we initially queue for analysis in `Compilation.update`.294/// These are the modules which we initially queue for analysis in `Compilation.update`.
297/// `resolveReferences` will use these as the root of its reachability traversal.295/// `resolveReferences` will use these as the root of its reachability traversal.
298analysis_roots_buffer: [5]*Module,296analysis_roots_buffer: [5]*Module,
299analysis_roots_len: usize = 0,297analysis_roots_len: usize,
300/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and298/// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and
301/// reset to `null` when any semantic analysis occurs (since this invalidates the data).299/// reset to `null` when any semantic analysis occurs (since this invalidates the data).
302/// Allocated into `gpa`.300/// Allocated into `gpa`.
303resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = null,301resolved_references: ?std.array_hash_map.Auto(AnalUnit, ?ResolvedReference),
304
305/// If `true`, then semantic analysis must not occur on this update due to AstGen errors.
306/// Essentially the entire pipeline after AstGen, including Sema, codegen, and link, is skipped.
307/// Reset to `false` at the start of each update in `Compilation.update`.
308skip_analysis_this_update: bool = false,
309302
310test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void) = .empty,303test_filters: []const []const u8,
304test_functions: std.array_hash_map.Auto(InternPool.Nav.Index, void),
311305
312global_assembly: std.array_hash_map.Auto(AnalUnit, []u8) = .empty,306global_assembly: std.array_hash_map.Auto(AnalUnit, []u8),
313307
314/// Key is the `AnalUnit` *performing* the reference. This representation allows308/// Key is the `AnalUnit` *performing* the reference. This representation allows
315/// incremental updates to quickly delete references caused by a specific `AnalUnit`.309/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
316/// Value is index into `all_references` of the first reference triggered by the unit.310/// Value is index into `all_references` of the first reference triggered by the unit.
317/// The `next` field on the `Reference` forms a linked list of all references311/// The `next` field on the `Reference` forms a linked list of all references
318/// triggered by the key `AnalUnit`.312/// triggered by the key `AnalUnit`.
319reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty,313reference_table: std.array_hash_map.Auto(AnalUnit, u32),
320all_references: std.ArrayList(Reference) = .empty,314all_references: std.ArrayList(Reference),
321/// Freelist of indices in `all_references`.315/// Freelist of indices in `all_references`.
322free_references: std.ArrayList(u32) = .empty,316free_references: std.ArrayList(u32),
323317
324inline_reference_frames: std.ArrayList(InlineReferenceFrame) = .empty,318inline_reference_frames: std.ArrayList(InlineReferenceFrame),
325free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index) = .empty,319free_inline_reference_frames: std.ArrayList(InlineReferenceFrame.Index),
326320
327/// Key is the `AnalUnit` *performing* the reference. This representation allows321/// Key is the `AnalUnit` *performing* the reference. This representation allows
328/// incremental updates to quickly delete references caused by a specific `AnalUnit`.322/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
329/// Value is index into `all_type_reference` of the first reference triggered by the unit.323/// Value is index into `all_type_reference` of the first reference triggered by the unit.
330/// The `next` field on the `TypeReference` forms a linked list of all type references324/// The `next` field on the `TypeReference` forms a linked list of all type references
331/// triggered by the key `AnalUnit`.325/// triggered by the key `AnalUnit`.
332type_reference_table: std.array_hash_map.Auto(AnalUnit, u32) = .empty,326type_reference_table: std.array_hash_map.Auto(AnalUnit, u32),
333all_type_references: std.ArrayList(TypeReference) = .empty,327all_type_references: std.ArrayList(TypeReference),
334/// Freelist of indices in `all_type_references`.328/// Freelist of indices in `all_type_references`.
335free_type_references: std.ArrayList(u32) = .empty,329free_type_references: std.ArrayList(u32),
336330
337/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.331/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element.
338std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none),332std_lang_decl_values: StdLangDecl.Memoized,
339333
340incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void =334incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void,
341 if (build_options.enable_debug_extensions) .init else {},
342335
343/// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit,336/// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit,
344/// this timer must be temporarily paused and resumed later.337/// this timer must be temporarily paused and resumed later.
345cur_analysis_timer: ?Compilation.Timer = null,338cur_analysis_timer: ?Compilation.Timer,
346339
347codegen_task_pool: CodegenTaskPool,340codegen_task_pool: CodegenTaskPool,
348341
349generation: u32 = 0,342generation: u32,
350343
351/// Only access from the Sema thread.344/// Only accessed from the Sema thread.
352anon_name_counter: u32,345anon_name_counter: u32,
353346
354pub const DependencyReason = struct {347pub const DependencyReason = struct {
...@@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct {...@@ -434,7 +427,7 @@ pub const EmbedTableAdapter = struct {
434 _ = ctx;427 _ = ctx;
435 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path));428 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path));
436 }429 }
437 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool {430 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: EmbedFile, b_index: usize) bool {
438 _ = ctx;431 _ = ctx;
439 _ = b_index;432 _ = b_index;
440 const b_path = b_file.path;433 const b_path = b_file.path;
...@@ -1250,10 +1243,15 @@ pub const EmbedFile = struct {...@@ -1250,10 +1243,15 @@ pub const EmbedFile = struct {
12501243
1251 pub const Index = enum(u32) {1244 pub const Index = enum(u32) {
1252 _,1245 _,
1253 pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile {1246 pub fn get(idx: Index, zcu: *const Zcu) *const EmbedFile {
1254 return zcu.embed_table.keys()[@backingInt(idx)];1247 return &zcu.embed_table.keys()[@backingInt(idx)];
1255 }1248 }
1256 };1249 };
1250
1251 pub fn deinit(ef: *EmbedFile, gpa: Allocator) void {
1252 ef.path.deinit(gpa);
1253 ef.* = undefined;
1254 }
1257};1255};
12581256
1259/// This struct holds data necessary to construct API-facing `AllErrors.Message`.1257/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
...@@ -2894,16 +2892,130 @@ pub const CompileError = error{...@@ -2894,16 +2892,130 @@ pub const CompileError = error{
2894 ComptimeBreak,2892 ComptimeBreak,
2895};2893};
28962894
2897pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void {
2898 try zcu.intern_pool.init(gpa, io, thread_count);
2899}
2900
2901/// It is valid to not call this function before `deinit` in error paths.2895/// It is valid to not call this function before `deinit` in error paths.
2902/// Requires the fields on `zcu.comp` to already be initialized.2896/// Requires the fields on `zcu.comp` to already be initialized.
2903pub fn initAfterCompilation(zcu: *Zcu) void {2897pub fn init(zcu: *Zcu) void {
2904 zcu.initTracyPlots();2898 zcu.initTracyPlots();
2905}2899}
29062900
2901pub fn reset(zcu: *Zcu, arena: Allocator) Allocator.Error!void {
2902 const comp = zcu.comp;
2903 const gpa = comp.gpa;
2904 const io = comp.io;
2905
2906 zcu.all_exports.clearRetainingCapacity();
2907 zcu.free_exports.clearRetainingCapacity();
2908 zcu.single_exports.clearRetainingCapacity();
2909 zcu.multi_exports.clearRetainingCapacity();
2910
2911 zcu.module_roots.clearRetainingCapacity();
2912 // builtin modules can still be reused from a previous non-incremental update
2913
2914 for (zcu.import_table.keys()) |file| zcu.destroyFile(file);
2915 zcu.import_table.clearRetainingCapacity();
2916 zcu.alive_files.clearRetainingCapacity();
2917 for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa);
2918 zcu.embed_table.clearRetainingCapacity();
2919
2920 zcu.compile_logs.clearRetainingCapacity();
2921 zcu.compile_log_lines.clearRetainingCapacity();
2922 zcu.free_compile_log_lines.clearRetainingCapacity();
2923
2924 zcu.illegal_module_root = null;
2925 zcu.multi_module_err = null;
2926 zcu.failed_imports.clearRetainingCapacity();
2927 for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg);
2928 zcu.failed_files.clearRetainingCapacity();
2929 zcu.analysis_in_progress.clearRetainingCapacity();
2930 for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa);
2931 zcu.failed_analysis.clearRetainingCapacity();
2932 zcu.transitive_failed_analysis.clearRetainingCapacity();
2933 zcu.dependency_loops.clearRetainingCapacity();
2934 zcu.dependency_loop_nodes.clearRetainingCapacity();
2935 for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa);
2936 zcu.failed_codegen.clearRetainingCapacity();
2937 for (zcu.failed_types.values()) |msg| msg.destroy(gpa);
2938 zcu.failed_types.clearRetainingCapacity();
2939 for (zcu.failed_exports.values()) |msg| msg.destroy(gpa);
2940 zcu.failed_exports.clearRetainingCapacity();
2941
2942 assert(zcu.potentially_outdated.count() == 0);
2943 assert(zcu.outdated.count() == 0);
2944 assert(zcu.outdated_ready.funcs.count() == 0);
2945 assert(zcu.outdated_ready.other.count() == 0);
2946 zcu.retryable_failures.clearRetainingCapacity();
2947
2948 zcu.analysis_roots_len = 0;
2949 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.std_mod;
2950 zcu.analysis_roots_len += 1;
2951 // Normally we rely on importing std to in turn import the root source file in the start code.
2952 // However, the main module is distinct from the root module in tests, so that won't happen there.
2953 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) {
2954 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zcu.main_mod;
2955 zcu.analysis_roots_len += 1;
2956 }
2957 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2958 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = compiler_rt_mod;
2959 zcu.analysis_roots_len += 1;
2960 }
2961 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2962 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = ubsan_rt_mod;
2963 zcu.analysis_roots_len += 1;
2964 }
2965 if (zcu.root_mod.deps.get("zigc")) |zigc_mod| {
2966 zcu.analysis_roots_buffer[zcu.analysis_roots_len] = zigc_mod;
2967 zcu.analysis_roots_len += 1;
2968 }
2969 zcu.clearCachedResolvedReferences();
2970
2971 zcu.test_functions.clearRetainingCapacity();
2972
2973 zcu.global_assembly.clearRetainingCapacity();
2974
2975 zcu.reference_table.clearRetainingCapacity();
2976 zcu.all_references.clearRetainingCapacity();
2977 zcu.free_references.clearRetainingCapacity();
2978
2979 zcu.inline_reference_frames.clearRetainingCapacity();
2980 zcu.free_inline_reference_frames.clearRetainingCapacity();
2981
2982 zcu.type_reference_table.clearRetainingCapacity();
2983 zcu.all_type_references.clearRetainingCapacity();
2984 zcu.free_type_references.clearRetainingCapacity();
2985
2986 zcu.std_lang_decl_values = .initFill(.none);
2987
2988 for (zcu.codegen_task_pool.task_funcs) |task_func| assert(task_func == .none);
2989
2990 assert(zcu.generation == 0);
2991
2992 zcu.anon_name_counter = 0;
2993
2994 zcu.intern_pool.deinit(gpa, io);
2995 zcu.intern_pool = .empty;
2996 try zcu.intern_pool.init(gpa, io, comp.thread_limit);
2997
2998 {
2999 const active = zcu.acquire();
3000 defer active.release();
3001 try active.pt.populateModuleRootTable();
3002 }
3003
3004 assert(zcu.llvm_object == null);
3005 if (comp.config.use_llvm and
3006 (comp.emit_bin != null or
3007 comp.emit_asm != null or
3008 comp.emit_llvm_ir != null or
3009 comp.emit_llvm_bc != null or
3010 log_llvm_ir: {
3011 break :log_llvm_ir debugLogScopeEnabled("llvm-ir") or debugLogScopeEnabled("opt-llvm-ir");
3012 }))
3013 {
3014 dev.check(.llvm_backend);
3015 zcu.llvm_object = try .create(if (comp.config.incremental) comp.arena else arena, zcu);
3016 }
3017}
3018
2907pub fn deinit(zcu: *Zcu) void {3019pub fn deinit(zcu: *Zcu) void {
2908 const comp = zcu.comp;3020 const comp = zcu.comp;
2909 const io = comp.io;3021 const io = comp.io;
...@@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2911,70 +3023,54 @@ pub fn deinit(zcu: *Zcu) void {
2911 {3023 {
2912 if (zcu.llvm_object) |llvm_object| llvm_object.deinit();3024 if (zcu.llvm_object) |llvm_object| llvm_object.deinit();
29133025
2914 zcu.builtin_modules.deinit(gpa);3026 zcu.global_zir_cache.handle.close(io);
3027 zcu.local_zir_cache.handle.close(io);
3028
3029 zcu.all_exports.deinit(gpa);
3030 zcu.free_exports.deinit(gpa);
3031 zcu.single_exports.deinit(gpa);
3032 zcu.multi_exports.deinit(gpa);
3033
2915 zcu.module_roots.deinit(gpa);3034 zcu.module_roots.deinit(gpa);
2916 for (zcu.import_table.keys()) |file_index| {3035 zcu.builtin_modules.deinit(gpa);
2917 zcu.destroyFile(file_index);3036
2918 }3037 for (zcu.import_table.keys()) |file| zcu.destroyFile(file);
2919 zcu.import_table.deinit(gpa);3038 zcu.import_table.deinit(gpa);
2920 zcu.alive_files.deinit(gpa);3039 zcu.alive_files.deinit(gpa);
29213040 for (zcu.embed_table.keys()) |*ef| ef.deinit(gpa);
2922 for (zcu.embed_table.keys()) |embed_file| {
2923 embed_file.path.deinit(gpa);
2924 gpa.destroy(embed_file);
2925 }
2926 zcu.embed_table.deinit(gpa);3041 zcu.embed_table.deinit(gpa);
29273042
2928 zcu.local_zir_cache.handle.close(io);3043 zcu.compile_logs.deinit(gpa);
2929 zcu.global_zir_cache.handle.close(io);3044 zcu.compile_log_lines.deinit(gpa);
3045 zcu.free_compile_log_lines.deinit(gpa);
29303046
2931 for (zcu.failed_analysis.values()) |value| value.destroy(gpa);3047 zcu.failed_imports.deinit(gpa);
2932 for (zcu.failed_codegen.values()) |value| value.destroy(gpa);3048 for (zcu.failed_files.values()) |maybe_msg| if (maybe_msg) |msg| gpa.free(msg);
2933 for (zcu.failed_types.values()) |value| value.destroy(gpa);3049 zcu.failed_files.deinit(gpa);
2934 zcu.analysis_in_progress.deinit(gpa);3050 zcu.analysis_in_progress.deinit(gpa);
3051 for (zcu.failed_analysis.values()) |msg| msg.destroy(gpa);
2935 zcu.failed_analysis.deinit(gpa);3052 zcu.failed_analysis.deinit(gpa);
2936 zcu.transitive_failed_analysis.deinit(gpa);3053 zcu.transitive_failed_analysis.deinit(gpa);
2937 zcu.dependency_loops.deinit(gpa);3054 zcu.dependency_loops.deinit(gpa);
2938 zcu.dependency_loop_nodes.deinit(gpa);3055 zcu.dependency_loop_nodes.deinit(gpa);
3056 for (zcu.failed_codegen.values()) |msg| msg.destroy(gpa);
2939 zcu.failed_codegen.deinit(gpa);3057 zcu.failed_codegen.deinit(gpa);
3058 for (zcu.failed_types.values()) |msg| msg.destroy(gpa);
2940 zcu.failed_types.deinit(gpa);3059 zcu.failed_types.deinit(gpa);
29413060 for (zcu.failed_exports.values()) |msg| msg.destroy(gpa);
2942 for (zcu.failed_files.values()) |value| {
2943 if (value) |msg| gpa.free(msg);
2944 }
2945 zcu.failed_files.deinit(gpa);
2946 zcu.failed_imports.deinit(gpa);
2947
2948 for (zcu.failed_exports.values()) |value| {
2949 value.destroy(gpa);
2950 }
2951 zcu.failed_exports.deinit(gpa);3061 zcu.failed_exports.deinit(gpa);
29523062
2953 for (zcu.cimport_errors.values()) |*errs| {
2954 errs.deinit(gpa);
2955 }
2956 zcu.cimport_errors.deinit(gpa);
2957
2958 zcu.compile_logs.deinit(gpa);
2959 zcu.compile_log_lines.deinit(gpa);
2960 zcu.free_compile_log_lines.deinit(gpa);
2961
2962 zcu.all_exports.deinit(gpa);
2963 zcu.free_exports.deinit(gpa);
2964 zcu.single_exports.deinit(gpa);
2965 zcu.multi_exports.deinit(gpa);
2966
2967 zcu.potentially_outdated.deinit(gpa);3063 zcu.potentially_outdated.deinit(gpa);
2968 zcu.outdated.deinit(gpa);3064 zcu.outdated.deinit(gpa);
2969 zcu.outdated_ready.funcs.deinit(gpa);3065 zcu.outdated_ready.funcs.deinit(gpa);
2970 zcu.outdated_ready.other.deinit(gpa);3066 zcu.outdated_ready.other.deinit(gpa);
2971 zcu.retryable_failures.deinit(gpa);3067 zcu.retryable_failures.deinit(gpa);
29723068
3069 if (zcu.resolved_references) |*r| r.deinit(gpa);
3070
2973 zcu.test_functions.deinit(gpa);3071 zcu.test_functions.deinit(gpa);
29743072
2975 for (zcu.global_assembly.values()) |s| {3073 for (zcu.global_assembly.values()) |s| gpa.free(s);
2976 gpa.free(s);
2977 }
2978 zcu.global_assembly.deinit(gpa);3074 zcu.global_assembly.deinit(gpa);
29793075
2980 zcu.reference_table.deinit(gpa);3076 zcu.reference_table.deinit(gpa);
...@@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2988,8 +3084,6 @@ pub fn deinit(zcu: *Zcu) void {
2988 zcu.all_type_references.deinit(gpa);3084 zcu.all_type_references.deinit(gpa);
2989 zcu.free_type_references.deinit(gpa);3085 zcu.free_type_references.deinit(gpa);
29903086
2991 if (zcu.resolved_references) |*r| r.deinit(gpa);
2992
2993 if (comp.debugIncremental()) {3087 if (comp.debugIncremental()) {
2994 zcu.incremental_debug_state.deinit(gpa);3088 zcu.incremental_debug_state.deinit(gpa);
2995 }3089 }
...@@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana...@@ -4352,8 +4446,8 @@ fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(Ana
4352 .unnamed_test => true,4446 .unnamed_test => true,
4353 .@"test", .decltest => a: {4447 .@"test", .decltest => a: {
4354 const fqn_slice = nav.fqn.toSlice(ip);4448 const fqn_slice = nav.fqn.toSlice(ip);
4355 if (comp.test_filters.len > 0) {4449 if (zcu.test_filters.len > 0) {
4356 for (comp.test_filters) |test_filter| {4450 for (zcu.test_filters) |test_filter| {
4357 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;4451 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;
4358 } else break :a false;4452 } else break :a false;
4359 }4453 }
src/Zcu/PerThread.zig+46-44
...@@ -148,6 +148,12 @@ pub fn update(...@@ -148,6 +148,12 @@ pub fn update(
148 comp.link_queue.finishZcuQueue(comp);148 comp.link_queue.finishZcuQueue(comp);
149 }149 }
150150
151 if (zcu.illegal_module_root) |_| {
152 // We cannot run AstGen because we failed to set up the module roots. We can return early
153 // because this is a guaranteed compile error.
154 return;
155 }
156
151 {157 {
152 const tracy_trace = traceNamed(@src(), "astgen");158 const tracy_trace = traceNamed(@src(), "astgen");
153 defer tracy_trace.end();159 defer tracy_trace.end();
...@@ -203,11 +209,9 @@ pub fn update(...@@ -203,11 +209,9 @@ pub fn update(
203 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here209 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
204 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one210 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
205 // `@embedFile` can't trigger analysis of a new `@embedFile`!211 // `@embedFile` can't trigger analysis of a new `@embedFile`!
206 for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {212 for (0.., zcu.embed_table.keys()) |ef_index_usize, *ef| {
207 const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize));213 const ef_index: Zcu.EmbedFile.Index = @fromBackingInt(@intCast(ef_index_usize));
208 astgen_group.async(io, workerUpdateEmbedFile, .{214 astgen_group.async(io, workerUpdateEmbedFile, .{ comp, ef_index, ef });
209 comp, ef_index, ef,
210 });
211 }215 }
212216
213 try astgen_group.await(io);217 try astgen_group.await(io);
...@@ -219,8 +223,8 @@ pub fn update(...@@ -219,8 +223,8 @@ pub fn update(
219 // they belong to.223 // they belong to.
220 const any_fatal_files = try pt.computeAliveFiles();224 const any_fatal_files = try pt.computeAliveFiles();
221225
222 // If the cache mode is `whole`, add every alive source file to the manifest.
223 switch (comp.cache_use) {226 switch (comp.cache_use) {
227 .none => {},
224 .whole => |whole| if (whole.cache_manifest) |man| {228 .whole => |whole| if (whole.cache_manifest) |man| {
225 for (zcu.alive_files.keys()) |file_index| {229 for (zcu.alive_files.keys()) |file_index| {
226 const file = zcu.fileByIndex(file_index);230 const file = zcu.fileByIndex(file_index);
...@@ -250,7 +254,11 @@ pub fn update(...@@ -250,7 +254,11 @@ pub fn update(
250 };254 };
251 }255 }
252 },256 },
253 .none, .incremental => {},257 .incremental => {
258 // Do not include file contents in the cache manifest because we
259 // want the hash to be the same regardless of the contents of the
260 // source files so that incremental can do its thing.
261 },
254 }262 }
255263
256 if (comp.time_report) |*tr| {264 if (comp.time_report) |*tr| {
...@@ -2494,11 +2502,7 @@ pub fn doImport(...@@ -2494,11 +2502,7 @@ pub fn doImport(
2494}2502}
2495/// This is called once during `Compilation.create` and never again. "builtin" modules don't yet2503/// This is called once during `Compilation.create` and never again. "builtin" modules don't yet
2496/// exist, so are not added to `module_roots` here. They must be added when they are created.2504/// exist, so are not added to `module_roots` here. They must be added when they are created.
2497pub fn populateModuleRootTable(pt: Zcu.PerThread) error{2505pub fn populateModuleRootTable(pt: Zcu.PerThread) Allocator.Error!void {
2498 OutOfMemory,
2499 /// One of the specified modules had its root source file at an illegal path.
2500 IllegalZigImport,
2501}!void {
2502 const zcu = pt.zcu;2506 const zcu = pt.zcu;
2503 const comp = zcu.comp;2507 const comp = zcu.comp;
2504 const gpa = comp.gpa;2508 const gpa = comp.gpa;
...@@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{...@@ -2507,7 +2511,7 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
2507 // We'll initially add [mod, undefined] pairs, and when we reach the pair while2511 // We'll initially add [mod, undefined] pairs, and when we reach the pair while
2508 // iterating, rewrite the undefined value.2512 // iterating, rewrite the undefined value.
2509 const roots = &zcu.module_roots;2513 const roots = &zcu.module_roots;
2510 roots.clearRetainingCapacity();2514 assert(roots.count() == 0);
25112515
2512 // Start with:2516 // Start with:
2513 // * `std_mod`, which is the main root of analysis2517 // * `std_mod`, which is the main root of analysis
...@@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{...@@ -2542,7 +2546,9 @@ pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
2542 errdefer path.deinit(gpa);2546 errdefer path.deinit(gpa);
25432547
2544 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {2548 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {
2545 return error.IllegalZigImport;2549 // One of the specified modules had its root source file at an illegal path.
2550 zcu.illegal_module_root = mod;
2551 return;
2546 }2552 }
25472553
2548 const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu });2554 const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu });
...@@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct...@@ -2781,15 +2787,21 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct
2781 const gpa = comp.gpa;2787 const gpa = comp.gpa;
2782 const io = comp.io;2788 const io = comp.io;
27832789
2784 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());2790 const mod: *Module = mod: {
2785 if (gop.found_existing) return .{ // the `File` is up-to-date2791 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());
2786 .file = zcu.module_roots.get(gop.value_ptr.*).?.unwrap().?,2792 if (!gop.found_existing) {
2787 .module_root = gop.value_ptr.*,2793 errdefer _ = zcu.builtin_modules.pop();
2794 gop.value_ptr.* = try .createBuiltin(comp.arena, opts, comp.dirs);
2795 }
2796 const mod = gop.value_ptr.*;
2797 assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin
2798 break :mod mod;
2788 };2799 };
2789 errdefer _ = zcu.builtin_modules.pop();
27902800
2791 const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs);2801 if (zcu.module_roots.get(mod)) |file| {
2792 assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin2802 // We have already loaded this builtin.zig before!
2803 return .{ .file = file.unwrap().?, .module_root = mod };
2804 }
27932805
2794 const path = try mod.root.join(gpa, comp.dirs, "builtin.zig");2806 const path = try mod.root.join(gpa, comp.dirs, "builtin.zig");
2795 errdefer path.deinit(gpa);2807 errdefer path.deinit(gpa);
...@@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct...@@ -2827,7 +2839,6 @@ fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!struct
2827 .root_type = .none,2839 .root_type = .none,
2828 });2840 });
28292841
2830 gop.value_ptr.* = mod;
2831 file_gop.key_ptr.* = file_index;2842 file_gop.key_ptr.* = file_index;
2832 zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional());2843 zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional());
2833 try opts.populateFile(gpa, file);2844 try opts.populateFile(gpa, file);
...@@ -2883,22 +2894,19 @@ pub fn embedFile(...@@ -2883,22 +2894,19 @@ pub fn embedFile(
2883 return @fromBackingInt(@intCast(gop.index));2894 return @fromBackingInt(@intCast(gop.index));
2884 }2895 }
2885 errdefer _ = zcu.embed_table.pop();2896 errdefer _ = zcu.embed_table.pop();
2886 gop.key_ptr.* = try pt.newEmbedFile(path);2897 try pt.initEmbedFile(gop.key_ptr, path);
2887 return @fromBackingInt(@intCast(gop.index));2898 return @fromBackingInt(@intCast(gop.index));
2888 }2899 }
28892900
2890 const embed_file: *Zcu.EmbedFile, const embed_file_idx: Zcu.EmbedFile.Index = ef: {2901 const embed_file, const embed_file_idx: Zcu.EmbedFile.Index = ef: {
2891 const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string);2902 const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string);
2892 errdefer path.deinit(gpa);2903 errdefer path.deinit(gpa);
2893 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});2904 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});
2894 if (gop.found_existing) {2905 if (!gop.found_existing) {
2895 path.deinit(gpa); // we're not using this key
2896 break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) };
2897 } else {
2898 errdefer _ = zcu.embed_table.pop();2906 errdefer _ = zcu.embed_table.pop();
2899 gop.key_ptr.* = try pt.newEmbedFile(path);2907 try pt.initEmbedFile(gop.key_ptr, path);
2900 break :ef .{ gop.key_ptr.*, @fromBackingInt(@intCast(gop.index)) };2908 } else path.deinit(gpa); // we're not using this key
2901 }2909 break :ef .{ gop.key_ptr, @fromBackingInt(@intCast(gop.index)) };
2902 };2910 };
29032911
2904 switch (embed_file.path.isNested(cur_file.mod.?.root)) {2912 switch (embed_file.path.isNested(cur_file.mod.?.root)) {
...@@ -2913,7 +2921,7 @@ pub fn updateEmbedFile(...@@ -2913,7 +2921,7 @@ pub fn updateEmbedFile(
2913 pt: Zcu.PerThread,2921 pt: Zcu.PerThread,
2914 ef: *Zcu.EmbedFile,2922 ef: *Zcu.EmbedFile,
2915 /// If not `null`, the interned file data is stored here, if it was loaded.2923 /// If not `null`, the interned file data is stored here, if it was loaded.
2916 /// `newEmbedFile` uses this to add the file to the `whole` cache manifest.2924 /// `initEmbedFile` uses this to add the file to the `whole` cache manifest.
2917 ip_str_out: ?*?InternPool.String,2925 ip_str_out: ?*?InternPool.String,
2918) Allocator.Error!void {2926) Allocator.Error!void {
2919 pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) {2927 pt.updateEmbedFileInner(ef, ip_str_out) catch |err| switch (err) {
...@@ -3000,17 +3008,13 @@ fn updateEmbedFileInner(...@@ -3000,17 +3008,13 @@ fn updateEmbedFileInner(
3000}3008}
30013009
3002/// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success.3010/// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success.
3003fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.EmbedFile {3011fn initEmbedFile(pt: Zcu.PerThread, ef: *Zcu.EmbedFile, path: Compilation.Path) EmbedFileError!void {
3004 const zcu = pt.zcu;3012 const zcu = pt.zcu;
3005 const comp = zcu.comp;3013 const comp = zcu.comp;
3006 const io = comp.io;3014 const io = comp.io;
3007 const gpa = comp.gpa;
3008 const ip = &zcu.intern_pool;3015 const ip = &zcu.intern_pool;
30093016
3010 const new_file = try gpa.create(Zcu.EmbedFile);3017 ef.* = .{
3011 errdefer gpa.destroy(new_file);
3012
3013 new_file.* = .{
3014 .path = path,3018 .path = path,
3015 .val = .none,3019 .val = .none,
3016 .err = null,3020 .err = null,
...@@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E...@@ -3018,7 +3022,7 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E
3018 };3022 };
30193023
3020 var opt_ip_str: ?InternPool.String = null;3024 var opt_ip_str: ?InternPool.String = null;
3021 try pt.updateEmbedFile(new_file, &opt_ip_str);3025 try pt.updateEmbedFile(ef, &opt_ip_str);
30223026
3023 try comp.appendFileSystemInput(path);3027 try comp.appendFileSystemInput(path);
30243028
...@@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E...@@ -3031,19 +3035,17 @@ fn newEmbedFile(pt: Zcu.PerThread, path: Compilation.Path) EmbedFileError!*Zcu.E
3031 const man = whole.cache_manifest orelse break :cache;3035 const man = whole.cache_manifest orelse break :cache;
3032 const ip_str = opt_ip_str orelse break :cache; // this will be a compile error3036 const ip_str = opt_ip_str orelse break :cache; // this will be a compile error
30333037
3034 const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu);3038 const array_len = Value.fromInterned(ef.val).typeOf(zcu).childType(zcu).arrayLen(zcu);
3035 const contents = ip_str.toSlice(array_len, ip);3039 const contents = ip_str.toSlice(array_len, ip);
30363040
3037 try whole.cache_manifest_mutex.lock(io);3041 try whole.cache_manifest_mutex.lock(io);
3038 defer whole.cache_manifest_mutex.unlock(io);3042 defer whole.cache_manifest_mutex.unlock(io);
30393043
3040 path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, new_file.stat) catch |err| switch (err) {3044 path.addToCacheManifestAsDiscovered(man, &comp.dirs, contents, ef.stat) catch |err| switch (err) {
3041 error.FileSystemFailure => unreachable, // contents and stat are both provided3045 error.FileSystemFailure => unreachable, // contents and stat are both provided
3042 else => |e| return e,3046 else => |e| return e,
3043 };3047 };
3044 }3048 }
3045
3046 return new_file;
3047}3049}
30483050
3049pub fn scanNamespace(3051pub fn scanNamespace(
...@@ -3242,9 +3244,9 @@ const ScanDeclIter = struct {...@@ -3242,9 +3244,9 @@ const ScanDeclIter = struct {
3242 // Perhaps we should add all test indiscriminately and filter at the end of the update.3244 // Perhaps we should add all test indiscriminately and filter at the end of the update.
3243 if (!comp.config.is_test) break :a false;3245 if (!comp.config.is_test) break :a false;
3244 if (file.mod != zcu.main_mod) break :a false;3246 if (file.mod != zcu.main_mod) break :a false;
3245 if (is_named and comp.test_filters.len > 0) {3247 if (is_named and zcu.test_filters.len > 0) {
3246 const fqn_slice = fqn.toSlice(ip);3248 const fqn_slice = fqn.toSlice(ip);
3247 for (comp.test_filters) |test_filter| {3249 for (zcu.test_filters) |test_filter| {
3248 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;3250 if (std.mem.find(u8, fqn_slice, test_filter) != null) break;
3249 } else break :a false;3251 } else break :a false;
3250 }3252 }
src/main.zig+1-4
...@@ -4413,13 +4413,12 @@ fn serve(...@@ -4413,13 +4413,12 @@ fn serve(
4413 switch (hdr.tag) {4413 switch (hdr.tag) {
4414 .exit => return cleanExit(io),4414 .exit => return cleanExit(io),
4415 .update => {4415 .update => {
4416 file_system_inputs.clearRetainingCapacity();
4417
4418 if (arg_mode == .translate_c) {4416 if (arg_mode == .translate_c) {
4419 var arena_instance = std.heap.ArenaAllocator.init(gpa);4417 var arena_instance = std.heap.ArenaAllocator.init(gpa);
4420 defer arena_instance.deinit();4418 defer arena_instance.deinit();
4421 const arena = arena_instance.allocator();4419 const arena = arena_instance.allocator();
4422 var output: Compilation.TranslateCResult = undefined;4420 var output: Compilation.TranslateCResult = undefined;
4421 file_system_inputs.clearRetainingCapacity();
4423 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map);4422 try cmdTranslateC(comp, arena, &output, file_system_inputs, main_progress_node, environ_map);
4424 defer output.deinit(gpa);4423 defer output.deinit(gpa);
44254424
...@@ -4437,7 +4436,6 @@ fn serve(...@@ -4437,7 +4436,6 @@ fn serve(
44374436
4438 continue;4437 continue;
4439 }4438 }
4440
4441 try comp.makeBinFileWritable();4439 try comp.makeBinFileWritable();
4442 try comp.update(main_progress_node);4440 try comp.update(main_progress_node);
4443 try comp.makeBinFileExecutable();4441 try comp.makeBinFileExecutable();
...@@ -4463,7 +4461,6 @@ fn serve(...@@ -4463,7 +4461,6 @@ fn serve(
4463 //);4461 //);
4464 },4462 },
4465 .hot_update => {4463 .hot_update => {
4466 file_system_inputs.clearRetainingCapacity();
4467 if (child_pid) |pid| {4464 if (child_pid) |pid| {
4468 try comp.hotCodeSwap(main_progress_node, pid);4465 try comp.hotCodeSwap(main_progress_node, pid);
4469 try serveUpdateResults(&server, comp);4466 try serveUpdateResults(&server, comp);
test/src/Cases.zig-1
...@@ -75,7 +75,6 @@ pub const Case = struct {...@@ -75,7 +75,6 @@ pub const Case = struct {
7575
76 emit_asm: bool = false,76 emit_asm: bool = false,
77 emit_bin: bool = true,77 emit_bin: bool = true,
78 emit_h: bool = false,
79 is_test: bool = false,78 is_test: bool = false,
80 expect_exact: bool = false,79 expect_exact: bool = false,
81 backend: Backend = .auto,80 backend: Backend = .auto,