authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-20 03:25:19+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-05-20 03:25:19+01:00
log23c817548bbd3988a5fd224b590a4f6102dbe5db
tree5448478794cb493b456de356c2e29fb100e81cfb
parentf2077f57ae03ef21f1bfee6e4e041c5f466fc3be
parent37a9a4e0f16c1df8de3a4add3a9566b24f024a95
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #23836 from mlugg/incr-fixes

Incremental fixes, refactor `Zcu.File`

53 files changed, 2796 insertions(+), 2394 deletions(-)

build.zig+11-6
......@@ -508,11 +508,9 @@ pub fn build(b: *std.Build) !void {
508508 test_step.dependOn(unit_tests_step);
509509
510510 const unit_tests = b.addTest(.{
511 .root_module = b.createModule(.{
512 .root_source_file = b.path("src/main.zig"),
511 .root_module = addCompilerMod(b, .{
513512 .optimize = optimize,
514513 .target = target,
515 .link_libc = link_libc,
516514 .single_threaded = single_threaded,
517515 }),
518516 .filters = test_filters,
......@@ -520,6 +518,9 @@ pub fn build(b: *std.Build) !void {
520518 .use_lld = use_llvm,
521519 .zig_lib_dir = b.path("lib"),
522520 });
521 if (link_libc) {
522 unit_tests.root_module.link_libc = true;
523 }
523524 unit_tests.root_module.addOptions("build_options", exe_options);
524525 unit_tests_step.dependOn(&b.addRunArtifact(unit_tests).step);
525526
......@@ -650,7 +651,7 @@ fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {
650651 update_zig1_step.dependOn(&copy_zig_h.step);
651652}
652653
653const AddCompilerStepOptions = struct {
654const AddCompilerModOptions = struct {
654655 optimize: std.builtin.OptimizeMode,
655656 target: std.Build.ResolvedTarget,
656657 strip: ?bool = null,
......@@ -659,7 +660,7 @@ const AddCompilerStepOptions = struct {
659660 single_threaded: ?bool = null,
660661};
661662
662fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.Step.Compile {
663fn addCompilerMod(b: *std.Build, options: AddCompilerModOptions) *std.Build.Module {
663664 const compiler_mod = b.createModule(.{
664665 .root_source_file = b.path("src/main.zig"),
665666 .target = options.target,
......@@ -682,10 +683,14 @@ fn addCompilerStep(b: *std.Build, options: AddCompilerStepOptions) *std.Build.St
682683 compiler_mod.addImport("aro", aro_mod);
683684 compiler_mod.addImport("aro_translate_c", aro_translate_c_mod);
684685
686 return compiler_mod;
687}
688
689fn addCompilerStep(b: *std.Build, options: AddCompilerModOptions) *std.Build.Step.Compile {
685690 const exe = b.addExecutable(.{
686691 .name = "zig",
687692 .max_rss = 7_800_000_000,
688 .root_module = compiler_mod,
693 .root_module = addCompilerMod(b, options),
689694 });
690695 exe.stack_size = stack_size;
691696
lib/std/Build/Cache.zig+2-3
......@@ -1011,17 +1011,16 @@ pub const Manifest = struct {
10111011 }
10121012
10131013 /// Like `addFilePost` but when the file contents have already been loaded from disk.
1014 /// On success, cache takes ownership of `resolved_path`.
10151014 pub fn addFilePostContents(
10161015 self: *Manifest,
1017 resolved_path: []u8,
1016 file_path: []const u8,
10181017 bytes: []const u8,
10191018 stat: File.Stat,
10201019 ) !void {
10211020 assert(self.manifest_file != null);
10221021 const gpa = self.cache.gpa;
10231022
1024 const prefixed_path = try self.cache.findPrefixResolved(resolved_path);
1023 const prefixed_path = try self.cache.findPrefix(file_path);
10251024 errdefer gpa.free(prefixed_path.sub_path);
10261025
10271026 const gop = try self.files.getOrPutAdapted(gpa, prefixed_path, FilesAdapter{});
src/Builtin.zig+64-27
......@@ -19,6 +19,26 @@ code_model: std.builtin.CodeModel,
1919omit_frame_pointer: bool,
2020wasi_exec_model: std.builtin.WasiExecModel,
2121
22/// Compute an abstract hash representing this `Builtin`. This is *not* a hash
23/// of the resulting file contents.
24pub fn hash(opts: @This()) [std.Build.Cache.bin_digest_len]u8 {
25 var h: Cache.Hasher = Cache.hasher_init;
26 inline for (@typeInfo(@This()).@"struct".fields) |f| {
27 if (comptime std.mem.eql(u8, f.name, "target")) {
28 // This needs special handling.
29 std.hash.autoHash(&h, opts.target.cpu);
30 std.hash.autoHash(&h, opts.target.os.tag);
31 std.hash.autoHash(&h, opts.target.os.versionRange());
32 std.hash.autoHash(&h, opts.target.abi);
33 std.hash.autoHash(&h, opts.target.ofmt);
34 std.hash.autoHash(&h, opts.target.dynamic_linker);
35 } else {
36 std.hash.autoHash(&h, @field(opts, f.name));
37 }
38 }
39 return h.finalResult();
40}
41
2242pub fn generate(opts: @This(), allocator: Allocator) Allocator.Error![:0]u8 {
2343 var buffer = std.ArrayList(u8).init(allocator);
2444 try append(opts, &buffer);
......@@ -263,50 +283,66 @@ pub fn append(opts: @This(), buffer: *std.ArrayList(u8)) Allocator.Error!void {
263283 }
264284}
265285
266pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
267 if (mod.root.statFile(mod.root_src_path)) |stat| {
286/// This essentially takes the place of `Zcu.PerThread.updateFile`, but for 'builtin' modules.
287/// Instead of reading the file from disk, its contents are generated in-memory.
288pub fn populateFile(opts: @This(), gpa: Allocator, file: *File) Allocator.Error!void {
289 assert(file.is_builtin);
290 assert(file.status == .never_loaded);
291 assert(file.source == null);
292 assert(file.tree == null);
293 assert(file.zir == null);
294
295 file.source = try opts.generate(gpa);
296
297 log.debug("parsing and generating 'builtin.zig'", .{});
298
299 file.tree = try std.zig.Ast.parse(gpa, file.source.?, .zig);
300 assert(file.tree.?.errors.len == 0); // builtin.zig must parse
301
302 file.zir = try AstGen.generate(gpa, file.tree.?);
303 assert(!file.zir.?.hasCompileErrors()); // builtin.zig must not have astgen errors
304 file.status = .success;
305}
306
307/// After `populateFile` succeeds, call this function to write the generated file out to disk
308/// if necessary. This is useful for external tooling such as debuggers.
309/// Assumes that `file.mod` is correctly set to the builtin module.
310pub fn updateFileOnDisk(file: *File, comp: *Compilation) !void {
311 assert(file.is_builtin);
312 assert(file.status == .success);
313 assert(file.source != null);
314
315 const root_dir, const sub_path = file.path.openInfo(comp.dirs);
316
317 if (root_dir.statFile(sub_path)) |stat| {
268318 if (stat.size != file.source.?.len) {
269319 std.log.warn(
270 "the cached file '{}{s}' had the wrong size. Expected {d}, found {d}. " ++
320 "the cached file '{}' had the wrong size. Expected {d}, found {d}. " ++
271321 "Overwriting with correct file contents now",
272 .{ mod.root, mod.root_src_path, file.source.?.len, stat.size },
322 .{ file.path.fmt(comp), file.source.?.len, stat.size },
273323 );
274
275 try writeFile(file, mod);
276324 } else {
277325 file.stat = .{
278326 .size = stat.size,
279327 .inode = stat.inode,
280328 .mtime = stat.mtime,
281329 };
330 return;
282331 }
283332 } else |err| switch (err) {
284 error.BadPathName => unreachable, // it's always "builtin.zig"
285 error.NameTooLong => unreachable, // it's always "builtin.zig"
286 error.PipeBusy => unreachable, // it's not a pipe
287 error.NoDevice => unreachable, // it's not a pipe
288 error.WouldBlock => unreachable, // not asking for non-blocking I/O
333 error.FileNotFound => {},
289334
290 error.FileNotFound => try writeFile(file, mod),
335 error.WouldBlock => unreachable, // not asking for non-blocking I/O
336 error.BadPathName => unreachable, // it's always "o/digest/builtin.zig"
337 error.NameTooLong => unreachable, // it's always "o/digest/builtin.zig"
291338
339 // We don't expect the file to be a pipe, but can't mark `error.PipeBusy` as `unreachable`,
340 // because the user could always replace the file on disk.
292341 else => |e| return e,
293342 }
294343
295 log.debug("parsing and generating '{s}'", .{mod.root_src_path});
296
297 file.tree = try std.zig.Ast.parse(comp.gpa, file.source.?, .zig);
298 assert(file.tree.?.errors.len == 0); // builtin.zig must parse
299
300 file.zir = try AstGen.generate(comp.gpa, file.tree.?);
301 assert(!file.zir.?.hasCompileErrors()); // builtin.zig must not have astgen errors
302 file.status = .success;
303 // Note that whilst we set `zir` here, we populated `path_digest`
304 // all the way back in `Package.Module.create`.
305}
306
307fn writeFile(file: *File, mod: *Module) !void {
308 var buf: [std.fs.max_path_bytes]u8 = undefined;
309 var af = try mod.root.atomicFile(mod.root_src_path, .{ .make_path = true }, &buf);
344 // `make_path` matters because the dir hasn't actually been created yet.
345 var af = try root_dir.atomicFile(sub_path, .{ .make_path = true });
310346 defer af.deinit();
311347 try af.file.writeAll(file.source.?);
312348 af.finish() catch |err| switch (err) {
......@@ -331,6 +367,7 @@ fn writeFile(file: *File, mod: *Module) !void {
331367const builtin = @import("builtin");
332368const std = @import("std");
333369const Allocator = std.mem.Allocator;
370const Cache = std.Build.Cache;
334371const build_options = @import("build_options");
335372const Module = @import("Package/Module.zig");
336373const assert = std.debug.assert;
src/Compilation.zig+830-577
......@@ -2,6 +2,7 @@ const Compilation = @This();
22
33const std = @import("std");
44const builtin = @import("builtin");
5const fs = std.fs;
56const mem = std.mem;
67const Allocator = std.mem.Allocator;
78const assert = std.debug.assert;
......@@ -10,12 +11,13 @@ const Target = std.Target;
1011const ThreadPool = std.Thread.Pool;
1112const WaitGroup = std.Thread.WaitGroup;
1213const ErrorBundle = std.zig.ErrorBundle;
13const Path = Cache.Path;
14const fatal = std.process.fatal;
1415
1516const Value = @import("Value.zig");
1617const Type = @import("Type.zig");
1718const target_util = @import("target.zig");
1819const Package = @import("Package.zig");
20const introspect = @import("introspect.zig");
1921const link = @import("link.zig");
2022const tracy = @import("tracy.zig");
2123const trace = tracy.trace;
......@@ -28,7 +30,6 @@ const mingw = @import("libs/mingw.zig");
2830const libunwind = @import("libs/libunwind.zig");
2931const libcxx = @import("libs/libcxx.zig");
3032const wasi_libc = @import("libs/wasi_libc.zig");
31const fatal = @import("main.zig").fatal;
3233const clangMain = @import("main.zig").clangMain;
3334const Zcu = @import("Zcu.zig");
3435const Sema = @import("Sema.zig");
......@@ -43,7 +44,6 @@ const LlvmObject = @import("codegen/llvm.zig").Object;
4344const dev = @import("dev.zig");
4445const ThreadSafeQueue = @import("ThreadSafeQueue.zig").ThreadSafeQueue;
4546
46pub const Directory = Cache.Directory;
4747pub const Config = @import("Compilation/Config.zig");
4848
4949/// General-purpose allocator. Used for both temporary and long-term storage.
......@@ -75,9 +75,9 @@ bin_file: ?*link.File,
7575/// The root path for the dynamic linker and system libraries (as well as frameworks on Darwin)
7676sysroot: ?[]const u8,
7777/// This is `null` when not building a Windows DLL, or when `-fno-emit-implib` is used.
78implib_emit: ?Path,
78implib_emit: ?Cache.Path,
7979/// This is non-null when `-femit-docs` is provided.
80docs_emit: ?Path,
80docs_emit: ?Cache.Path,
8181root_name: [:0]const u8,
8282compiler_rt_strat: RtStrat,
8383ubsan_rt_strat: RtStrat,
......@@ -152,11 +152,6 @@ win32_resource_work_queue: if (dev.env.supports(.win32_resource)) std.fifo.Linea
152152 pub fn deinit(_: @This()) void {}
153153},
154154
155/// These jobs are to tokenize, parse, and astgen files, which may be outdated
156/// since the last compilation, as well as scan for `@import` and queue up
157/// additional jobs corresponding to those new files.
158astgen_work_queue: std.fifo.LinearFifo(Zcu.File.Index, .Dynamic),
159
160155/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
161156/// This data is accessed by multiple threads and is protected by `mutex`.
162157failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.Diag.Bundle) = .empty,
......@@ -207,9 +202,8 @@ cache_parent: *Cache,
207202parent_whole_cache: ?ParentWholeCache,
208203/// Path to own executable for invoking `zig clang`.
209204self_exe_path: ?[]const u8,
210zig_lib_directory: Directory,
211local_cache_directory: Directory,
212global_cache_directory: Directory,
205/// Owned by the caller of `Compilation.create`.
206dirs: Directories,
213207libc_include_dir_list: []const []const u8,
214208libc_framework_dir_list: []const []const u8,
215209rc_includes: RcIncludes,
......@@ -293,7 +287,6 @@ const QueuedJobs = struct {
293287 ubsan_rt_lib: bool = false,
294288 ubsan_rt_obj: bool = false,
295289 fuzzer_lib: bool = false,
296 update_builtin_zig: bool,
297290 musl_crt_file: [@typeInfo(musl.CrtFile).@"enum".fields.len]bool = @splat(false),
298291 glibc_crt_file: [@typeInfo(glibc.CrtFile).@"enum".fields.len]bool = @splat(false),
299292 freebsd_crt_file: [@typeInfo(freebsd.CrtFile).@"enum".fields.len]bool = @splat(false),
......@@ -312,12 +305,466 @@ const QueuedJobs = struct {
312305 zigc_lib: bool = false,
313306};
314307
308/// A filesystem path, represented relative to one of a few specific directories where possible.
309/// Every path (considering symlinks as distinct paths) has a canonical representation in this form.
310/// This abstraction allows us to:
311/// * always open files relative to a consistent root on the filesystem
312/// * detect when two paths correspond to the same file, e.g. for deduplicating `@import`s
313pub const Path = struct {
314 root: Root,
315 /// This path is always in a normalized form, where:
316 /// * All components are separated by `fs.path.sep`
317 /// * There are no repeated separators (like "foo//bar")
318 /// * There are no "." or ".." components
319 /// * There is no trailing path separator
320 ///
321 /// There is a leading separator iff `root` is `.none` *and* `builtin.target.os.tag != .wasi`.
322 ///
323 /// If this `Path` exactly represents a `Root`, the sub path is "", not ".".
324 sub_path: []u8,
325
326 const Root = enum {
327 /// `sub_path` is relative to the Zig lib directory on `Compilation`.
328 zig_lib,
329 /// `sub_path` is relative to the global cache directory on `Compilation`.
330 global_cache,
331 /// `sub_path` is relative to the local cache directory on `Compilation`.
332 local_cache,
333 /// `sub_path` is not relative to any of the roots listed above.
334 /// It is resolved starting with `Directories.cwd`; so it is an absolute path on most
335 /// targets, but cwd-relative on WASI. We do not make it cwd-relative on other targets
336 /// so that `Path.digest` gives hashes which can be stored in the Zig cache (as they
337 /// don't depend on a specific compiler instance).
338 none,
339 };
340
341 /// In general, we can only construct canonical `Path`s at runtime, because weird nesting might
342 /// mean that e.g. a sub path inside zig/lib/ is actually in the global cache. However, because
343 /// `Directories` guarantees that `zig_lib` is a distinct path from both cache directories, it's
344 /// okay for us to construct this path, and only this path, as a comptime constant.
345 pub const zig_lib_root: Path = .{ .root = .zig_lib, .sub_path = "" };
346
347 pub fn deinit(p: Path, gpa: Allocator) void {
348 gpa.free(p.sub_path);
349 }
350
351 /// The returned digest is relocatable across any compiler process using the same lib and cache
352 /// directories; it does not depend on cwd.
353 pub fn digest(p: Path) Cache.BinDigest {
354 var h = Cache.hasher_init;
355 h.update(&.{@intFromEnum(p.root)});
356 h.update(p.sub_path);
357 return h.finalResult();
358 }
359
360 /// Given a `Path`, returns the directory handle and sub path to be used to open the path.
361 pub fn openInfo(p: Path, dirs: Directories) struct { fs.Dir, []const u8 } {
362 const dir = switch (p.root) {
363 .none => {
364 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);
365 return .{ fs.cwd(), cwd_sub_path };
366 },
367 .zig_lib => dirs.zig_lib.handle,
368 .global_cache => dirs.global_cache.handle,
369 .local_cache => dirs.local_cache.handle,
370 };
371 if (p.sub_path.len == 0) return .{ dir, "." };
372 assert(!fs.path.isAbsolute(p.sub_path));
373 return .{ dir, p.sub_path };
374 }
375
376 pub const format = unreachable; // do not format direcetly
377 pub fn fmt(p: Path, comp: *Compilation) Formatter {
378 return .{ .p = p, .comp = comp };
379 }
380 const Formatter = struct {
381 p: Path,
382 comp: *Compilation,
383 pub fn format(f: Formatter, comptime unused_fmt: []const u8, options: std.fmt.FormatOptions, w: anytype) !void {
384 comptime assert(unused_fmt.len == 0);
385 _ = options;
386 const root_path: []const u8 = switch (f.p.root) {
387 .zig_lib => f.comp.dirs.zig_lib.path orelse ".",
388 .global_cache => f.comp.dirs.global_cache.path orelse ".",
389 .local_cache => f.comp.dirs.local_cache.path orelse ".",
390 .none => {
391 const cwd_sub_path = absToCwdRelative(f.p.sub_path, f.comp.dirs.cwd);
392 try w.writeAll(cwd_sub_path);
393 return;
394 },
395 };
396 assert(root_path.len != 0);
397 try w.writeAll(root_path);
398 if (f.p.sub_path.len > 0) {
399 try w.writeByte(fs.path.sep);
400 try w.writeAll(f.p.sub_path);
401 }
402 }
403 };
404
405 /// Given the `sub_path` of a `Path` with `Path.root == .none`, attempts to convert
406 /// the (absolute) path to a cwd-relative path. Otherwise, returns the absolute path
407 /// unmodified. The returned string is never empty: "" is converted to ".".
408 fn absToCwdRelative(sub_path: []const u8, cwd_path: []const u8) []const u8 {
409 if (builtin.target.os.tag == .wasi) {
410 if (sub_path.len == 0) return ".";
411 assert(!fs.path.isAbsolute(sub_path));
412 return sub_path;
413 }
414 assert(fs.path.isAbsolute(sub_path));
415 if (!std.mem.startsWith(u8, sub_path, cwd_path)) return sub_path;
416 if (sub_path.len == cwd_path.len) return "."; // the strings are equal
417 if (sub_path[cwd_path.len] != fs.path.sep) return sub_path; // last component before cwd differs
418 return sub_path[cwd_path.len + 1 ..]; // remove '/path/to/cwd/' prefix
419 }
420
421 /// From an unresolved path (which can be made of multiple not-yet-joined strings), construct a
422 /// canonical `Path`.
423 pub fn fromUnresolved(gpa: Allocator, dirs: Compilation.Directories, unresolved_parts: []const []const u8) Allocator.Error!Path {
424 const resolved = try introspect.resolvePath(gpa, dirs.cwd, unresolved_parts);
425 errdefer gpa.free(resolved);
426
427 // If, for instance, `dirs.local_cache.path` is within the lib dir, it must take priority,
428 // so that we prefer `.root = .local_cache` over `.root = .zig_lib`. The easiest way to do
429 // this is simply to prioritize the longest root path.
430 const PathAndRoot = struct { ?[]const u8, Root };
431 var roots: [3]PathAndRoot = .{
432 .{ dirs.zig_lib.path, .zig_lib },
433 .{ dirs.global_cache.path, .global_cache },
434 .{ dirs.local_cache.path, .local_cache },
435 };
436 // This must be a stable sort, because the global and local cache directories may be the same, in
437 // which case we need to make a consistent choice.
438 std.mem.sort(PathAndRoot, &roots, {}, struct {
439 fn lessThan(_: void, lhs: PathAndRoot, rhs: PathAndRoot) bool {
440 const lhs_path_len = if (lhs[0]) |p| p.len else 0;
441 const rhs_path_len = if (rhs[0]) |p| p.len else 0;
442 return lhs_path_len > rhs_path_len; // '>' instead of '<' to sort descending
443 }
444 }.lessThan);
445
446 for (roots) |path_and_root| {
447 const opt_root_path, const root = path_and_root;
448 const root_path = opt_root_path orelse {
449 // This root is the cwd.
450 if (!fs.path.isAbsolute(resolved)) {
451 return .{
452 .root = root,
453 .sub_path = resolved,
454 };
455 }
456 continue;
457 };
458 if (!mem.startsWith(u8, resolved, root_path)) continue;
459 const sub: []const u8 = if (resolved.len != root_path.len) sub: {
460 // Check the trailing slash, so that we don't match e.g. `/foo/bar` with `/foo/barren`
461 if (resolved[root_path.len] != fs.path.sep) continue;
462 break :sub resolved[root_path.len + 1 ..];
463 } else "";
464 const duped = try gpa.dupe(u8, sub);
465 gpa.free(resolved);
466 return .{ .root = root, .sub_path = duped };
467 }
468
469 // We're not relative to any root, so we will use an absolute path (on targets where they are available).
470
471 if (builtin.target.os.tag == .wasi or fs.path.isAbsolute(resolved)) {
472 // `resolved` is already absolute (or we're on WASI, where absolute paths don't really exist).
473 return .{ .root = .none, .sub_path = resolved };
474 }
475
476 if (resolved.len == 0) {
477 // We just need the cwd path, no trailing separator. Note that `gpa.free(resolved)` would be a nop.
478 return .{ .root = .none, .sub_path = try gpa.dupe(u8, dirs.cwd) };
479 }
480
481 // We need to make an absolute path. Because `resolved` came from `introspect.resolvePath`, we can just
482 // join the paths with a simple format string.
483 const abs_path = try std.fmt.allocPrint(gpa, "{s}{c}{s}", .{ dirs.cwd, fs.path.sep, resolved });
484 gpa.free(resolved);
485 return .{ .root = .none, .sub_path = abs_path };
486 }
487
488 /// Constructs a canonical `Path` representing `sub_path` relative to `root`.
489 ///
490 /// If `sub_path` is resolved, this is almost like directly constructing a `Path`, but this
491 /// function also canonicalizes the result, which matters because `sub_path` may move us into
492 /// a different root.
493 ///
494 /// For instance, if the Zig lib directory is inside the global cache, passing `root` as
495 /// `.global_cache` could still end up returning a `Path` with `Path.root == .zig_lib`.
496 pub fn fromRoot(
497 gpa: Allocator,
498 dirs: Compilation.Directories,
499 root: Path.Root,
500 sub_path: []const u8,
501 ) Allocator.Error!Path {
502 // Currently, this just wraps `fromUnresolved` for simplicity. A more efficient impl is
503 // probably possible if this function ever ends up impacting performance somehow.
504 return .fromUnresolved(gpa, dirs, &.{
505 switch (root) {
506 .zig_lib => dirs.zig_lib.path orelse "",
507 .global_cache => dirs.global_cache.path orelse "",
508 .local_cache => dirs.local_cache.path orelse "",
509 .none => "",
510 },
511 sub_path,
512 });
513 }
514
515 /// Given a `Path` and an (unresolved) sub path relative to it, construct a `Path` representing
516 /// the joined path `p/sub_path`. Note that, like with `fromRoot`, the `sub_path` might cause us
517 /// to move into a different `Path.Root`.
518 pub fn join(
519 p: Path,
520 gpa: Allocator,
521 dirs: Compilation.Directories,
522 sub_path: []const u8,
523 ) Allocator.Error!Path {
524 // Currently, this just wraps `fromUnresolved` for simplicity. A more efficient impl is
525 // probably possible if this function ever ends up impacting performance somehow.
526 return .fromUnresolved(gpa, dirs, &.{
527 switch (p.root) {
528 .zig_lib => dirs.zig_lib.path orelse "",
529 .global_cache => dirs.global_cache.path orelse "",
530 .local_cache => dirs.local_cache.path orelse "",
531 .none => "",
532 },
533 p.sub_path,
534 sub_path,
535 });
536 }
537
538 /// Like `join`, but `sub_path` is relative to the dirname of `p` instead of `p` itself.
539 pub fn upJoin(
540 p: Path,
541 gpa: Allocator,
542 dirs: Compilation.Directories,
543 sub_path: []const u8,
544 ) Allocator.Error!Path {
545 return .fromUnresolved(gpa, dirs, &.{
546 switch (p.root) {
547 .zig_lib => dirs.zig_lib.path orelse "",
548 .global_cache => dirs.global_cache.path orelse "",
549 .local_cache => dirs.local_cache.path orelse "",
550 .none => "",
551 },
552 p.sub_path,
553 "..",
554 sub_path,
555 });
556 }
557
558 pub fn toCachePath(p: Path, dirs: Directories) Cache.Path {
559 const root_dir: Cache.Directory = switch (p.root) {
560 .zig_lib => dirs.zig_lib,
561 .global_cache => dirs.global_cache,
562 .local_cache => dirs.local_cache,
563 else => {
564 const cwd_sub_path = absToCwdRelative(p.sub_path, dirs.cwd);
565 return .{
566 .root_dir = .cwd(),
567 .sub_path = cwd_sub_path,
568 };
569 },
570 };
571 assert(!fs.path.isAbsolute(p.sub_path));
572 return .{
573 .root_dir = root_dir,
574 .sub_path = p.sub_path,
575 };
576 }
577
578 /// This should not be used for most of the compiler pipeline, but is useful when emitting
579 /// paths from the compilation (e.g. in debug info), because they will not depend on the cwd.
580 /// The returned path is owned by the caller and allocated into `gpa`.
581 pub fn toAbsolute(p: Path, dirs: Directories, gpa: Allocator) Allocator.Error![]u8 {
582 const root_path: []const u8 = switch (p.root) {
583 .zig_lib => dirs.zig_lib.path orelse "",
584 .global_cache => dirs.global_cache.path orelse "",
585 .local_cache => dirs.local_cache.path orelse "",
586 .none => "",
587 };
588 return fs.path.resolve(gpa, &.{
589 dirs.cwd,
590 root_path,
591 p.sub_path,
592 });
593 }
594
595 pub fn isNested(inner: Path, outer: Path) union(enum) {
596 /// Value is the sub path, which is a sub-slice of `inner.sub_path`.
597 yes: []const u8,
598 no,
599 different_roots,
600 } {
601 if (inner.root != outer.root) return .different_roots;
602 if (!mem.startsWith(u8, inner.sub_path, outer.sub_path)) return .no;
603 if (inner.sub_path.len == outer.sub_path.len) return .no;
604 if (outer.sub_path.len == 0) return .{ .yes = inner.sub_path };
605 if (inner.sub_path[outer.sub_path.len] != fs.path.sep) return .no;
606 return .{ .yes = inner.sub_path[outer.sub_path.len + 1 ..] };
607 }
608
609 /// Returns whether this `Path` is illegal to have as a user-imported `Zcu.File` (including
610 /// as the root of a module). Such paths exist in directories which the Zig compiler treats
611 /// specially, like 'global_cache/b/', which stores 'builtin.zig' files.
612 pub fn isIllegalZigImport(p: Path, gpa: Allocator, dirs: Directories) Allocator.Error!bool {
613 const zig_builtin_dir: Path = try .fromRoot(gpa, dirs, .global_cache, "b");
614 defer zig_builtin_dir.deinit(gpa);
615 return switch (p.isNested(zig_builtin_dir)) {
616 .yes => true,
617 .no, .different_roots => false,
618 };
619 }
620};
621
622pub const Directories = struct {
623 /// The string returned by `introspect.getResolvedCwd`. This is typically an absolute path,
624 /// but on WASI is the empty string "" instead, because WASI does not have absolute paths.
625 cwd: []const u8,
626 /// The Zig 'lib' directory.
627 /// `zig_lib.path` is resolved (`introspect.resolvePath`) or `null` for cwd.
628 /// Guaranteed to be a different path from `global_cache` and `local_cache`.
629 zig_lib: Cache.Directory,
630 /// The global Zig cache directory.
631 /// `global_cache.path` is resolved (`introspect.resolvePath`) or `null` for cwd.
632 global_cache: Cache.Directory,
633 /// The local Zig cache directory.
634 /// `local_cache.path` is resolved (`introspect.resolvePath`) or `null` for cwd.
635 /// This may be the same as `global_cache`.
636 local_cache: Cache.Directory,
637
638 pub fn deinit(dirs: *Directories) void {
639 // The local and global caches could be the same.
640 const close_local = dirs.local_cache.handle.fd != dirs.global_cache.handle.fd;
641
642 dirs.global_cache.handle.close();
643 if (close_local) dirs.local_cache.handle.close();
644 dirs.zig_lib.handle.close();
645 }
646
647 /// Returns a `Directories` where `local_cache` is replaced with `global_cache`, intended for
648 /// use by sub-compilations (e.g. compiler_rt). Do not `deinit` the returned `Directories`; it
649 /// shares handles with `dirs`.
650 pub fn withoutLocalCache(dirs: Directories) Directories {
651 return .{
652 .cwd = dirs.cwd,
653 .zig_lib = dirs.zig_lib,
654 .global_cache = dirs.global_cache,
655 .local_cache = dirs.global_cache,
656 };
657 }
658
659 /// Uses `std.process.fatal` on error conditions.
660 pub fn init(
661 arena: Allocator,
662 override_zig_lib: ?[]const u8,
663 override_global_cache: ?[]const u8,
664 local_cache_strat: union(enum) {
665 override: []const u8,
666 search,
667 global,
668 },
669 wasi_preopens: switch (builtin.target.os.tag) {
670 .wasi => std.fs.wasi.Preopens,
671 else => void,
672 },
673 self_exe_path: switch (builtin.target.os.tag) {
674 .wasi => void,
675 else => []const u8,
676 },
677 ) Directories {
678 const wasi = builtin.target.os.tag == .wasi;
679
680 const cwd = introspect.getResolvedCwd(arena) catch |err| {
681 fatal("unable to get cwd: {s}", .{@errorName(err)});
682 };
683
684 const zig_lib: Cache.Directory = d: {
685 if (override_zig_lib) |path| break :d openUnresolved(arena, cwd, path, .@"zig lib");
686 if (wasi) break :d openWasiPreopen(wasi_preopens, "/lib");
687 break :d introspect.findZigLibDirFromSelfExe(arena, cwd, self_exe_path) catch |err| {
688 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
689 };
690 };
691
692 const global_cache: Cache.Directory = d: {
693 if (override_global_cache) |path| break :d openUnresolved(arena, cwd, path, .@"global cache");
694 if (wasi) break :d openWasiPreopen(wasi_preopens, "/cache");
695 const path = introspect.resolveGlobalCacheDir(arena) catch |err| {
696 fatal("unable to resolve zig cache directory: {s}", .{@errorName(err)});
697 };
698 break :d openUnresolved(arena, cwd, path, .@"global cache");
699 };
700
701 const local_cache: Cache.Directory = switch (local_cache_strat) {
702 .override => |path| openUnresolved(arena, cwd, path, .@"local cache"),
703 .search => d: {
704 const maybe_path = introspect.resolveSuitableLocalCacheDir(arena, cwd) catch |err| {
705 fatal("unable to resolve zig cache directory: {s}", .{@errorName(err)});
706 };
707 const path = maybe_path orelse break :d global_cache;
708 break :d openUnresolved(arena, cwd, path, .@"local cache");
709 },
710 .global => global_cache,
711 };
712
713 if (std.mem.eql(u8, zig_lib.path orelse "", global_cache.path orelse "")) {
714 fatal("zig lib directory '{}' cannot be equal to global cache directory '{}'", .{ zig_lib, global_cache });
715 }
716 if (std.mem.eql(u8, zig_lib.path orelse "", local_cache.path orelse "")) {
717 fatal("zig lib directory '{}' cannot be equal to local cache directory '{}'", .{ zig_lib, local_cache });
718 }
719
720 return .{
721 .cwd = cwd,
722 .zig_lib = zig_lib,
723 .global_cache = global_cache,
724 .local_cache = local_cache,
725 };
726 }
727 fn openWasiPreopen(preopens: std.fs.wasi.Preopens, name: []const u8) Cache.Directory {
728 return .{
729 .path = if (std.mem.eql(u8, name, ".")) null else name,
730 .handle = .{
731 .fd = preopens.find(name) orelse fatal("WASI preopen not found: '{s}'", .{name}),
732 },
733 };
734 }
735 fn openUnresolved(arena: Allocator, cwd: []const u8, unresolved_path: []const u8, thing: enum { @"zig lib", @"global cache", @"local cache" }) Cache.Directory {
736 const path = introspect.resolvePath(arena, cwd, &.{unresolved_path}) catch |err| {
737 fatal("unable to resolve {s} directory: {s}", .{ @tagName(thing), @errorName(err) });
738 };
739 const nonempty_path = if (path.len == 0) "." else path;
740 const handle_or_err = switch (thing) {
741 .@"zig lib" => std.fs.cwd().openDir(nonempty_path, .{}),
742 .@"global cache", .@"local cache" => std.fs.cwd().makeOpenPath(nonempty_path, .{}),
743 };
744 return .{
745 .path = if (path.len == 0) null else path,
746 .handle = handle_or_err catch |err| {
747 const extra_str: []const u8 = e: {
748 if (thing == .@"global cache") switch (err) {
749 error.AccessDenied, error.ReadOnlyFileSystem => break :e "\n" ++
750 "If this location is not writable then consider specifying an alternative with " ++
751 "the ZIG_GLOBAL_CACHE_DIR environment variable or the --global-cache-dir option.",
752 else => {},
753 };
754 break :e "";
755 };
756 fatal("unable to open {s} directory '{s}': {s}{s}", .{ @tagName(thing), nonempty_path, @errorName(err), extra_str });
757 },
758 };
759 }
760};
761
315762pub const default_stack_protector_buffer_size = target_util.default_stack_protector_buffer_size;
316763pub const SemaError = Zcu.SemaError;
317764
318765pub const CrtFile = struct {
319766 lock: Cache.Lock,
320 full_object_path: Path,
767 full_object_path: Cache.Path,
321768
322769 pub fn isObject(cf: CrtFile) bool {
323770 return switch (classifyFileExt(cf.full_object_path.sub_path)) {
......@@ -430,7 +877,7 @@ pub const CObject = struct {
430877 new,
431878 success: struct {
432879 /// The outputted result. `sub_path` owned by gpa.
433 object_path: Path,
880 object_path: Cache.Path,
434881 /// This is a file system lock on the cache hash manifest representing this
435882 /// object. It prevents other invocations of the Zig compiler from interfering
436883 /// with this object until released.
......@@ -854,7 +1301,7 @@ pub const MiscError = struct {
8541301pub const EmitLoc = struct {
8551302 /// If this is `null` it means the file will be output to the cache directory.
8561303 /// When provided, both the open file handle and the path name must outlive the `Compilation`.
857 directory: ?Compilation.Directory,
1304 directory: ?Cache.Directory,
8581305 /// This may not have sub-directories in it.
8591306 basename: []const u8,
8601307};
......@@ -977,7 +1424,7 @@ const CacheUse = union(CacheMode) {
9771424 implib_sub_path: ?[]u8,
9781425 docs_sub_path: ?[]u8,
9791426 lf_open_opts: link.File.OpenOptions,
980 tmp_artifact_directory: ?Directory,
1427 tmp_artifact_directory: ?Cache.Directory,
9811428 /// Prevents other processes from clobbering files in the output directory.
9821429 lock: ?Cache.Lock,
9831430
......@@ -997,7 +1444,7 @@ const CacheUse = union(CacheMode) {
9971444
9981445 const Incremental = struct {
9991446 /// Where build artifacts and incremental compilation metadata serialization go.
1000 artifact_directory: Compilation.Directory,
1447 artifact_directory: Cache.Directory,
10011448 };
10021449
10031450 fn deinit(cu: CacheUse) void {
......@@ -1013,9 +1460,7 @@ const CacheUse = union(CacheMode) {
10131460};
10141461
10151462pub const CreateOptions = struct {
1016 zig_lib_directory: Directory,
1017 local_cache_directory: Directory,
1018 global_cache_directory: Directory,
1463 dirs: Directories,
10191464 thread_pool: *ThreadPool,
10201465 self_exe_path: ?[]const u8 = null,
10211466
......@@ -1059,7 +1504,7 @@ pub const CreateOptions = struct {
10591504 /// This field is intended to be removed.
10601505 /// The ELF implementation no longer uses this data, however the MachO and COFF
10611506 /// implementations still do.
1062 lib_directories: []const Directory = &.{},
1507 lib_directories: []const Cache.Directory = &.{},
10631508 rpath_list: []const []const u8 = &[0][]const u8{},
10641509 symbol_wrap_set: std.StringArrayHashMapUnmanaged(void) = .empty,
10651510 c_source_files: []const CSourceFile = &.{},
......@@ -1195,68 +1640,35 @@ pub const CreateOptions = struct {
11951640};
11961641
11971642fn addModuleTableToCacheHash(
1198 gpa: Allocator,
1643 zcu: *Zcu,
11991644 arena: Allocator,
12001645 hash: *Cache.HashHelper,
1201 root_mod: *Package.Module,
1202 main_mod: *Package.Module,
12031646 hash_type: union(enum) { path_bytes, files: *Cache.Manifest },
1204) (error{OutOfMemory} || std.process.GetCwdError)!void {
1205 var seen_table: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .empty;
1206 defer seen_table.deinit(gpa);
1207
1208 // root_mod and main_mod may be the same pointer. In fact they usually are.
1209 // However in the case of `zig test` or `zig build` they will be different,
1210 // and it's possible for one to not reference the other via the import table.
1211 try seen_table.put(gpa, root_mod, {});
1212 try seen_table.put(gpa, main_mod, {});
1213
1214 const SortByName = struct {
1215 has_builtin: bool,
1216 names: []const []const u8,
1217
1218 pub fn lessThan(ctx: @This(), lhs: usize, rhs: usize) bool {
1219 return if (ctx.has_builtin and (lhs == 0 or rhs == 0))
1220 lhs < rhs
1221 else
1222 mem.lessThan(u8, ctx.names[lhs], ctx.names[rhs]);
1647) error{
1648 OutOfMemory,
1649 Unexpected,
1650 CurrentWorkingDirectoryUnlinked,
1651}!void {
1652 assert(zcu.module_roots.count() != 0); // module_roots is populated
1653
1654 for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, opt_mod_root_file| {
1655 if (mod == zcu.std_mod) continue; // redundant
1656 if (opt_mod_root_file.unwrap()) |mod_root_file| {
1657 if (zcu.fileByIndex(mod_root_file).is_builtin) continue; // redundant
12231658 }
1224 };
1225
1226 var i: usize = 0;
1227 while (i < seen_table.count()) : (i += 1) {
1228 const mod = seen_table.keys()[i];
1229 if (mod.isBuiltin()) {
1230 // Skip builtin.zig; it is useless as an input, and we don't want to
1231 // have to write it before checking for a cache hit.
1232 continue;
1233 }
1234
12351659 cache_helpers.addModule(hash, mod);
1236
12371660 switch (hash_type) {
12381661 .path_bytes => {
1239 hash.addBytes(mod.root_src_path);
1240 hash.addOptionalBytes(mod.root.root_dir.path);
1662 hash.add(mod.root.root);
12411663 hash.addBytes(mod.root.sub_path);
1664 hash.addBytes(mod.root_src_path);
12421665 },
12431666 .files => |man| if (mod.root_src_path.len != 0) {
1244 const pkg_zig_file = try mod.root.joinString(arena, mod.root_src_path);
1245 _ = try man.addFile(pkg_zig_file, null);
1667 const root_src_path = try mod.root.toCachePath(zcu.comp.dirs).join(arena, mod.root_src_path);
1668 _ = try man.addFilePath(root_src_path, null);
12461669 },
12471670 }
1248
1249 mod.deps.sortUnstable(SortByName{
1250 .has_builtin = mod.deps.count() >= 1 and
1251 mod.deps.values()[0].isBuiltin(),
1252 .names = mod.deps.keys(),
1253 });
1254
12551671 hash.addListOfBytes(mod.deps.keys());
1256
1257 const deps = mod.deps.values();
1258 try seen_table.ensureUnusedCapacity(gpa, deps.len);
1259 for (deps) |dep| seen_table.putAssumeCapacity(dep, {});
12601672 }
12611673}
12621674
......@@ -1310,7 +1722,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13101722
13111723 const libc_dirs = try std.zig.LibCDirs.detect(
13121724 arena,
1313 options.zig_lib_directory.path.?,
1725 options.dirs.zig_lib.path.?,
13141726 options.root_mod.resolved_target.result,
13151727 options.root_mod.resolved_target.is_native_abi,
13161728 link_libc,
......@@ -1332,11 +1744,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13321744 // For objects, this mechanism relies on essentially `_ = @import("compiler-rt");`
13331745 // injected into the object.
13341746 const compiler_rt_mod = try Package.Module.create(arena, .{
1335 .global_cache_directory = options.global_cache_directory,
13361747 .paths = .{
1337 .root = .{
1338 .root_dir = options.zig_lib_directory,
1339 },
1748 .root = .zig_lib_root,
13401749 .root_src_path = "compiler_rt.zig",
13411750 },
13421751 .fully_qualified_name = "compiler_rt",
......@@ -1348,8 +1757,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13481757 },
13491758 .global = options.config,
13501759 .parent = options.root_mod,
1351 .builtin_mod = options.root_mod.getBuiltinDependency(),
1352 .builtin_modules = null, // `builtin_mod` is set
13531760 });
13541761 try options.root_mod.deps.putNoClobber(arena, "compiler_rt", compiler_rt_mod);
13551762 }
......@@ -1369,11 +1776,8 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13691776
13701777 if (ubsan_rt_strat == .zcu) {
13711778 const ubsan_rt_mod = try Package.Module.create(arena, .{
1372 .global_cache_directory = options.global_cache_directory,
13731779 .paths = .{
1374 .root = .{
1375 .root_dir = options.zig_lib_directory,
1376 },
1780 .root = .zig_lib_root,
13771781 .root_src_path = "ubsan_rt.zig",
13781782 },
13791783 .fully_qualified_name = "ubsan_rt",
......@@ -1381,8 +1785,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
13811785 .inherited = .{},
13821786 .global = options.config,
13831787 .parent = options.root_mod,
1384 .builtin_mod = options.root_mod.getBuiltinDependency(),
1385 .builtin_modules = null, // `builtin_mod` is set
13861788 });
13871789 try options.root_mod.deps.putNoClobber(arena, "ubsan_rt", ubsan_rt_mod);
13881790 }
......@@ -1415,13 +1817,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
14151817 const cache = try arena.create(Cache);
14161818 cache.* = .{
14171819 .gpa = gpa,
1418 .manifest_dir = try options.local_cache_directory.handle.makeOpenPath("h", .{}),
1820 .manifest_dir = try options.dirs.local_cache.handle.makeOpenPath("h", .{}),
14191821 };
14201822 // These correspond to std.zig.Server.Message.PathPrefix.
14211823 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
1422 cache.addPrefix(options.zig_lib_directory);
1423 cache.addPrefix(options.local_cache_directory);
1424 cache.addPrefix(options.global_cache_directory);
1824 cache.addPrefix(options.dirs.zig_lib);
1825 cache.addPrefix(options.dirs.local_cache);
1826 cache.addPrefix(options.dirs.global_cache);
14251827 errdefer cache.manifest_dir.close();
14261828
14271829 // This is shared hasher state common to zig source and all C source files.
......@@ -1458,26 +1860,22 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
14581860 // to redundantly happen for each AstGen operation.
14591861 const zir_sub_dir = "z";
14601862
1461 var local_zir_dir = try options.local_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
1863 var local_zir_dir = try options.dirs.local_cache.handle.makeOpenPath(zir_sub_dir, .{});
14621864 errdefer local_zir_dir.close();
1463 const local_zir_cache: Directory = .{
1865 const local_zir_cache: Cache.Directory = .{
14641866 .handle = local_zir_dir,
1465 .path = try options.local_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
1867 .path = try options.dirs.local_cache.join(arena, &.{zir_sub_dir}),
14661868 };
1467 var global_zir_dir = try options.global_cache_directory.handle.makeOpenPath(zir_sub_dir, .{});
1869 var global_zir_dir = try options.dirs.global_cache.handle.makeOpenPath(zir_sub_dir, .{});
14681870 errdefer global_zir_dir.close();
1469 const global_zir_cache: Directory = .{
1871 const global_zir_cache: Cache.Directory = .{
14701872 .handle = global_zir_dir,
1471 .path = try options.global_cache_directory.join(arena, &[_][]const u8{zir_sub_dir}),
1873 .path = try options.dirs.global_cache.join(arena, &.{zir_sub_dir}),
14721874 };
14731875
14741876 const std_mod = options.std_mod orelse try Package.Module.create(arena, .{
1475 .global_cache_directory = options.global_cache_directory,
14761877 .paths = .{
1477 .root = .{
1478 .root_dir = options.zig_lib_directory,
1479 .sub_path = "std",
1480 },
1878 .root = try .fromRoot(arena, options.dirs, .zig_lib, "std"),
14811879 .root_src_path = "std.zig",
14821880 },
14831881 .fully_qualified_name = "std",
......@@ -1485,8 +1883,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
14851883 .inherited = .{},
14861884 .global = options.config,
14871885 .parent = options.root_mod,
1488 .builtin_mod = options.root_mod.getBuiltinDependency(),
1489 .builtin_modules = null, // `builtin_mod` is set
14901886 });
14911887
14921888 const zcu = try arena.create(Zcu);
......@@ -1522,16 +1918,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
15221918 .docs_emit = null, // handled below
15231919 .root_mod = options.root_mod,
15241920 .config = options.config,
1525 .zig_lib_directory = options.zig_lib_directory,
1526 .local_cache_directory = options.local_cache_directory,
1527 .global_cache_directory = options.global_cache_directory,
1921 .dirs = options.dirs,
15281922 .emit_asm = options.emit_asm,
15291923 .emit_llvm_ir = options.emit_llvm_ir,
15301924 .emit_llvm_bc = options.emit_llvm_bc,
15311925 .work_queues = @splat(.init(gpa)),
15321926 .c_object_work_queue = std.fifo.LinearFifo(*CObject, .Dynamic).init(gpa),
15331927 .win32_resource_work_queue = if (dev.env.supports(.win32_resource)) std.fifo.LinearFifo(*Win32Resource, .Dynamic).init(gpa) else .{},
1534 .astgen_work_queue = std.fifo.LinearFifo(Zcu.File.Index, .Dynamic).init(gpa),
15351928 .c_source_files = options.c_source_files,
15361929 .rc_source_files = options.rc_source_files,
15371930 .cache_parent = cache,
......@@ -1572,9 +1965,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
15721965 .framework_dirs = options.framework_dirs,
15731966 .llvm_opt_bisect_limit = options.llvm_opt_bisect_limit,
15741967 .skip_linker_dependencies = options.skip_linker_dependencies,
1575 .queued_jobs = .{
1576 .update_builtin_zig = have_zcu,
1577 },
1968 .queued_jobs = .{},
15781969 .function_sections = options.function_sections,
15791970 .data_sections = options.data_sections,
15801971 .native_system_include_paths = options.native_system_include_paths,
......@@ -1596,6 +1987,13 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
15961987 comp.config.any_sanitize_c = any_sanitize_c;
15971988 comp.config.any_fuzz = any_fuzz;
15981989
1990 if (opt_zcu) |zcu| {
1991 // Populate `zcu.module_roots`.
1992 const pt: Zcu.PerThread = .activate(zcu, .main);
1993 defer pt.deactivate();
1994 try pt.populateModuleRootTable();
1995 }
1996
15991997 const lf_open_opts: link.File.OpenOptions = .{
16001998 .linker_script = options.linker_script,
16011999 .z_nodelete = options.linker_z_nodelete,
......@@ -1686,7 +2084,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
16862084 // do want to namespace different source file names because they are
16872085 // likely different compilations and therefore this would be likely to
16882086 // cause cache hits.
1689 try addModuleTableToCacheHash(gpa, arena, &hash, options.root_mod, main_mod, .path_bytes);
2087 if (comp.zcu) |zcu| {
2088 try addModuleTableToCacheHash(zcu, arena, &hash, .path_bytes);
2089 } else {
2090 cache_helpers.addModule(&hash, options.root_mod);
2091 }
16902092
16912093 // In the case of incremental cache mode, this `artifact_directory`
16922094 // is computed based on a hash of non-linker inputs, and it is where all
......@@ -1695,11 +2097,11 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
16952097 const digest = hash.final();
16962098
16972099 const artifact_sub_dir = "o" ++ std.fs.path.sep_str ++ digest;
1698 var artifact_dir = try options.local_cache_directory.handle.makeOpenPath(artifact_sub_dir, .{});
2100 var artifact_dir = try options.dirs.local_cache.handle.makeOpenPath(artifact_sub_dir, .{});
16992101 errdefer artifact_dir.close();
1700 const artifact_directory: Directory = .{
2102 const artifact_directory: Cache.Directory = .{
17012103 .handle = artifact_dir,
1702 .path = try options.local_cache_directory.join(arena, &[_][]const u8{artifact_sub_dir}),
2104 .path = try options.dirs.local_cache.join(arena, &.{artifact_sub_dir}),
17032105 };
17042106
17052107 const incremental = try arena.create(CacheUse.Incremental);
......@@ -1709,7 +2111,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
17092111 comp.cache_use = .{ .incremental = incremental };
17102112
17112113 if (options.emit_bin) |emit_bin| {
1712 const emit: Path = .{
2114 const emit: Cache.Path = .{
17132115 .root_dir = emit_bin.directory orelse artifact_directory,
17142116 .sub_path = emit_bin.basename,
17152117 };
......@@ -1998,10 +2400,10 @@ pub fn destroy(comp: *Compilation) void {
19982400 if (comp.bin_file) |lf| lf.destroy();
19992401 if (comp.zcu) |zcu| zcu.deinit();
20002402 comp.cache_use.deinit();
2403
20012404 for (comp.work_queues) |work_queue| work_queue.deinit();
20022405 comp.c_object_work_queue.deinit();
20032406 comp.win32_resource_work_queue.deinit();
2004 comp.astgen_work_queue.deinit();
20052407
20062408 comp.windows_libs.deinit(gpa);
20072409
......@@ -2207,15 +2609,15 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
22072609 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
22082610
22092611 // Compile the artifacts to a temporary directory.
2210 const tmp_artifact_directory: Directory = d: {
2612 const tmp_artifact_directory: Cache.Directory = d: {
22112613 const s = std.fs.path.sep_str;
22122614 tmp_dir_rand_int = std.crypto.random.int(u64);
22132615 const tmp_dir_sub_path = "tmp" ++ s ++ std.fmt.hex(tmp_dir_rand_int);
22142616
2215 const path = try comp.local_cache_directory.join(gpa, &.{tmp_dir_sub_path});
2617 const path = try comp.dirs.local_cache.join(gpa, &.{tmp_dir_sub_path});
22162618 errdefer gpa.free(path);
22172619
2218 const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
2620 const handle = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
22192621 errdefer handle.close();
22202622
22212623 break :d .{
......@@ -2243,7 +2645,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
22432645 }
22442646
22452647 if (whole.bin_sub_path) |sub_path| {
2246 const emit: Path = .{
2648 const emit: Cache.Path = .{
22472649 .root_dir = tmp_artifact_directory,
22482650 .sub_path = std.fs.path.basename(sub_path),
22492651 };
......@@ -2265,26 +2667,22 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
22652667 // For compiling C objects, we rely on the cache hash system to avoid duplicating work.
22662668 // Add a Job for each C object.
22672669 try comp.c_object_work_queue.ensureUnusedCapacity(comp.c_object_table.count());
2268 for (comp.c_object_table.keys()) |key| {
2269 comp.c_object_work_queue.writeItemAssumeCapacity(key);
2270 }
2271 if (comp.file_system_inputs) |fsi| {
2272 for (comp.c_object_table.keys()) |c_object| {
2273 try comp.appendFileSystemInput(fsi, Cache.Path.cwd(), c_object.src.src_path);
2274 }
2670 for (comp.c_object_table.keys()) |c_object| {
2671 comp.c_object_work_queue.writeItemAssumeCapacity(c_object);
2672 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{c_object.src.src_path}));
22752673 }
22762674
22772675 // For compiling Win32 resources, we rely on the cache hash system to avoid duplicating work.
22782676 // Add a Job for each Win32 resource file.
22792677 try comp.win32_resource_work_queue.ensureUnusedCapacity(comp.win32_resource_table.count());
2280 for (comp.win32_resource_table.keys()) |key| {
2281 comp.win32_resource_work_queue.writeItemAssumeCapacity(key);
2282 }
2283 if (comp.file_system_inputs) |fsi| {
2284 for (comp.win32_resource_table.keys()) |win32_resource| switch (win32_resource.src) {
2285 .rc => |f| try comp.appendFileSystemInput(fsi, Cache.Path.cwd(), f.src_path),
2286 .manifest => continue,
2287 };
2678 for (comp.win32_resource_table.keys()) |win32_resource| {
2679 comp.win32_resource_work_queue.writeItemAssumeCapacity(win32_resource);
2680 switch (win32_resource.src) {
2681 .rc => |f| {
2682 try comp.appendFileSystemInput(try .fromUnresolved(arena, comp.dirs, &.{f.src_path}));
2683 },
2684 .manifest => {},
2685 }
22882686 }
22892687
22902688 if (comp.zcu) |zcu| {
......@@ -2293,69 +2691,26 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
22932691
22942692 zcu.skip_analysis_this_update = false;
22952693
2296 // Make sure std.zig is inside the import_table. We unconditionally need
2297 // it for start.zig.
2298 const std_mod = zcu.std_mod;
2299 _ = try pt.importPkg(std_mod);
2300
2301 // Normally we rely on importing std to in turn import the root source file
2302 // in the start code, but when using the stage1 backend that won't happen,
2303 // so in order to run AstGen on the root source file we put it into the
2304 // import_table here.
2305 // Likewise, in the case of `zig test`, the test runner is the root source file,
2306 // and so there is nothing to import the main file.
2307 if (comp.config.is_test) {
2308 _ = try pt.importPkg(zcu.main_mod);
2309 }
2310
2311 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2312 _ = try pt.importPkg(ubsan_rt_mod);
2313 }
2314
2315 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2316 _ = try pt.importPkg(compiler_rt_mod);
2317 }
2318
2319 // Put a work item in for every known source file to detect if
2320 // it changed, and, if so, re-compute ZIR and then queue the job
2321 // to update it.
2322 try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
2323 for (zcu.import_table.values()) |file_index| {
2324 if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
2325 comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
2326 }
2327 if (comp.file_system_inputs) |fsi| {
2328 for (zcu.import_table.values()) |file_index| {
2329 const file = zcu.fileByIndex(file_index);
2330 try comp.appendFileSystemInput(fsi, file.mod.root, file.sub_file_path);
2331 }
2332 }
2333
2334 if (comp.file_system_inputs) |fsi| {
2335 const ip = &zcu.intern_pool;
2336 for (zcu.embed_table.values()) |embed_file| {
2337 const sub_file_path = embed_file.sub_file_path.toSlice(ip);
2338 try comp.appendFileSystemInput(fsi, embed_file.owner.root, sub_file_path);
2339 }
2694 // TODO: doing this in `resolveReferences` later could avoid adding inputs for dead embedfiles. Investigate!
2695 for (zcu.embed_table.keys()) |embed_file| {
2696 try comp.appendFileSystemInput(embed_file.path);
23402697 }
23412698
23422699 zcu.analysis_roots.clear();
23432700
2344 try comp.queueJob(.{ .analyze_mod = std_mod });
2345 zcu.analysis_roots.appendAssumeCapacity(std_mod);
2701 zcu.analysis_roots.appendAssumeCapacity(zcu.std_mod);
23462702
2347 if (comp.config.is_test and zcu.main_mod != std_mod) {
2348 try comp.queueJob(.{ .analyze_mod = zcu.main_mod });
2703 // Normally we rely on importing std to in turn import the root source file in the start code.
2704 // However, the main module is distinct from the root module in tests, so that won't happen there.
2705 if (comp.config.is_test and zcu.main_mod != zcu.std_mod) {
23492706 zcu.analysis_roots.appendAssumeCapacity(zcu.main_mod);
23502707 }
23512708
23522709 if (zcu.root_mod.deps.get("compiler_rt")) |compiler_rt_mod| {
2353 try comp.queueJob(.{ .analyze_mod = compiler_rt_mod });
23542710 zcu.analysis_roots.appendAssumeCapacity(compiler_rt_mod);
23552711 }
23562712
23572713 if (zcu.root_mod.deps.get("ubsan_rt")) |ubsan_rt_mod| {
2358 try comp.queueJob(.{ .analyze_mod = ubsan_rt_mod });
23592714 zcu.analysis_roots.appendAssumeCapacity(ubsan_rt_mod);
23602715 }
23612716 }
......@@ -2451,13 +2806,13 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
24512806 break :w .no;
24522807 };
24532808
2454 renameTmpIntoCache(comp.local_cache_directory, tmp_dir_sub_path, o_sub_path) catch |err| {
2809 renameTmpIntoCache(comp.dirs.local_cache, tmp_dir_sub_path, o_sub_path) catch |err| {
24552810 return comp.setMiscFailure(
24562811 .rename_results,
24572812 "failed to rename compilation results ('{}{s}') into local cache ('{}{s}'): {s}",
24582813 .{
2459 comp.local_cache_directory, tmp_dir_sub_path,
2460 comp.local_cache_directory, o_sub_path,
2814 comp.dirs.local_cache, tmp_dir_sub_path,
2815 comp.dirs.local_cache, o_sub_path,
24612816 @errorName(err),
24622817 },
24632818 );
......@@ -2470,7 +2825,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
24702825 // references object file paths.
24712826 if (comp.bin_file) |lf| {
24722827 lf.emit = .{
2473 .root_dir = comp.local_cache_directory,
2828 .root_dir = comp.dirs.local_cache,
24742829 .sub_path = whole.bin_sub_path.?,
24752830 };
24762831
......@@ -2486,7 +2841,7 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
24862841 }
24872842
24882843 try flush(comp, arena, .{
2489 .root_dir = comp.local_cache_directory,
2844 .root_dir = comp.dirs.local_cache,
24902845 .sub_path = o_sub_path,
24912846 }, .main, main_progress_node);
24922847
......@@ -2515,34 +2870,36 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
25152870 }
25162871}
25172872
2518pub fn appendFileSystemInput(
2519 comp: *Compilation,
2520 file_system_inputs: *std.ArrayListUnmanaged(u8),
2521 root: Cache.Path,
2522 sub_file_path: []const u8,
2523) Allocator.Error!void {
2873pub fn appendFileSystemInput(comp: *Compilation, path: Compilation.Path) Allocator.Error!void {
25242874 const gpa = comp.gpa;
2875 const fsi = comp.file_system_inputs orelse return;
25252876 const prefixes = comp.cache_parent.prefixes();
2526 try file_system_inputs.ensureUnusedCapacity(gpa, root.sub_path.len + sub_file_path.len + 3);
2527 if (file_system_inputs.items.len > 0) file_system_inputs.appendAssumeCapacity(0);
2528 for (prefixes, 1..) |prefix_directory, i| {
2529 if (prefix_directory.eql(root.root_dir)) {
2530 file_system_inputs.appendAssumeCapacity(@intCast(i));
2531 if (root.sub_path.len > 0) {
2532 file_system_inputs.appendSliceAssumeCapacity(root.sub_path);
2533 file_system_inputs.appendAssumeCapacity(std.fs.path.sep);
2534 }
2535 file_system_inputs.appendSliceAssumeCapacity(sub_file_path);
2536 return;
2877
2878 const want_prefix_dir: Cache.Directory = switch (path.root) {
2879 .zig_lib => comp.dirs.zig_lib,
2880 .global_cache => comp.dirs.global_cache,
2881 .local_cache => comp.dirs.local_cache,
2882 .none => .cwd(),
2883 };
2884 const prefix: u8 = for (prefixes, 1..) |prefix_dir, i| {
2885 if (prefix_dir.eql(want_prefix_dir)) {
2886 break @intCast(i);
25372887 }
2538 }
2539 std.debug.panic("missing prefix directory: {}, {s}", .{ root, sub_file_path });
2888 } else std.debug.panic(
2889 "missing prefix directory '{s}' ('{}') for '{s}'",
2890 .{ @tagName(path.root), want_prefix_dir, path.sub_path },
2891 );
2892
2893 try fsi.ensureUnusedCapacity(gpa, path.sub_path.len + 3);
2894 if (fsi.items.len > 0) fsi.appendAssumeCapacity(0);
2895 fsi.appendAssumeCapacity(prefix);
2896 fsi.appendSliceAssumeCapacity(path.sub_path);
25402897}
25412898
25422899fn flush(
25432900 comp: *Compilation,
25442901 arena: Allocator,
2545 default_artifact_directory: Path,
2902 default_artifact_directory: Cache.Path,
25462903 tid: Zcu.PerThread.Id,
25472904 prog_node: std.Progress.Node,
25482905) !void {
......@@ -2574,7 +2931,7 @@ fn flush(
25742931/// implementation at the bottom of this function.
25752932/// This function is only called when CacheMode is `whole`.
25762933fn renameTmpIntoCache(
2577 cache_directory: Compilation.Directory,
2934 cache_directory: Cache.Directory,
25782935 tmp_dir_sub_path: []const u8,
25792936 o_sub_path: []const u8,
25802937) !void {
......@@ -2627,7 +2984,7 @@ fn wholeCacheModeSetBinFilePath(
26272984 @memcpy(sub_path[digest_start..][0..digest.len], digest);
26282985
26292986 comp.implib_emit = .{
2630 .root_dir = comp.local_cache_directory,
2987 .root_dir = comp.dirs.local_cache,
26312988 .sub_path = sub_path,
26322989 };
26332990 }
......@@ -2636,7 +2993,7 @@ fn wholeCacheModeSetBinFilePath(
26362993 @memcpy(sub_path[digest_start..][0..digest.len], digest);
26372994
26382995 comp.docs_emit = .{
2639 .root_dir = comp.local_cache_directory,
2996 .root_dir = comp.dirs.local_cache,
26402997 .sub_path = sub_path,
26412998 };
26422999 }
......@@ -2661,19 +3018,17 @@ fn addNonIncrementalStuffToCacheManifest(
26613018 arena: Allocator,
26623019 man: *Cache.Manifest,
26633020) !void {
2664 const gpa = comp.gpa;
2665
26663021 comptime assert(link_hash_implementation_version == 14);
26673022
2668 if (comp.zcu) |mod| {
2669 try addModuleTableToCacheHash(gpa, arena, &man.hash, mod.root_mod, mod.main_mod, .{ .files = man });
3023 if (comp.zcu) |zcu| {
3024 try addModuleTableToCacheHash(zcu, arena, &man.hash, .{ .files = man });
26703025
26713026 // Synchronize with other matching comments: ZigOnlyHashStuff
26723027 man.hash.addListOfBytes(comp.test_filters);
26733028 man.hash.addOptionalBytes(comp.test_name_prefix);
26743029 man.hash.add(comp.skip_linker_dependencies);
2675 //man.hash.add(mod.emit_h != null);
2676 man.hash.add(mod.error_limit);
3030 //man.hash.add(zcu.emit_h != null);
3031 man.hash.add(zcu.error_limit);
26773032 } else {
26783033 cache_helpers.addModule(&man.hash, comp.root_mod);
26793034 }
......@@ -2839,7 +3194,7 @@ fn emitOthers(comp: *Compilation) void {
28393194pub fn emitLlvmObject(
28403195 comp: *Compilation,
28413196 arena: Allocator,
2842 default_artifact_directory: Path,
3197 default_artifact_directory: Cache.Path,
28433198 bin_emit_loc: ?EmitLoc,
28443199 llvm_object: LlvmObject.Ptr,
28453200 prog_node: std.Progress.Node,
......@@ -2866,7 +3221,7 @@ pub fn emitLlvmObject(
28663221
28673222fn resolveEmitLoc(
28683223 arena: Allocator,
2869 default_artifact_directory: Path,
3224 default_artifact_directory: Cache.Path,
28703225 opt_loc: ?EmitLoc,
28713226) Allocator.Error!?[*:0]const u8 {
28723227 const loc = opt_loc orelse return null;
......@@ -2877,132 +3232,6 @@ fn resolveEmitLoc(
28773232 return slice.ptr;
28783233}
28793234
2880fn reportMultiModuleErrors(pt: Zcu.PerThread) !void {
2881 const zcu = pt.zcu;
2882 const gpa = zcu.gpa;
2883 const ip = &zcu.intern_pool;
2884 // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to
2885 // print all of, so we'll cap the number of these to emit.
2886 var num_errors: u32 = 0;
2887 const max_errors = 5;
2888 // Attach the "some omitted" note to the final error message
2889 var last_err: ?*Zcu.ErrorMsg = null;
2890
2891 for (zcu.import_table.values()) |file_index| {
2892 const file = zcu.fileByIndex(file_index);
2893 if (!file.multi_pkg) continue;
2894
2895 num_errors += 1;
2896 if (num_errors > max_errors) continue;
2897
2898 const err = err_blk: {
2899 // Like with errors, let's cap the number of notes to prevent a huge error spew.
2900 const max_notes = 5;
2901 const omitted = file.references.items.len -| max_notes;
2902 const num_notes = file.references.items.len - omitted;
2903
2904 const notes = try gpa.alloc(Zcu.ErrorMsg, if (omitted > 0) num_notes + 1 else num_notes);
2905 errdefer gpa.free(notes);
2906
2907 for (notes[0..num_notes], file.references.items[0..num_notes], 0..) |*note, ref, i| {
2908 errdefer for (notes[0..i]) |*n| n.deinit(gpa);
2909 note.* = switch (ref) {
2910 .import => |import| try Zcu.ErrorMsg.init(
2911 gpa,
2912 .{
2913 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2914 .file = import.file,
2915 .inst = .main_struct_inst,
2916 }),
2917 .offset = .{ .token_abs = import.token },
2918 },
2919 "imported from module {s}",
2920 .{zcu.fileByIndex(import.file).mod.fully_qualified_name},
2921 ),
2922 .root => |pkg| try Zcu.ErrorMsg.init(
2923 gpa,
2924 .{
2925 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2926 .file = file_index,
2927 .inst = .main_struct_inst,
2928 }),
2929 .offset = .entire_file,
2930 },
2931 "root of module {s}",
2932 .{pkg.fully_qualified_name},
2933 ),
2934 };
2935 }
2936 errdefer for (notes[0..num_notes]) |*n| n.deinit(gpa);
2937
2938 if (omitted > 0) {
2939 notes[num_notes] = try Zcu.ErrorMsg.init(
2940 gpa,
2941 .{
2942 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2943 .file = file_index,
2944 .inst = .main_struct_inst,
2945 }),
2946 .offset = .entire_file,
2947 },
2948 "{} more references omitted",
2949 .{omitted},
2950 );
2951 }
2952 errdefer if (omitted > 0) notes[num_notes].deinit(gpa);
2953
2954 const err = try Zcu.ErrorMsg.create(
2955 gpa,
2956 .{
2957 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
2958 .file = file_index,
2959 .inst = .main_struct_inst,
2960 }),
2961 .offset = .entire_file,
2962 },
2963 "file exists in multiple modules",
2964 .{},
2965 );
2966 err.notes = notes;
2967 break :err_blk err;
2968 };
2969 errdefer err.destroy(gpa);
2970 try zcu.failed_files.putNoClobber(gpa, file, err);
2971 last_err = err;
2972 }
2973
2974 // If we omitted any errors, add a note saying that
2975 if (num_errors > max_errors) {
2976 const err = last_err.?;
2977
2978 // There isn't really any meaningful place to put this note, so just attach it to the
2979 // last failed file
2980 var note = try Zcu.ErrorMsg.init(
2981 gpa,
2982 err.src_loc,
2983 "{} more errors omitted",
2984 .{num_errors - max_errors},
2985 );
2986 errdefer note.deinit(gpa);
2987
2988 const i = err.notes.len;
2989 err.notes = try gpa.realloc(err.notes, i + 1);
2990 err.notes[i] = note;
2991 }
2992
2993 // Now that we've reported the errors, we need to deal with
2994 // dependencies. Any file referenced by a multi_pkg file should also be
2995 // marked multi_pkg and have its status set to astgen_failure, as it's
2996 // ambiguous which package they should be analyzed as a part of. We need
2997 // to add this flag after reporting the errors however, as otherwise
2998 // we'd get an error for every single downstream file, which wouldn't be
2999 // very useful.
3000 for (zcu.import_table.values()) |file_index| {
3001 const file = zcu.fileByIndex(file_index);
3002 if (file.multi_pkg) file.recursiveMarkMultiPkg(pt);
3003 }
3004}
3005
30063235/// Having the file open for writing is problematic as far as executing the
30073236/// binary is concerned. This will remove the write flag, or close the file,
30083237/// or whatever is needed so that it can be executed.
......@@ -3326,16 +3555,77 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
33263555 }
33273556
33283557 if (comp.zcu) |zcu| zcu_errors: {
3329 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
3558 if (zcu.multi_module_err != null) {
3559 try zcu.addFileInMultipleModulesError(&bundle);
3560 break :zcu_errors;
3561 }
3562 for (zcu.failed_imports.items) |failed| {
3563 assert(zcu.alive_files.contains(failed.file_index)); // otherwise it wouldn't have been added
3564 const file = zcu.fileByIndex(failed.file_index);
3565 const source = try file.getSource(zcu);
3566 const tree = try file.getTree(zcu);
3567 const start = tree.tokenStart(failed.import_token);
3568 const end = start + tree.tokenSlice(failed.import_token).len;
3569 const loc = std.zig.findLineColumn(source.bytes, start);
3570 try bundle.addRootErrorMessage(.{
3571 .msg = switch (failed.kind) {
3572 .file_outside_module_root => try bundle.addString("import of file outside module path"),
3573 .illegal_zig_import => try bundle.addString("this compiler implementation does not allow importing files from this directory"),
3574 },
3575 .src_loc = try bundle.addSourceLocation(.{
3576 .src_path = try bundle.printString("{}", .{file.path.fmt(comp)}),
3577 .span_start = start,
3578 .span_main = start,
3579 .span_end = @intCast(end),
3580 .line = @intCast(loc.line),
3581 .column = @intCast(loc.column),
3582 .source_line = try bundle.addString(loc.source_line),
3583 }),
3584 .notes_len = 0,
3585 });
3586 }
3587
3588 // Before iterating `failed_files`, we need to sort it into a consistent order so that error
3589 // messages appear consistently despite different ordering from the AstGen worker pool. File
3590 // paths are a great key for this sort! We are using sorting the `ArrayHashMap` itself to
3591 // make sure it reindexes; that's important because these entries need to be retained for
3592 // future updates.
3593 const FileSortCtx = struct {
3594 zcu: *Zcu,
3595 failed_files_keys: []const Zcu.File.Index,
3596 pub fn lessThan(ctx: @This(), lhs_index: usize, rhs_index: usize) bool {
3597 const lhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[lhs_index]).path;
3598 const rhs_path = ctx.zcu.fileByIndex(ctx.failed_files_keys[rhs_index]).path;
3599 if (lhs_path.root != rhs_path.root) return @intFromEnum(lhs_path.root) < @intFromEnum(rhs_path.root);
3600 return std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).compare(.lt);
3601 }
3602 };
3603 zcu.failed_files.sort(@as(FileSortCtx, .{
3604 .zcu = zcu,
3605 .failed_files_keys = zcu.failed_files.keys(),
3606 }));
3607
3608 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file_index, error_msg| {
3609 if (!zcu.alive_files.contains(file_index)) continue;
3610 const file = zcu.fileByIndex(file_index);
3611 const is_retryable = switch (file.status) {
3612 .retryable_failure => true,
3613 .success, .astgen_failure => false,
3614 .never_loaded => unreachable,
3615 };
33303616 if (error_msg) |msg| {
3331 try addModuleErrorMsg(zcu, &bundle, msg.*, false);
3617 assert(is_retryable);
3618 try addWholeFileError(zcu, &bundle, file_index, msg);
33323619 } else {
3333 // Must be ZIR or Zoir errors. Note that this may include AST errors.
3334 _ = try file.getTree(gpa); // Tree must be loaded.
3620 assert(!is_retryable);
3621 // AstGen/ZoirGen succeeded with errors. Note that this may include AST errors.
3622 _ = try file.getTree(zcu); // Tree must be loaded.
3623 const path = try std.fmt.allocPrint(gpa, "{}", .{file.path.fmt(comp)});
3624 defer gpa.free(path);
33353625 if (file.zir != null) {
3336 try addZirErrorMessages(&bundle, file);
3626 try bundle.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, path);
33373627 } else if (file.zoir != null) {
3338 try addZoirErrorMessages(&bundle, file);
3628 try bundle.addZoirErrorMessages(file.zoir.?, file.tree.?, file.source.?, path);
33393629 } else {
33403630 // Either Zir or Zoir must have been loaded.
33413631 unreachable;
......@@ -3646,20 +3936,16 @@ pub fn addModuleErrorMsg(
36463936 const gpa = eb.gpa;
36473937 const ip = &zcu.intern_pool;
36483938 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
3649 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
3650 const file_path = try err_src_loc.file_scope.fullPath(gpa);
3651 defer gpa.free(file_path);
3939 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| {
36523940 try eb.addRootErrorMessage(.{
3653 .msg = try eb.printString("unable to load '{s}': {s}", .{
3654 file_path, @errorName(err),
3941 .msg = try eb.printString("unable to load '{}': {s}", .{
3942 err_src_loc.file_scope.path.fmt(zcu.comp), @errorName(err),
36553943 }),
36563944 });
36573945 return;
36583946 };
3659 const err_span = try err_src_loc.span(gpa);
3947 const err_span = try err_src_loc.span(zcu);
36603948 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
3661 const file_path = try err_src_loc.file_scope.fullPath(gpa);
3662 defer gpa.free(file_path);
36633949
36643950 var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .empty;
36653951 defer ref_traces.deinit(gpa);
......@@ -3715,16 +4001,13 @@ pub fn addModuleErrorMsg(
37154001 }
37164002
37174003 const src_loc = try eb.addSourceLocation(.{
3718 .src_path = try eb.addString(file_path),
4004 .src_path = try eb.printString("{}", .{err_src_loc.file_scope.path.fmt(zcu.comp)}),
37194005 .span_start = err_span.start,
37204006 .span_main = err_span.main,
37214007 .span_end = err_span.end,
37224008 .line = @intCast(err_loc.line),
37234009 .column = @intCast(err_loc.column),
3724 .source_line = if (err_src_loc.lazy == .entire_file)
3725 0
3726 else
3727 try eb.addString(err_loc.source_line),
4010 .source_line = try eb.addString(err_loc.source_line),
37284011 .reference_trace_len = @intCast(ref_traces.items.len),
37294012 });
37304013
......@@ -3740,11 +4023,9 @@ pub fn addModuleErrorMsg(
37404023 var last_note_loc: ?std.zig.Loc = null;
37414024 for (module_err_msg.notes) |module_note| {
37424025 const note_src_loc = module_note.src_loc.upgrade(zcu);
3743 const source = try note_src_loc.file_scope.getSource(gpa);
3744 const span = try note_src_loc.span(gpa);
4026 const source = try note_src_loc.file_scope.getSource(zcu);
4027 const span = try note_src_loc.span(zcu);
37454028 const loc = std.zig.findLineColumn(source.bytes, span.main);
3746 const note_file_path = try note_src_loc.file_scope.fullPath(gpa);
3747 defer gpa.free(note_file_path);
37484029
37494030 const omit_source_line = loc.eql(err_loc) or (last_note_loc != null and loc.eql(last_note_loc.?));
37504031 last_note_loc = loc;
......@@ -3752,7 +4033,7 @@ pub fn addModuleErrorMsg(
37524033 const gop = try notes.getOrPutContext(gpa, .{
37534034 .msg = try eb.addString(module_note.msg),
37544035 .src_loc = try eb.addSourceLocation(.{
3755 .src_path = try eb.addString(note_file_path),
4036 .src_path = try eb.printString("{}", .{note_src_loc.file_scope.path.fmt(zcu.comp)}),
37564037 .span_start = span.start,
37574038 .span_main = span.main,
37584039 .span_end = span.end,
......@@ -3791,15 +4072,13 @@ fn addReferenceTraceFrame(
37914072) !void {
37924073 const gpa = zcu.gpa;
37934074 const src = lazy_src.upgrade(zcu);
3794 const source = try src.file_scope.getSource(gpa);
3795 const span = try src.span(gpa);
4075 const source = try src.file_scope.getSource(zcu);
4076 const span = try src.span(zcu);
37964077 const loc = std.zig.findLineColumn(source.bytes, span.main);
3797 const rt_file_path = try src.file_scope.fullPath(gpa);
3798 defer gpa.free(rt_file_path);
37994078 try ref_traces.append(gpa, .{
38004079 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
38014080 .src_loc = try eb.addSourceLocation(.{
3802 .src_path = try eb.addString(rt_file_path),
4081 .src_path = try eb.printString("{}", .{src.file_scope.path.fmt(zcu.comp)}),
38034082 .span_start = span.start,
38044083 .span_main = span.main,
38054084 .span_end = span.end,
......@@ -3810,18 +4089,30 @@ fn addReferenceTraceFrame(
38104089 });
38114090}
38124091
3813pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3814 const gpa = eb.gpa;
3815 const src_path = try file.fullPath(gpa);
3816 defer gpa.free(src_path);
3817 return eb.addZirErrorMessages(file.zir.?, file.tree.?, file.source.?, src_path);
3818}
4092pub fn addWholeFileError(
4093 zcu: *Zcu,
4094 eb: *ErrorBundle.Wip,
4095 file_index: Zcu.File.Index,
4096 msg: []const u8,
4097) !void {
4098 // note: "file imported here" on the import reference token
4099 const imported_note: ?ErrorBundle.MessageIndex = switch (zcu.alive_files.get(file_index).?) {
4100 .analysis_root => null,
4101 .import => |import| try eb.addErrorMessage(.{
4102 .msg = try eb.addString("file imported here"),
4103 .src_loc = try zcu.fileByIndex(import.importer).errorBundleTokenSrc(import.tok, zcu, eb),
4104 }),
4105 };
38194106
3820pub fn addZoirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
3821 const gpa = eb.gpa;
3822 const src_path = try file.fullPath(gpa);
3823 defer gpa.free(src_path);
3824 return eb.addZoirErrorMessages(file.zoir.?, file.tree.?, file.source.?, src_path);
4107 try eb.addRootErrorMessage(.{
4108 .msg = try eb.addString(msg),
4109 .src_loc = try zcu.fileByIndex(file_index).errorBundleWholeFileSrc(zcu, eb),
4110 .notes_len = if (imported_note != null) 1 else 0,
4111 });
4112 if (imported_note) |n| {
4113 const note_idx = try eb.reserveNotes(1);
4114 eb.extra.items[note_idx] = @intFromEnum(n);
4115 }
38254116}
38264117
38274118pub fn performAllTheWork(
......@@ -3966,51 +4257,48 @@ fn performAllTheWorkInner(
39664257 var astgen_wait_group: WaitGroup = .{};
39674258 defer astgen_wait_group.wait();
39684259
3969 // builtin.zig is handled specially for two reasons:
3970 // 1. to avoid race condition of zig processes truncating each other's builtin.zig files
3971 // 2. optimization; in the hot path it only incurs a stat() syscall, which happens
3972 // in the `astgen_wait_group`.
3973 if (comp.queued_jobs.update_builtin_zig) b: {
3974 comp.queued_jobs.update_builtin_zig = false;
3975 if (comp.zcu == null) break :b;
3976 // TODO put all the modules in a flat array to make them easy to iterate.
3977 var seen: std.AutoArrayHashMapUnmanaged(*Package.Module, void) = .empty;
3978 defer seen.deinit(comp.gpa);
3979 try seen.put(comp.gpa, comp.root_mod, {});
3980 var i: usize = 0;
3981 while (i < seen.count()) : (i += 1) {
3982 const mod = seen.keys()[i];
3983 for (mod.deps.values()) |dep|
3984 try seen.put(comp.gpa, dep, {});
3985
3986 const file = mod.builtin_file orelse continue;
3987
3988 comp.thread_pool.spawnWg(&astgen_wait_group, workerUpdateBuiltinZigFile, .{
3989 comp, mod, file,
4260 if (comp.zcu) |zcu| {
4261 const gpa = zcu.gpa;
4262
4263 // We cannot reference `zcu.import_table` after we spawn any `workerUpdateFile` jobs,
4264 // because on single-threaded targets the worker will be run eagerly, meaning the
4265 // `import_table` could be mutated, and not even holding `comp.mutex` will save us. So,
4266 // build up a list of the files to update *before* we spawn any jobs.
4267 var astgen_work_items: std.MultiArrayList(struct {
4268 file_index: Zcu.File.Index,
4269 file: *Zcu.File,
4270 }) = .empty;
4271 defer astgen_work_items.deinit(gpa);
4272 // Not every item in `import_table` will need updating, because some are builtin.zig
4273 // files. However, most will, so let's just reserve sufficient capacity upfront.
4274 try astgen_work_items.ensureTotalCapacity(gpa, zcu.import_table.count());
4275 for (zcu.import_table.keys()) |file_index| {
4276 const file = zcu.fileByIndex(file_index);
4277 if (file.is_builtin) {
4278 // This is a `builtin.zig`, so updating is redundant. However, we want to make
4279 // sure the file contents are still correct on disk, since it can improve the
4280 // debugging experience better. That job only needs `file`, so we can kick it
4281 // off right now.
4282 comp.thread_pool.spawnWg(&astgen_wait_group, workerUpdateBuiltinFile, .{ comp, file });
4283 continue;
4284 }
4285 astgen_work_items.appendAssumeCapacity(.{
4286 .file_index = file_index,
4287 .file = file,
39904288 });
39914289 }
3992 }
39934290
3994 if (comp.zcu) |zcu| {
3995 {
3996 // Worker threads may append to zcu.files and zcu.import_table
3997 // so we must hold the lock while spawning those tasks, since
3998 // we access those tables in this loop.
3999 comp.mutex.lock();
4000 defer comp.mutex.unlock();
4001
4002 while (comp.astgen_work_queue.readItem()) |file_index| {
4003 // Pre-load these things from our single-threaded context since they
4004 // will be needed by the worker threads.
4005 const path_digest = zcu.filePathDigest(file_index);
4006 const file = zcu.fileByIndex(file_index);
4007 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateFile, .{
4008 comp, file, file_index, path_digest, zir_prog_node, &astgen_wait_group, .root,
4009 });
4010 }
4291 // Now that we're not going to touch `zcu.import_table` again, we can spawn `workerUpdateFile` jobs.
4292 for (astgen_work_items.items(.file_index), astgen_work_items.items(.file)) |file_index, file| {
4293 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateFile, .{
4294 comp, file, file_index, zir_prog_node, &astgen_wait_group,
4295 });
40114296 }
40124297
4013 for (0.., zcu.embed_table.values()) |ef_index_usize, ef| {
4298 // On the other hand, it's fine to directly iterate `zcu.embed_table.keys()` here
4299 // because `workerUpdateEmbedFile` can't invalidate it. The different here is that one
4300 // `@embedFile` can't trigger analysis of a new `@embedFile`!
4301 for (0.., zcu.embed_table.keys()) |ef_index_usize, ef| {
40144302 const ef_index: Zcu.EmbedFile.Index = @enumFromInt(ef_index_usize);
40154303 comp.thread_pool.spawnWgId(&astgen_wait_group, workerUpdateEmbedFile, .{
40164304 comp, ef_index, ef,
......@@ -4035,25 +4323,39 @@ fn performAllTheWorkInner(
40354323 const pt: Zcu.PerThread = .activate(zcu, .main);
40364324 defer pt.deactivate();
40374325
4038 // If the cache mode is `whole`, then add every source file to the cache manifest.
4326 const gpa = zcu.gpa;
4327
4328 // On an incremental update, a source file might become "dead", in that all imports of
4329 // the file were removed. This could even change what module the file belongs to! As such,
4330 // we do a traversal over the files, to figure out which ones are alive and the modules
4331 // they belong to.
4332 const any_fatal_files = try pt.computeAliveFiles();
4333
4334 // If the cache mode is `whole`, add every alive source file to the manifest.
40394335 switch (comp.cache_use) {
40404336 .whole => |whole| if (whole.cache_manifest) |man| {
4041 const gpa = zcu.gpa;
4042 for (zcu.import_table.values()) |file_index| {
4337 for (zcu.alive_files.keys()) |file_index| {
40434338 const file = zcu.fileByIndex(file_index);
4044 const source = file.getSource(gpa) catch |err| {
4045 try pt.reportRetryableFileError(file_index, "unable to load source: {s}", .{@errorName(err)});
4046 continue;
4339
4340 switch (file.status) {
4341 .never_loaded => unreachable, // AstGen tried to load it
4342 .retryable_failure => continue, // the file cannot be read; this is a guaranteed error
4343 .astgen_failure, .success => {}, // the file was read successfully
4344 }
4345
4346 const path = try file.path.toAbsolute(comp.dirs, gpa);
4347 defer gpa.free(path);
4348
4349 const result = res: {
4350 whole.cache_manifest_mutex.lock();
4351 defer whole.cache_manifest_mutex.unlock();
4352 if (file.source) |source| {
4353 break :res man.addFilePostContents(path, source, file.stat);
4354 } else {
4355 break :res man.addFilePost(path);
4356 }
40474357 };
4048 const resolved_path = try std.fs.path.resolve(gpa, &.{
4049 file.mod.root.root_dir.path orelse ".",
4050 file.mod.root.sub_path,
4051 file.sub_file_path,
4052 });
4053 errdefer gpa.free(resolved_path);
4054 whole.cache_manifest_mutex.lock();
4055 defer whole.cache_manifest_mutex.unlock();
4056 man.addFilePostContents(resolved_path, source.bytes, source.stat) catch |err| switch (err) {
4358 result catch |err| switch (err) {
40574359 error.OutOfMemory => |e| return e,
40584360 else => {
40594361 try pt.reportRetryableFileError(file_index, "unable to update cache: {s}", .{@errorName(err)});
......@@ -4065,23 +4367,14 @@ fn performAllTheWorkInner(
40654367 .incremental => {},
40664368 }
40674369
4068 try reportMultiModuleErrors(pt);
4069
4070 const any_fatal_files = for (zcu.import_table.values()) |file_index| {
4071 const file = zcu.fileByIndex(file_index);
4072 switch (file.status) {
4073 .never_loaded => unreachable, // everything is loaded by the workers
4074 .retryable_failure, .astgen_failure => break true,
4075 .success => {},
4076 }
4077 } else false;
4078
4079 if (any_fatal_files or comp.alloc_failure_occurred) {
4370 if (any_fatal_files or
4371 zcu.multi_module_err != null or
4372 zcu.failed_imports.items.len > 0 or
4373 comp.alloc_failure_occurred)
4374 {
40804375 // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
40814376 // us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
40824377 // However, this means our analysis data is invalid, so we want to omit all analysis errors.
4083
4084 assert(zcu.failed_files.count() > 0); // we will get an error
40854378 zcu.skip_analysis_this_update = true;
40864379 return;
40874380 }
......@@ -4093,6 +4386,11 @@ fn performAllTheWorkInner(
40934386 }
40944387 try zcu.flushRetryableFailures();
40954388
4389 // It's analysis time! Queue up our initial analysis.
4390 for (zcu.analysis_roots.slice()) |mod| {
4391 try comp.queueJob(.{ .analyze_mod = mod });
4392 }
4393
40964394 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
40974395 zcu.codegen_prog_node = if (comp.bin_file != null) main_progress_node.start("Code Generation", 0) else .none;
40984396 }
......@@ -4236,7 +4534,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
42364534
42374535 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
42384536 defer pt.deactivate();
4239 pt.semaPkg(mod) catch |err| switch (err) {
4537 pt.semaMod(mod) catch |err| switch (err) {
42404538 error.OutOfMemory => return error.OutOfMemory,
42414539 error.AnalysisFail => return,
42424540 };
......@@ -4301,7 +4599,7 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
43014599
43024600 for (&[_][]const u8{ "docs/main.js", "docs/index.html" }) |sub_path| {
43034601 const basename = std.fs.path.basename(sub_path);
4304 comp.zig_lib_directory.handle.copyFile(sub_path, out_dir, basename, .{}) catch |err| {
4602 comp.dirs.zig_lib.handle.copyFile(sub_path, out_dir, basename, .{}) catch |err| {
43054603 comp.lockAndSetMiscFailure(.docs_copy, "unable to copy {s}: {s}", .{
43064604 sub_path,
43074605 @errorName(err),
......@@ -4338,10 +4636,12 @@ fn docsCopyFallible(comp: *Compilation) anyerror!void {
43384636
43394637fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8, tar_file: std.fs.File) !void {
43404638 const root = module.root;
4341 const sub_path = if (root.sub_path.len == 0) "." else root.sub_path;
4342 var mod_dir = root.root_dir.handle.openDir(sub_path, .{ .iterate = true }) catch |err| {
4639 var mod_dir = d: {
4640 const root_dir, const sub_path = root.openInfo(comp.dirs);
4641 break :d root_dir.openDir(sub_path, .{ .iterate = true });
4642 } catch |err| {
43434643 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open directory '{}': {s}", .{
4344 root, @errorName(err),
4644 root.fmt(comp), @errorName(err),
43454645 });
43464646 };
43474647 defer mod_dir.close();
......@@ -4363,13 +4663,13 @@ fn docsCopyModule(comp: *Compilation, module: *Package.Module, name: []const u8,
43634663 }
43644664 var file = mod_dir.openFile(entry.path, .{}) catch |err| {
43654665 return comp.lockAndSetMiscFailure(.docs_copy, "unable to open '{}{s}': {s}", .{
4366 root, entry.path, @errorName(err),
4666 root.fmt(comp), entry.path, @errorName(err),
43674667 });
43684668 };
43694669 defer file.close();
43704670 archiver.writeFile(entry.path, file) catch |err| {
43714671 return comp.lockAndSetMiscFailure(.docs_copy, "unable to archive '{}{s}': {s}", .{
4372 root, entry.path, @errorName(err),
4672 root.fmt(comp), entry.path, @errorName(err),
43734673 });
43744674 };
43754675 }
......@@ -4430,13 +4730,11 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
44304730 const src_basename = "main.zig";
44314731 const root_name = std.fs.path.stem(src_basename);
44324732
4733 const dirs = comp.dirs.withoutLocalCache();
4734
44334735 const root_mod = try Package.Module.create(arena, .{
4434 .global_cache_directory = comp.global_cache_directory,
44354736 .paths = .{
4436 .root = .{
4437 .root_dir = comp.zig_lib_directory,
4438 .sub_path = "docs/wasm",
4439 },
4737 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"),
44404738 .root_src_path = src_basename,
44414739 },
44424740 .fully_qualified_name = root_name,
......@@ -4447,16 +4745,10 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
44474745 .global = config,
44484746 .cc_argv = &.{},
44494747 .parent = null,
4450 .builtin_mod = null,
4451 .builtin_modules = null,
44524748 });
44534749 const walk_mod = try Package.Module.create(arena, .{
4454 .global_cache_directory = comp.global_cache_directory,
44554750 .paths = .{
4456 .root = .{
4457 .root_dir = comp.zig_lib_directory,
4458 .sub_path = "docs/wasm",
4459 },
4751 .root = try .fromRoot(arena, dirs, .zig_lib, "docs/wasm"),
44604752 .root_src_path = "Walk.zig",
44614753 },
44624754 .fully_qualified_name = "Walk",
......@@ -4467,8 +4759,6 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
44674759 .global = config,
44684760 .cc_argv = &.{},
44694761 .parent = root_mod,
4470 .builtin_mod = root_mod.getBuiltinDependency(),
4471 .builtin_modules = null, // `builtin_mod` is set
44724762 });
44734763 try root_mod.deps.put(arena, "Walk", walk_mod);
44744764 const bin_basename = try std.zig.binNameAlloc(arena, .{
......@@ -4478,9 +4768,7 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
44784768 });
44794769
44804770 const sub_compilation = try Compilation.create(gpa, arena, .{
4481 .global_cache_directory = comp.global_cache_directory,
4482 .local_cache_directory = comp.global_cache_directory,
4483 .zig_lib_directory = comp.zig_lib_directory,
4771 .dirs = dirs,
44844772 .self_exe_path = comp.self_exe_path,
44854773 .config = config,
44864774 .root_mod = root_mod,
......@@ -4517,14 +4805,14 @@ fn workerDocsWasmFallible(comp: *Compilation, prog_node: std.Progress.Node) anye
45174805 };
45184806 defer out_dir.close();
45194807
4520 sub_compilation.local_cache_directory.handle.copyFile(
4808 sub_compilation.dirs.local_cache.handle.copyFile(
45214809 sub_compilation.cache_use.whole.bin_sub_path.?,
45224810 out_dir,
45234811 "main.wasm",
45244812 .{},
45254813 ) catch |err| {
45264814 return comp.lockAndSetMiscFailure(.docs_copy, "unable to copy '{}{s}' to '{}{s}': {s}", .{
4527 sub_compilation.local_cache_directory,
4815 sub_compilation.dirs.local_cache,
45284816 sub_compilation.cache_use.whole.bin_sub_path.?,
45294817 emit.root_dir,
45304818 emit.sub_path,
......@@ -4538,28 +4826,23 @@ fn workerUpdateFile(
45384826 comp: *Compilation,
45394827 file: *Zcu.File,
45404828 file_index: Zcu.File.Index,
4541 path_digest: Cache.BinDigest,
45424829 prog_node: std.Progress.Node,
45434830 wg: *WaitGroup,
4544 src: Zcu.AstGenSrc,
45454831) void {
4546 const child_prog_node = prog_node.start(file.sub_file_path, 0);
4832 const child_prog_node = prog_node.start(std.fs.path.basename(file.path.sub_path), 0);
45474833 defer child_prog_node.end();
45484834
45494835 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
45504836 defer pt.deactivate();
4551 pt.updateFile(file, path_digest) catch |err| switch (err) {
4552 error.AnalysisFail => return,
4553 else => {
4554 pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {
4555 error.OutOfMemory => {
4556 comp.mutex.lock();
4557 defer comp.mutex.unlock();
4558 comp.setAllocFailure();
4559 },
4560 };
4561 return;
4562 },
4837 pt.updateFile(file_index, file) catch |err| {
4838 pt.reportRetryableFileError(file_index, "unable to load '{s}': {s}", .{ std.fs.path.basename(file.path.sub_path), @errorName(err) }) catch |oom| switch (oom) {
4839 error.OutOfMemory => {
4840 comp.mutex.lock();
4841 defer comp.mutex.unlock();
4842 comp.setAllocFailure();
4843 },
4844 };
4845 return;
45634846 };
45644847
45654848 switch (file.getMode()) {
......@@ -4567,9 +4850,9 @@ fn workerUpdateFile(
45674850 .zon => return, // ZON can't import anything so we're done
45684851 }
45694852
4570 // Pre-emptively look for `@import` paths and queue them up.
4571 // If we experience an error preemptively fetching the
4572 // file, just ignore it and let it happen again later during Sema.
4853 // Discover all imports in the file. Imports of modules we ignore for now since we don't
4854 // know which module we're in, but imports of file paths might need us to queue up other
4855 // AstGen jobs.
45734856 const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
45744857 if (imports_index != 0) {
45754858 const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
......@@ -4581,54 +4864,34 @@ fn workerUpdateFile(
45814864 extra_index = item.end;
45824865
45834866 const import_path = file.zir.?.nullTerminatedString(item.data.name);
4584 // `@import("builtin")` is handled specially.
4585 if (mem.eql(u8, import_path, "builtin")) continue;
4586
4587 const import_result, const imported_path_digest = blk: {
4588 comp.mutex.lock();
4589 defer comp.mutex.unlock();
45904867
4591 const res = pt.importFile(file, import_path) catch continue;
4592 if (!res.is_pkg) {
4593 res.file.addReference(pt.zcu, .{ .import = .{
4594 .file = file_index,
4595 .token = item.data.token,
4596 } }) catch continue;
4597 }
4598 if (res.is_new) if (comp.file_system_inputs) |fsi| {
4599 comp.appendFileSystemInput(fsi, res.file.mod.root, res.file.sub_file_path) catch continue;
4600 };
4601 const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
4602 break :blk .{ res, imported_path_digest };
4603 };
4604 if (import_result.is_new) {
4605 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
4606 file.sub_file_path, import_path, import_result.file.sub_file_path,
4607 });
4608 const sub_src: Zcu.AstGenSrc = .{ .import = .{
4609 .importing_file = file_index,
4610 .import_tok = item.data.token,
4611 } };
4612 comp.thread_pool.spawnWgId(wg, workerUpdateFile, .{
4613 comp, import_result.file, import_result.file_index, imported_path_digest, prog_node, wg, sub_src,
4614 });
4868 if (pt.discoverImport(file.path, import_path)) |res| switch (res) {
4869 .module, .existing_file => {},
4870 .new_file => |new| {
4871 comp.thread_pool.spawnWgId(wg, workerUpdateFile, .{
4872 comp, new.file, new.index, prog_node, wg,
4873 });
4874 },
4875 } else |err| switch (err) {
4876 error.OutOfMemory => {
4877 comp.mutex.lock();
4878 defer comp.mutex.unlock();
4879 comp.setAllocFailure();
4880 },
46154881 }
46164882 }
46174883 }
46184884}
46194885
4620fn workerUpdateBuiltinZigFile(
4621 comp: *Compilation,
4622 mod: *Package.Module,
4623 file: *Zcu.File,
4624) void {
4625 Builtin.populateFile(comp, mod, file) catch |err| {
4886fn workerUpdateBuiltinFile(comp: *Compilation, file: *Zcu.File) void {
4887 Builtin.updateFileOnDisk(file, comp) catch |err| {
46264888 comp.mutex.lock();
46274889 defer comp.mutex.unlock();
4628
4629 comp.setMiscFailure(.write_builtin_zig, "unable to write '{}{s}': {s}", .{
4630 mod.root, mod.root_src_path, @errorName(err),
4631 });
4890 comp.setMiscFailure(
4891 .write_builtin_zig,
4892 "unable to write '{}': {s}",
4893 .{ file.path.fmt(comp), @errorName(err) },
4894 );
46324895 };
46334896}
46344897
......@@ -4738,10 +5001,10 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
47385001
47395002 const tmp_digest = man.hash.peek();
47405003 const tmp_dir_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &tmp_digest });
4741 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
5004 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
47425005 defer zig_cache_tmp_dir.close();
47435006 const cimport_basename = "cimport.h";
4744 const out_h_path = try comp.local_cache_directory.join(arena, &[_][]const u8{
5007 const out_h_path = try comp.dirs.local_cache.join(arena, &[_][]const u8{
47455008 tmp_dir_sub_path, cimport_basename,
47465009 });
47475010 const out_dep_path = try std.fmt.allocPrint(arena, "{s}.d", .{out_h_path});
......@@ -4779,7 +5042,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
47795042 new_argv[i] = try arena.dupeZ(u8, arg);
47805043 }
47815044
4782 const c_headers_dir_path_z = try comp.zig_lib_directory.joinZ(arena, &[_][]const u8{"include"});
5045 const c_headers_dir_path_z = try comp.dirs.zig_lib.joinZ(arena, &.{"include"});
47835046 var errors = std.zig.ErrorBundle.empty;
47845047 errdefer errors.deinit(comp.gpa);
47855048 break :tree translate_c.translate(
......@@ -4820,7 +5083,7 @@ pub fn cImport(comp: *Compilation, c_src: []const u8, owner_mod: *Package.Module
48205083 const bin_digest = man.finalBin();
48215084 const hex_digest = Cache.binToHex(bin_digest);
48225085 const o_sub_path = "o" ++ std.fs.path.sep_str ++ hex_digest;
4823 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
5086 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
48245087 defer o_dir.close();
48255088
48265089 var out_zig_file = try o_dir.createFile(cimport_zig_basename, .{});
......@@ -5226,7 +5489,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
52265489 // We can't know the digest until we do the C compiler invocation,
52275490 // so we need a temporary filename.
52285491 const out_obj_path = try comp.tmpFilePath(arena, o_basename);
5229 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
5492 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
52305493 defer zig_cache_tmp_dir.close();
52315494
52325495 const out_diag_path = if (comp.clang_passthrough_mode or !ext.clangSupportsDiagnostics())
......@@ -5362,7 +5625,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
53625625 // Rename into place.
53635626 const digest = man.final();
53645627 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
5365 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
5628 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
53665629 defer o_dir.close();
53675630 const tmp_basename = std.fs.path.basename(out_obj_path);
53685631 try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename);
......@@ -5386,7 +5649,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
53865649 c_object.status = .{
53875650 .success = .{
53885651 .object_path = .{
5389 .root_dir = comp.local_cache_directory,
5652 .root_dir = comp.dirs.local_cache,
53905653 .sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, o_basename }),
53915654 },
53925655 .lock = man.toOwnedLock(),
......@@ -5449,13 +5712,13 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
54495712 const digest = man.final();
54505713
54515714 const o_sub_path = try std.fs.path.join(arena, &.{ "o", &digest });
5452 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
5715 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
54535716 defer o_dir.close();
54545717
5455 const in_rc_path = try comp.local_cache_directory.join(comp.gpa, &.{
5718 const in_rc_path = try comp.dirs.local_cache.join(comp.gpa, &.{
54565719 o_sub_path, rc_basename,
54575720 });
5458 const out_res_path = try comp.local_cache_directory.join(comp.gpa, &.{
5721 const out_res_path = try comp.dirs.local_cache.join(comp.gpa, &.{
54595722 o_sub_path, res_basename,
54605723 });
54615724
......@@ -5517,7 +5780,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
55175780
55185781 win32_resource.status = .{
55195782 .success = .{
5520 .res_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
5783 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{
55215784 "o", &digest, res_basename,
55225785 }),
55235786 .lock = man.toOwnedLock(),
......@@ -5535,7 +5798,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
55355798 const rc_basename_noext = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
55365799
55375800 const digest = if (try man.hit()) man.final() else blk: {
5538 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
5801 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
55395802 defer zig_cache_tmp_dir.close();
55405803
55415804 const res_filename = try std.fmt.allocPrint(arena, "{s}.res", .{rc_basename_noext});
......@@ -5605,7 +5868,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
56055868 // Rename into place.
56065869 const digest = man.final();
56075870 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
5608 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
5871 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
56095872 defer o_dir.close();
56105873 const tmp_basename = std.fs.path.basename(out_res_path);
56115874 try std.fs.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename);
......@@ -5626,7 +5889,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
56265889
56275890 win32_resource.status = .{
56285891 .success = .{
5629 .res_path = try comp.local_cache_directory.join(comp.gpa, &[_][]const u8{
5892 .res_path = try comp.dirs.local_cache.join(comp.gpa, &[_][]const u8{
56305893 "o", &digest, res_basename,
56315894 }),
56325895 .lock = man.toOwnedLock(),
......@@ -5721,7 +5984,7 @@ fn spawnZigRc(
57215984pub fn tmpFilePath(comp: Compilation, ally: Allocator, suffix: []const u8) error{OutOfMemory}![]const u8 {
57225985 const s = std.fs.path.sep_str;
57235986 const rand_int = std.crypto.random.int(u64);
5724 if (comp.local_cache_directory.path) |p| {
5987 if (comp.dirs.local_cache.path) |p| {
57255988 return std.fmt.allocPrint(ally, "{s}" ++ s ++ "tmp" ++ s ++ "{x}-{s}", .{ p, rand_int, suffix });
57265989 } else {
57275990 return std.fmt.allocPrint(ally, "tmp" ++ s ++ "{x}-{s}", .{ rand_int, suffix });
......@@ -5962,12 +6225,12 @@ pub fn addCCArgs(
59626225 if (comp.config.link_libcpp) {
59636226 try argv.append("-isystem");
59646227 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5965 comp.zig_lib_directory.path.?, "libcxx", "include",
6228 comp.dirs.zig_lib.path.?, "libcxx", "include",
59666229 }));
59676230
59686231 try argv.append("-isystem");
59696232 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5970 comp.zig_lib_directory.path.?, "libcxxabi", "include",
6233 comp.dirs.zig_lib.path.?, "libcxxabi", "include",
59716234 }));
59726235
59736236 try libcxx.addCxxArgs(comp, arena, argv);
......@@ -5977,7 +6240,7 @@ pub fn addCCArgs(
59776240 // However as noted by @dimenus, appending libc headers before compiler headers breaks
59786241 // intrinsics and other compiler specific items.
59796242 try argv.append("-isystem");
5980 try argv.append(try std.fs.path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, "include" }));
6243 try argv.append(try std.fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "include" }));
59816244
59826245 try argv.ensureUnusedCapacity(comp.libc_include_dir_list.len * 2);
59836246 for (comp.libc_include_dir_list) |include_dir| {
......@@ -5996,7 +6259,7 @@ pub fn addCCArgs(
59966259 if (comp.config.link_libunwind) {
59976260 try argv.append("-isystem");
59986261 try argv.append(try std.fs.path.join(arena, &[_][]const u8{
5999 comp.zig_lib_directory.path.?, "libunwind", "include",
6262 comp.dirs.zig_lib.path.?, "libunwind", "include",
60006263 }));
60016264 }
60026265
......@@ -6584,12 +6847,12 @@ test "classifyFileExt" {
65846847 try std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
65856848}
65866849
6587fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Path {
6850fn get_libc_crt_file(comp: *Compilation, arena: Allocator, basename: []const u8) !Cache.Path {
65886851 return (try crtFilePath(&comp.crt_files, basename)) orelse {
65896852 const lci = comp.libc_installation orelse return error.LibCInstallationNotAvailable;
65906853 const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCrtDir;
65916854 const full_path = try std.fs.path.join(arena, &[_][]const u8{ crt_dir_path, basename });
6592 return Path.initCwd(full_path);
6855 return Cache.Path.initCwd(full_path);
65936856 };
65946857}
65956858
......@@ -6598,7 +6861,7 @@ pub fn crtFileAsString(comp: *Compilation, arena: Allocator, basename: []const u
65986861 return path.toString(arena);
65996862}
66006863
6601fn crtFilePath(crt_files: *std.StringHashMapUnmanaged(CrtFile), basename: []const u8) Allocator.Error!?Path {
6864fn crtFilePath(crt_files: *std.StringHashMapUnmanaged(CrtFile), basename: []const u8) Allocator.Error!?Cache.Path {
66026865 const crt_file = crt_files.get(basename) orelse return null;
66036866 return crt_file.full_object_path;
66046867}
......@@ -6736,9 +6999,8 @@ fn buildOutputFromZig(
67366999 });
67377000
67387001 const root_mod = try Package.Module.create(arena, .{
6739 .global_cache_directory = comp.global_cache_directory,
67407002 .paths = .{
6741 .root = .{ .root_dir = comp.zig_lib_directory },
7003 .root = .zig_lib_root,
67427004 .root_src_path = src_basename,
67437005 },
67447006 .fully_qualified_name = "root",
......@@ -6760,8 +7022,6 @@ fn buildOutputFromZig(
67607022 .global = config,
67617023 .cc_argv = &.{},
67627024 .parent = null,
6763 .builtin_mod = null,
6764 .builtin_modules = null, // there is only one module in this compilation
67657025 });
67667026 const target = comp.getTarget();
67677027 const bin_basename = try std.zig.binNameAlloc(arena, .{
......@@ -6785,9 +7045,7 @@ fn buildOutputFromZig(
67857045 };
67867046
67877047 const sub_compilation = try Compilation.create(gpa, arena, .{
6788 .global_cache_directory = comp.global_cache_directory,
6789 .local_cache_directory = comp.global_cache_directory,
6790 .zig_lib_directory = comp.zig_lib_directory,
7048 .dirs = comp.dirs.withoutLocalCache(),
67917049 .cache_mode = .whole,
67927050 .parent_whole_cache = parent_whole_cache,
67937051 .self_exe_path = comp.self_exe_path,
......@@ -6878,9 +7136,8 @@ pub fn build_crt_file(
68787136 },
68797137 });
68807138 const root_mod = try Package.Module.create(arena, .{
6881 .global_cache_directory = comp.global_cache_directory,
68827139 .paths = .{
6883 .root = .{ .root_dir = comp.zig_lib_directory },
7140 .root = .zig_lib_root,
68847141 .root_src_path = "",
68857142 },
68867143 .fully_qualified_name = "root",
......@@ -6908,8 +7165,6 @@ pub fn build_crt_file(
69087165 .global = config,
69097166 .cc_argv = &.{},
69107167 .parent = null,
6911 .builtin_mod = null,
6912 .builtin_modules = null, // there is only one module in this compilation
69137168 });
69147169
69157170 for (c_source_files) |*item| {
......@@ -6917,9 +7172,7 @@ pub fn build_crt_file(
69177172 }
69187173
69197174 const sub_compilation = try Compilation.create(gpa, arena, .{
6920 .local_cache_directory = comp.global_cache_directory,
6921 .global_cache_directory = comp.global_cache_directory,
6922 .zig_lib_directory = comp.zig_lib_directory,
7175 .dirs = comp.dirs.withoutLocalCache(),
69237176 .self_exe_path = comp.self_exe_path,
69247177 .cache_mode = .whole,
69257178 .config = config,
......@@ -6962,7 +7215,7 @@ pub fn build_crt_file(
69627215 }
69637216}
69647217
6965pub fn queueLinkTaskMode(comp: *Compilation, path: Path, output_mode: std.builtin.OutputMode) void {
7218pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, output_mode: std.builtin.OutputMode) void {
69667219 comp.queueLinkTasks(switch (output_mode) {
69677220 .Exe => unreachable,
69687221 .Obj => &.{.{ .load_object = path }},
......@@ -6983,7 +7236,7 @@ pub fn queueLinkTasks(comp: *Compilation, tasks: []const link.Task) void {
69837236pub fn toCrtFile(comp: *Compilation) Allocator.Error!CrtFile {
69847237 return .{
69857238 .full_object_path = .{
6986 .root_dir = comp.local_cache_directory,
7239 .root_dir = comp.dirs.local_cache,
69877240 .sub_path = try comp.gpa.dupe(u8, comp.cache_use.whole.bin_sub_path.?),
69887241 },
69897242 .lock = comp.cache_use.whole.moveLock(),
src/InternPool.zig+13
......@@ -1723,6 +1723,19 @@ pub const FileIndex = enum(u32) {
17231723 .index = @intFromEnum(file_index) & ip.getIndexMask(u32),
17241724 };
17251725 }
1726 pub fn toOptional(i: FileIndex) Optional {
1727 return @enumFromInt(@intFromEnum(i));
1728 }
1729 pub const Optional = enum(u32) {
1730 none = std.math.maxInt(u32),
1731 _,
1732 pub fn unwrap(opt: Optional) ?FileIndex {
1733 return switch (opt) {
1734 .none => null,
1735 _ => @enumFromInt(@intFromEnum(opt)),
1736 };
1737 }
1738 };
17261739};
17271740
17281741const File = struct {
src/Package/Module.zig+74-148
......@@ -1,15 +1,17 @@
11//! Corresponds to something that Zig source code can `@import`.
22
3/// Only files inside this directory can be imported.
4root: Cache.Path,
5/// Relative to `root`. May contain path separators.
3/// The root directory of the module. Only files inside this directory can be imported.
4root: Compilation.Path,
5/// Path to the root source file of this module. Relative to `root`. May contain path separators.
66root_src_path: []const u8,
77/// Name used in compile errors. Looks like "root.foo.bar".
88fully_qualified_name: []const u8,
9/// The dependency table of this module. Shared dependencies such as 'std',
10/// 'builtin', and 'root' are not specified in every dependency table, but
11/// instead only in the table of `main_mod`. `Module.importFile` is
12/// responsible for detecting these names and using the correct package.
9/// The dependency table of this module. The shared dependencies 'std' and
10/// 'root' are not specified in every module dependency table, but are stored
11/// separately in `Zcu`. 'builtin' is also not stored here, although it is
12/// not necessarily the same between all modules. Handling of `@import` in
13/// the rest of the compiler must detect these special names and use the
14/// correct module instead of consulting `deps`.
1315deps: Deps = .{},
1416
1517resolved_target: ResolvedTarget,
......@@ -33,25 +35,14 @@ cc_argv: []const []const u8,
3335structured_cfg: bool,
3436no_builtin: bool,
3537
36/// If the module is an `@import("builtin")` module, this is the `File` that
37/// is preallocated for it. Otherwise this field is null.
38builtin_file: ?*File,
39
4038pub const Deps = std.StringArrayHashMapUnmanaged(*Module);
4139
42pub fn isBuiltin(m: Module) bool {
43 return m.builtin_file != null;
44}
45
4640pub const Tree = struct {
4741 /// Each `Package` exposes a `Module` with build.zig as its root source file.
4842 build_module_table: std.AutoArrayHashMapUnmanaged(MultiHashHexDigest, *Module),
4943};
5044
5145pub const CreateOptions = struct {
52 /// Where to store builtin.zig. The global cache directory is used because
53 /// it is a pure function based on CLI flags.
54 global_cache_directory: Cache.Directory,
5546 paths: Paths,
5647 fully_qualified_name: []const u8,
5748
......@@ -61,15 +52,8 @@ pub const CreateOptions = struct {
6152 /// If this is null then `resolved_target` must be non-null.
6253 parent: ?*Package.Module,
6354
64 builtin_mod: ?*Package.Module,
65
66 /// Allocated into the given `arena`. Should be shared across all module creations in a Compilation.
67 /// Ignored if `builtin_mod` is passed or if `!have_zcu`.
68 /// Otherwise, may be `null` only if this Compilation consists of a single module.
69 builtin_modules: ?*std.StringHashMapUnmanaged(*Module),
70
7155 pub const Paths = struct {
72 root: Cache.Path,
56 root: Compilation.Path,
7357 /// Relative to `root`. May contain path separators.
7458 root_src_path: []const u8,
7559 };
......@@ -401,126 +385,13 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
401385 .cc_argv = options.cc_argv,
402386 .structured_cfg = structured_cfg,
403387 .no_builtin = no_builtin,
404 .builtin_file = null,
405388 };
406
407 const opt_builtin_mod = options.builtin_mod orelse b: {
408 if (!options.global.have_zcu) break :b null;
409
410 const generated_builtin_source = try Builtin.generate(.{
411 .target = target,
412 .zig_backend = zig_backend,
413 .output_mode = options.global.output_mode,
414 .link_mode = options.global.link_mode,
415 .unwind_tables = unwind_tables,
416 .is_test = options.global.is_test,
417 .single_threaded = single_threaded,
418 .link_libc = options.global.link_libc,
419 .link_libcpp = options.global.link_libcpp,
420 .optimize_mode = optimize_mode,
421 .error_tracing = error_tracing,
422 .valgrind = valgrind,
423 .sanitize_thread = sanitize_thread,
424 .fuzz = fuzz,
425 .pic = pic,
426 .pie = options.global.pie,
427 .strip = strip,
428 .code_model = code_model,
429 .omit_frame_pointer = omit_frame_pointer,
430 .wasi_exec_model = options.global.wasi_exec_model,
431 }, arena);
432
433 const new = if (options.builtin_modules) |builtins| new: {
434 const gop = try builtins.getOrPut(arena, generated_builtin_source);
435 if (gop.found_existing) break :b gop.value_ptr.*;
436 errdefer builtins.removeByPtr(gop.key_ptr);
437 const new = try arena.create(Module);
438 gop.value_ptr.* = new;
439 break :new new;
440 } else try arena.create(Module);
441 errdefer if (options.builtin_modules) |builtins| assert(builtins.remove(generated_builtin_source));
442
443 const new_file = try arena.create(File);
444
445 const hex_digest = digest: {
446 var hasher: Cache.Hasher = Cache.hasher_init;
447 hasher.update(generated_builtin_source);
448
449 var bin_digest: Cache.BinDigest = undefined;
450 hasher.final(&bin_digest);
451
452 var hex_digest: Cache.HexDigest = undefined;
453 _ = std.fmt.bufPrint(
454 &hex_digest,
455 "{s}",
456 .{std.fmt.fmtSliceHexLower(&bin_digest)},
457 ) catch unreachable;
458
459 break :digest hex_digest;
460 };
461
462 const builtin_sub_path = try arena.dupe(u8, "b" ++ std.fs.path.sep_str ++ hex_digest);
463
464 new.* = .{
465 .root = .{
466 .root_dir = options.global_cache_directory,
467 .sub_path = builtin_sub_path,
468 },
469 .root_src_path = "builtin.zig",
470 .fully_qualified_name = if (options.parent == null)
471 "builtin"
472 else
473 try std.fmt.allocPrint(arena, "{s}.builtin", .{options.fully_qualified_name}),
474 .resolved_target = .{
475 .result = target,
476 .is_native_os = resolved_target.is_native_os,
477 .is_native_abi = resolved_target.is_native_abi,
478 .llvm_cpu_features = llvm_cpu_features,
479 },
480 .optimize_mode = optimize_mode,
481 .single_threaded = single_threaded,
482 .error_tracing = error_tracing,
483 .valgrind = valgrind,
484 .pic = pic,
485 .strip = strip,
486 .omit_frame_pointer = omit_frame_pointer,
487 .stack_check = stack_check,
488 .stack_protector = stack_protector,
489 .code_model = code_model,
490 .red_zone = red_zone,
491 .sanitize_c = sanitize_c,
492 .sanitize_thread = sanitize_thread,
493 .fuzz = fuzz,
494 .unwind_tables = unwind_tables,
495 .cc_argv = &.{},
496 .structured_cfg = structured_cfg,
497 .no_builtin = no_builtin,
498 .builtin_file = new_file,
499 };
500 new_file.* = .{
501 .sub_file_path = "builtin.zig",
502 .stat = undefined,
503 .source = generated_builtin_source,
504 .tree = null,
505 .zir = null,
506 .zoir = null,
507 .status = .never_loaded,
508 .mod = new,
509 };
510 break :b new;
511 };
512
513 if (opt_builtin_mod) |builtin_mod| {
514 try mod.deps.ensureUnusedCapacity(arena, 1);
515 mod.deps.putAssumeCapacityNoClobber("builtin", builtin_mod);
516 }
517
518389 return mod;
519390}
520391
521392/// All fields correspond to `CreateOptions`.
522393pub const LimitedOptions = struct {
523 root: Cache.Path,
394 root: Compilation.Path,
524395 root_src_path: []const u8,
525396 fully_qualified_name: []const u8,
526397};
......@@ -553,18 +424,73 @@ pub fn createLimited(gpa: Allocator, options: LimitedOptions) Allocator.Error!*P
553424 .cc_argv = undefined,
554425 .structured_cfg = undefined,
555426 .no_builtin = undefined,
556 .builtin_file = null,
557427 };
558428 return mod;
559429}
560430
561/// Asserts that the module has a builtin module, which is not true for non-zig
562/// modules such as ones only used for `@embedFile`, or the root module when
563/// there is no Zig Compilation Unit.
564pub fn getBuiltinDependency(m: Module) *Module {
565 const result = m.deps.values()[0];
566 assert(result.isBuiltin());
567 return result;
431/// Does not ensure that the module's root directory exists on-disk; see `Builtin.updateFileOnDisk` for that task.
432pub fn createBuiltin(arena: Allocator, opts: Builtin, dirs: Compilation.Directories) Allocator.Error!*Module {
433 const sub_path = "b" ++ Cache.binToHex(opts.hash());
434 const new = try arena.create(Module);
435 new.* = .{
436 .root = try .fromRoot(arena, dirs, .global_cache, sub_path),
437 .root_src_path = "builtin.zig",
438 .fully_qualified_name = "builtin",
439 .resolved_target = .{
440 .result = opts.target,
441 // These values are not in `opts`, but do not matter because `builtin.zig` contains no runtime code.
442 .is_native_os = false,
443 .is_native_abi = false,
444 .llvm_cpu_features = null,
445 },
446 .optimize_mode = opts.optimize_mode,
447 .single_threaded = opts.single_threaded,
448 .error_tracing = opts.error_tracing,
449 .valgrind = opts.valgrind,
450 .pic = opts.pic,
451 .strip = opts.strip,
452 .omit_frame_pointer = opts.omit_frame_pointer,
453 .code_model = opts.code_model,
454 .sanitize_thread = opts.sanitize_thread,
455 .fuzz = opts.fuzz,
456 .unwind_tables = opts.unwind_tables,
457 .cc_argv = &.{},
458 // These values are not in `opts`, but do not matter because `builtin.zig` contains no runtime code.
459 .stack_check = false,
460 .stack_protector = 0,
461 .red_zone = false,
462 .sanitize_c = .off,
463 .structured_cfg = false,
464 .no_builtin = false,
465 };
466 return new;
467}
468
469/// Returns the `Builtin` which forms the contents of `@import("builtin")` for this module.
470pub fn getBuiltinOptions(m: Module, global: Compilation.Config) Builtin {
471 assert(global.have_zcu);
472 return .{
473 .target = m.resolved_target.result,
474 .zig_backend = target_util.zigBackend(m.resolved_target.result, global.use_llvm),
475 .output_mode = global.output_mode,
476 .link_mode = global.link_mode,
477 .unwind_tables = m.unwind_tables,
478 .is_test = global.is_test,
479 .single_threaded = m.single_threaded,
480 .link_libc = global.link_libc,
481 .link_libcpp = global.link_libcpp,
482 .optimize_mode = m.optimize_mode,
483 .error_tracing = m.error_tracing,
484 .valgrind = m.valgrind,
485 .sanitize_thread = m.sanitize_thread,
486 .fuzz = m.fuzz,
487 .pic = m.pic,
488 .pie = global.pie,
489 .strip = m.strip,
490 .code_model = m.code_model,
491 .omit_frame_pointer = m.omit_frame_pointer,
492 .wasi_exec_model = global.wasi_exec_model,
493 };
568494}
569495
570496const Module = @This();
src/Sema.zig+81-70
......@@ -829,7 +829,7 @@ pub const Block = struct {
829829
830830 pub fn ownerModule(block: Block) *Package.Module {
831831 const zcu = block.sema.pt.zcu;
832 return zcu.namespacePtr(block.namespace).fileScope(zcu).mod;
832 return zcu.namespacePtr(block.namespace).fileScope(zcu).mod.?;
833833 }
834834
835835 fn trackZir(block: *Block, inst: Zir.Inst.Index) Allocator.Error!InternPool.TrackedInst.Index {
......@@ -1127,10 +1127,10 @@ fn analyzeBodyInner(
11271127
11281128 // The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away.
11291129 if (build_options.enable_logging) {
1130 std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: {
1130 std.log.scoped(.sema_zir).debug("sema ZIR {} %{d}", .{ path: {
11311131 const file_index = block.src_base_inst.resolveFile(&zcu.intern_pool);
11321132 const file = zcu.fileByIndex(file_index);
1133 break :sub_file_path file.sub_file_path;
1133 break :path file.path.fmt(zcu.comp);
11341134 }, inst });
11351135 }
11361136
......@@ -6162,50 +6162,67 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
61626162 }
61636163 const parent_mod = parent_block.ownerModule();
61646164 const digest = Cache.binToHex(c_import_res.digest);
6165 const c_import_zig_path = try comp.arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ digest);
6166 const c_import_mod = Package.Module.create(comp.arena, .{
6167 .global_cache_directory = comp.global_cache_directory,
6168 .paths = .{
6169 .root = .{
6170 .root_dir = comp.local_cache_directory,
6171 .sub_path = c_import_zig_path,
6172 },
6173 .root_src_path = "cimport.zig",
6174 },
6175 .fully_qualified_name = c_import_zig_path,
6176 .cc_argv = parent_mod.cc_argv,
6177 .inherited = .{},
6178 .global = comp.config,
6179 .parent = parent_mod,
6180 .builtin_mod = parent_mod.getBuiltinDependency(),
6181 .builtin_modules = null, // `builtin_mod` is set
6182 }) catch |err| switch (err) {
6183 // None of these are possible because we are creating a package with
6184 // the exact same configuration as the parent package, which already
6185 // passed these checks.
6186 error.ValgrindUnsupportedOnTarget => unreachable,
6187 error.TargetRequiresSingleThreaded => unreachable,
6188 error.BackendRequiresSingleThreaded => unreachable,
6189 error.TargetRequiresPic => unreachable,
6190 error.PieRequiresPic => unreachable,
6191 error.DynamicLinkingRequiresPic => unreachable,
6192 error.TargetHasNoRedZone => unreachable,
6193 error.StackCheckUnsupportedByTarget => unreachable,
6194 error.StackProtectorUnsupportedByTarget => unreachable,
6195 error.StackProtectorUnavailableWithoutLibC => unreachable,
61966165
6197 else => |e| return e,
6198 };
6166 const new_file_index = file: {
6167 const c_import_zig_path = try comp.arena.dupe(u8, "o" ++ std.fs.path.sep_str ++ digest);
6168 const c_import_mod = Package.Module.create(comp.arena, .{
6169 .paths = .{
6170 .root = try .fromRoot(comp.arena, comp.dirs, .local_cache, c_import_zig_path),
6171 .root_src_path = "cimport.zig",
6172 },
6173 .fully_qualified_name = c_import_zig_path,
6174 .cc_argv = parent_mod.cc_argv,
6175 .inherited = .{},
6176 .global = comp.config,
6177 .parent = parent_mod,
6178 }) catch |err| switch (err) {
6179 // None of these are possible because we are creating a package with
6180 // the exact same configuration as the parent package, which already
6181 // passed these checks.
6182 error.ValgrindUnsupportedOnTarget => unreachable,
6183 error.TargetRequiresSingleThreaded => unreachable,
6184 error.BackendRequiresSingleThreaded => unreachable,
6185 error.TargetRequiresPic => unreachable,
6186 error.PieRequiresPic => unreachable,
6187 error.DynamicLinkingRequiresPic => unreachable,
6188 error.TargetHasNoRedZone => unreachable,
6189 error.StackCheckUnsupportedByTarget => unreachable,
6190 error.StackProtectorUnsupportedByTarget => unreachable,
6191 error.StackProtectorUnavailableWithoutLibC => unreachable,
61996192
6200 const result = pt.importPkg(c_import_mod) catch |err|
6201 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
6202
6203 const path_digest = zcu.filePathDigest(result.file_index);
6204 pt.updateFile(result.file, path_digest) catch |err|
6193 else => |e| return e,
6194 };
6195 const c_import_file_path: Compilation.Path = try c_import_mod.root.join(gpa, comp.dirs, "cimport.zig");
6196 errdefer c_import_file_path.deinit(gpa);
6197 const c_import_file = try gpa.create(Zcu.File);
6198 errdefer gpa.destroy(c_import_file);
6199 const c_import_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
6200 .bin_digest = c_import_file_path.digest(),
6201 .file = c_import_file,
6202 .root_type = .none,
6203 });
6204 c_import_file.* = .{
6205 .status = .never_loaded,
6206 .stat = undefined,
6207 .is_builtin = false,
6208 .path = c_import_file_path,
6209 .source = null,
6210 .tree = null,
6211 .zir = null,
6212 .zoir = null,
6213 .mod = c_import_mod,
6214 .sub_file_path = "cimport.zig",
6215 .module_changed = false,
6216 .prev_zir = null,
6217 .zoir_invalidated = false,
6218 };
6219 break :file c_import_file_index;
6220 };
6221 pt.updateFile(new_file_index, zcu.fileByIndex(new_file_index)) catch |err|
62056222 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
62066223
6207 try pt.ensureFileAnalyzed(result.file_index);
6208 const ty = zcu.fileRootType(result.file_index);
6224 try pt.ensureFileAnalyzed(new_file_index);
6225 const ty = zcu.fileRootType(new_file_index);
62096226 try sema.declareDependency(.{ .interned = ty });
62106227 try sema.addTypeReferenceEntry(src, ty);
62116228 return Air.internedToRef(ty);
......@@ -14097,25 +14114,19 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1409714114 const operand_src = block.tokenOffset(inst_data.src_tok);
1409814115 const operand = sema.code.nullTerminatedString(extra.path);
1409914116
14100 const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
14101 error.ImportOutsideModulePath => {
14102 return sema.fail(block, operand_src, "import of file outside module path: '{s}'", .{operand});
14103 },
14104 error.ModuleNotFound => {
14105 return sema.fail(block, operand_src, "no module named '{s}' available within module {s}", .{
14106 operand, block.getFileScope(zcu).mod.fully_qualified_name,
14107 });
14108 },
14109 else => {
14110 // TODO: these errors are file system errors; make sure an update() will
14111 // retry this and not cache the file system error, which may be transient.
14112 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
14113 },
14117 const result = pt.doImport(block.getFileScope(zcu), operand) catch |err| switch (err) {
14118 error.ModuleNotFound => return sema.fail(block, operand_src, "no module named '{s}' available within module '{s}'", .{
14119 operand, block.getFileScope(zcu).mod.?.fully_qualified_name,
14120 }),
14121 error.IllegalZigImport => unreachable, // caught before semantic analysis
14122 error.OutOfMemory => |e| return e,
1411414123 };
14115 switch (result.file.getMode()) {
14124 const file_index = result.file;
14125 const file = zcu.fileByIndex(file_index);
14126 switch (file.getMode()) {
1411614127 .zig => {
14117 try pt.ensureFileAnalyzed(result.file_index);
14118 const ty = zcu.fileRootType(result.file_index);
14128 try pt.ensureFileAnalyzed(file_index);
14129 const ty = zcu.fileRootType(file_index);
1411914130 try sema.declareDependency(.{ .interned = ty });
1412014131 try sema.addTypeReferenceEntry(operand_src, ty);
1412114132 return Air.internedToRef(ty);
......@@ -14129,11 +14140,11 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1412914140 break :b res_ty.toIntern();
1413014141 };
1413114142
14132 try sema.declareDependency(.{ .zon_file = result.file_index });
14143 try sema.declareDependency(.{ .zon_file = file_index });
1413314144 const interned = try LowerZon.run(
1413414145 sema,
14135 result.file,
14136 result.file_index,
14146 file,
14147 file_index,
1413714148 res_ty,
1413814149 operand_src,
1413914150 block,
......@@ -17308,10 +17319,10 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1730817319 const name = name: {
1730917320 // TODO: we should probably store this name in the ZIR to avoid this complexity.
1731017321 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
17311 const tree = file.getTree(sema.gpa) catch |err| {
17322 const tree = file.getTree(zcu) catch |err| {
1731217323 // In this case we emit a warning + a less precise source location.
17313 log.warn("unable to load {s}: {s}", .{
17314 file.sub_file_path, @errorName(err),
17324 log.warn("unable to load {}: {s}", .{
17325 file.path.fmt(zcu.comp), @errorName(err),
1731517326 });
1731617327 break :name null;
1731717328 };
......@@ -17336,10 +17347,10 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1733617347 const msg = msg: {
1733717348 const name = name: {
1733817349 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
17339 const tree = file.getTree(sema.gpa) catch |err| {
17350 const tree = file.getTree(zcu) catch |err| {
1734017351 // In this case we emit a warning + a less precise source location.
17341 log.warn("unable to load {s}: {s}", .{
17342 file.sub_file_path, @errorName(err),
17352 log.warn("unable to load {}: {s}", .{
17353 file.path.fmt(zcu.comp), @errorName(err),
1734317354 });
1734417355 break :name null;
1734517356 };
......@@ -17433,7 +17444,7 @@ fn zirBuiltinSrc(
1743317444 };
1743417445
1743517446 const module_name_val = v: {
17436 const module_name = file_scope.mod.fully_qualified_name;
17447 const module_name = file_scope.mod.?.fully_qualified_name;
1743717448 const array_ty = try pt.intern(.{ .array_type = .{
1743817449 .len = module_name.len,
1743917450 .sentinel = .zero_u8,
src/Zcu.zig+441-262
......@@ -72,9 +72,9 @@ sema_prog_node: std.Progress.Node = std.Progress.Node.none,
7272codegen_prog_node: std.Progress.Node = std.Progress.Node.none,
7373
7474/// Used by AstGen worker to load and store ZIR cache.
75global_zir_cache: Compilation.Directory,
75global_zir_cache: Cache.Directory,
7676/// Used by AstGen worker to load and store ZIR cache.
77local_zir_cache: Compilation.Directory,
77local_zir_cache: Cache.Directory,
7878
7979/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
8080/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
......@@ -93,27 +93,72 @@ multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
9393 len: u32,
9494}) = .{},
9595
96/// Key is the digest returned by `Builtin.hash`; value is the corresponding module.
97builtin_modules: std.AutoArrayHashMapUnmanaged(Cache.BinDigest, *Package.Module) = .empty,
98
99/// Populated as soon as the `Compilation` is created. Guaranteed to contain all modules, even builtin ones.
100/// Modules whose root file is not a Zig or ZON file have the value `.none`.
101module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional) = .empty,
102
96103/// The set of all the Zig source files in the Zig Compilation Unit. Tracked in
97104/// order to iterate over it and check which source files have been modified on
98105/// the file system when an update is requested, as well as to cache `@import`
99106/// results.
100107///
101/// Keys are fully resolved file paths. This table owns the keys and values.
108/// Always accessed through `ImportTableAdapter`, where keys are fully resolved
109/// file paths in order to ensure files are properly deduplicated. This table owns
110/// the keys and values.
102111///
103112/// Protected by Compilation's mutex.
104113///
105114/// Not serialized. This state is reconstructed during the first call to
106115/// `Compilation.update` of the process for a given `Compilation`.
107///
108/// Indexes correspond 1:1 to `files`.
109import_table: std.StringArrayHashMapUnmanaged(File.Index) = .empty,
116import_table: std.ArrayHashMapUnmanaged(
117 File.Index,
118 void,
119 struct {
120 pub const hash = @compileError("all accesses should be through ImportTableAdapter");
121 pub const eql = @compileError("all accesses should be through ImportTableAdapter");
122 },
123 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
124) = .empty,
125
126/// The set of all files in `import_table` which are "alive" this update, meaning
127/// they are reachable by traversing imports starting from an analysis root. This
128/// is usually all files in `import_table`, but some could be omitted if an incremental
129/// update removes an import, or if a module specified on the CLI is never imported.
130/// Reconstructed on every update, after AstGen and before Sema.
131/// Value is why the file is alive.
132alive_files: std.AutoArrayHashMapUnmanaged(File.Index, File.Reference) = .empty,
133
134/// If this is populated, a "file exists in multiple modules" error should be emitted.
135/// This causes file errors to not be shown, because we don't really know which files
136/// should be alive (because the user has messed up their imports somewhere!).
137/// Cleared and recomputed every update, after AstGen and before Sema.
138multi_module_err: ?struct {
139 file: File.Index,
140 modules: [2]*Package.Module,
141 refs: [2]File.Reference,
142} = null,
110143
111144/// The set of all the files which have been loaded with `@embedFile` in the Module.
112145/// We keep track of this in order to iterate over it and check which files have been
113146/// modified on the file system when an update is requested, as well as to cache
114147/// `@embedFile` results.
115/// Keys are fully resolved file paths. This table owns the keys and values.
116embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .empty,
148///
149/// Like `import_table`, this is accessed through `EmbedTableAdapter`, so that it is keyed
150/// on the `Compilation.Path` of the `EmbedFile`.
151///
152/// This table owns all of the `*EmbedFile` memory, which is allocated into gpa.
153embed_table: std.ArrayHashMapUnmanaged(
154 *EmbedFile,
155 void,
156 struct {
157 pub const hash = @compileError("all accesses should be through EmbedTableAdapter");
158 pub const eql = @compileError("all accesses should be through EmbedTableAdapter");
159 },
160 true, // This is necessary! Without it, the map tries to use its Context to rehash. #21918
161) = .empty,
117162
118163/// Stores all Type and Value objects.
119164/// The idea is that this will be periodically garbage-collected, but such logic
......@@ -147,9 +192,41 @@ compile_logs: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
147192}) = .empty,
148193compile_log_lines: std.ArrayListUnmanaged(CompileLogLine) = .empty,
149194free_compile_log_lines: std.ArrayListUnmanaged(CompileLogLine.Index) = .empty,
150/// Using a map here for consistency with the other fields here.
151/// The ErrorMsg memory is owned by the `File`, using Module's general purpose allocator.
152failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .empty,
195/// This tracks files which triggered errors when generating AST/ZIR/ZOIR.
196/// If not `null`, the value is a retryable error (the file status is guaranteed
197/// to be `.retryable_failure`). Otherwise, the file status is `.astgen_failure`
198/// or `.success`, and there are ZIR/ZOIR errors which should be printed.
199/// We just store a `[]u8` instead of a full `*ErrorMsg`, because the source
200/// location is always the entire file. The `[]u8` memory is owned by the map
201/// and allocated into `gpa`.
202failed_files: std.AutoArrayHashMapUnmanaged(File.Index, ?[]u8) = .empty,
203/// AstGen is not aware of modules, and so cannot determine whether an import
204/// string makes sense. That is the job of a traversal after AstGen.
205///
206/// There are several ways in which an import can fail:
207///
208/// * It is an import of a file which does not exist. This case is not handled
209/// by this field, but with a `failed_files` entry on the *imported* file.
210/// * It is an import of a module which does not exist in the current module's
211/// dependency table. This happens at `Sema` time, so is not tracked by this
212/// field.
213/// * It is an import which reaches outside of the current module's root
214/// directory. This is tracked by this field.
215/// * It is an import which reaches into an "illegal import directory". Right now,
216/// the only such directory is 'global_cache/b/', but in general, these are
217/// directories the compiler treats specially. This is tracked by this field.
218///
219/// This is a flat array containing all of the relevant errors. It is cleared and
220/// recomputed on every update. The errors here are fatal, i.e. they block any
221/// semantic analysis this update.
222///
223/// Allocated into gpa.
224failed_imports: std.ArrayListUnmanaged(struct {
225 file_index: File.Index,
226 import_string: Zir.NullTerminatedString,
227 import_token: Ast.TokenIndex,
228 kind: enum { file_outside_module_root, illegal_zig_import },
229}) = .empty,
153230failed_exports: std.AutoArrayHashMapUnmanaged(Export.Index, *ErrorMsg) = .empty,
154231/// If analysis failed due to a cimport error, the corresponding Clang errors
155232/// are stored here.
......@@ -235,6 +312,32 @@ generation: u32 = 0,
235312
236313pub const PerThread = @import("Zcu/PerThread.zig");
237314
315pub const ImportTableAdapter = struct {
316 zcu: *const Zcu,
317 pub fn hash(ctx: ImportTableAdapter, path: Compilation.Path) u32 {
318 _ = ctx;
319 return @truncate(std.hash.Wyhash.hash(@intFromEnum(path.root), path.sub_path));
320 }
321 pub fn eql(ctx: ImportTableAdapter, a_path: Compilation.Path, b_file: File.Index, b_index: usize) bool {
322 _ = b_index;
323 const b_path = ctx.zcu.fileByIndex(b_file).path;
324 return a_path.root == b_path.root and mem.eql(u8, a_path.sub_path, b_path.sub_path);
325 }
326};
327
328pub const EmbedTableAdapter = struct {
329 pub fn hash(ctx: EmbedTableAdapter, path: Compilation.Path) u32 {
330 _ = ctx;
331 return @truncate(std.hash.Wyhash.hash(@intFromEnum(path.root), path.sub_path));
332 }
333 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool {
334 _ = ctx;
335 _ = b_index;
336 const b_path = b_file.path;
337 return a_path.root == b_path.root and mem.eql(u8, a_path.sub_path, b_path.sub_path);
338 }
339};
340
238341/// Names of declarations in `std.builtin` whose values are memoized in a `BuiltinDecl.Memoized`.
239342/// The name must exactly match the declaration name, as comptime logic is used to compute the namespace accesses.
240343/// Parent namespaces must be before their children in this enum. For instance, `.Type` must be before `.@"Type.Fn"`.
......@@ -732,41 +835,61 @@ pub const Namespace = struct {
732835};
733836
734837pub const File = struct {
735 /// Relative to the owning package's root source directory.
736 /// Memory is stored in gpa, owned by File.
737 sub_file_path: []const u8,
738
739838 status: enum {
740839 /// We have not yet attempted to load this file.
741840 /// `stat` is not populated and may be `undefined`.
742841 never_loaded,
743842 /// A filesystem access failed. It should be retried on the next update.
744 /// There is a `failed_files` entry containing a non-`null` message.
843 /// There is guaranteed to be a `failed_files` entry with at least one message.
844 /// ZIR/ZOIR errors should not be emitted as `zir`/`zoir` is not up-to-date.
745845 /// `stat` is not populated and may be `undefined`.
746846 retryable_failure,
747 /// Parsing/AstGen/ZonGen of this file has failed.
748 /// There is an error in `zir` or `zoir`.
749 /// There is a `failed_files` entry (with a `null` message).
847 /// This file has failed parsing, AstGen, or ZonGen.
848 /// There is guaranteed to be a `failed_files` entry, which may or may not have messages.
849 /// ZIR/ZOIR errors *should* be emitted as `zir`/`zoir` is up-to-date.
750850 /// `stat` is populated.
751851 astgen_failure,
752852 /// Parsing and AstGen/ZonGen of this file has succeeded.
853 /// There may still be a `failed_files` entry, e.g. for non-fatal AstGen errors.
753854 /// `stat` is populated.
754855 success,
755856 },
756857 /// Whether this is populated depends on `status`.
757858 stat: Cache.File.Stat,
758859
860 /// Whether this file is the generated file of a "builtin" module. This matters because those
861 /// files are generated and stored in-nemory rather than being read off-disk. The rest of the
862 /// pipeline generally shouldn't care about this.
863 is_builtin: bool,
864
865 /// The path of this file. It is important that this path has a "canonical form" because files
866 /// are deduplicated based on path; `Compilation.Path` guarantees this. Owned by this `File`,
867 /// allocated into `gpa`.
868 path: Compilation.Path,
869
759870 source: ?[:0]const u8,
760871 tree: ?Ast,
761872 zir: ?Zir,
762873 zoir: ?Zoir,
763874
764875 /// Module that this file is a part of, managed externally.
765 mod: *Package.Module,
766 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
767 multi_pkg: bool = false,
768 /// List of references to this file, used for multi-package errors.
769 references: std.ArrayListUnmanaged(File.Reference) = .empty,
876 /// This is initially `null`. After AstGen, a pass is run to determine which module each
877 /// file belongs to, at which point this field is set. It is never set to `null` again;
878 /// this is so that if the file starts belonging to a different module instead, we can
879 /// tell, and invalidate dependencies as needed (see `module_changed`).
880 /// During semantic analysis, this is always non-`null` for alive files (i.e. those which
881 /// have imports targeting them).
882 mod: ?*Package.Module,
883 /// Relative to the root directory of `mod`. If `mod == null`, this field is `undefined`.
884 /// This memory is managed externally and must not be directly freed.
885 /// Its lifetime is at least equal to that of this `File`.
886 sub_file_path: []const u8,
887
888 /// If this file's module identity changes on an incremental update, this flag is set to signal
889 /// to `Zcu.updateZirRefs` that all references to this file must be invalidated. This matters
890 /// because changing your module changes things like your optimization mode and codegen flags,
891 /// so everything needs to be re-done. `updateZirRefs` is responsible for resetting this flag.
892 module_changed: bool,
770893
771894 /// The ZIR for this file from the last update with no file failures. As such, this ZIR is never
772895 /// failed (although it may have compile errors).
......@@ -777,7 +900,7 @@ pub const File = struct {
777900 ///
778901 /// In other words, if `TrackedInst`s are tied to ZIR other than what's in the `zir` field, this
779902 /// field is populated with that old ZIR.
780 prev_zir: ?*Zir = null,
903 prev_zir: ?*Zir,
781904
782905 /// This field serves a similar purpose to `prev_zir`, but for ZOIR. However, since we do not
783906 /// need to map old ZOIR to new ZOIR -- instead only invalidating dependencies if the ZOIR
......@@ -785,27 +908,42 @@ pub const File = struct {
785908 ///
786909 /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`,
787910 /// we invalidate the corresponding `zon_file` dependency, and reset it to `false`.
788 zoir_invalidated: bool = false,
911 zoir_invalidated: bool,
912
913 pub const Path = struct {
914 root: enum {
915 cwd,
916 fs_root,
917 local_cache,
918 global_cache,
919 lib_dir,
920 },
921 };
789922
790923 /// A single reference to a file.
791924 pub const Reference = union(enum) {
792 /// The file is imported directly (i.e. not as a package) with @import.
925 analysis_root: *Package.Module,
793926 import: struct {
794 file: File.Index,
795 token: Ast.TokenIndex,
927 importer: Zcu.File.Index,
928 tok: Ast.TokenIndex,
929 /// If the file is imported as the root of a module, this is that module.
930 /// `null` means the file was imported directly by path.
931 module: ?*Package.Module,
796932 },
797 /// The file is the root of a module.
798 root: *Package.Module,
799933 };
800934
801935 pub fn getMode(self: File) Ast.Mode {
802 if (std.mem.endsWith(u8, self.sub_file_path, ".zon")) {
936 // We never create a `File` whose path doesn't give a mode.
937 return modeFromPath(self.path.sub_path).?;
938 }
939
940 pub fn modeFromPath(path: []const u8) ?Ast.Mode {
941 if (std.mem.endsWith(u8, path, ".zon")) {
803942 return .zon;
804 } else if (std.mem.endsWith(u8, self.sub_file_path, ".zig")) {
943 } else if (std.mem.endsWith(u8, path, ".zig")) {
805944 return .zig;
806945 } else {
807 // `Module.importFile` rejects all other extensions
808 unreachable;
946 return null;
809947 }
810948 }
811949
......@@ -842,15 +980,18 @@ pub const File = struct {
842980 stat: Cache.File.Stat,
843981 };
844982
845 pub fn getSource(file: *File, gpa: Allocator) !Source {
983 pub fn getSource(file: *File, zcu: *const Zcu) !Source {
984 const gpa = zcu.gpa;
985
846986 if (file.source) |source| return .{
847987 .bytes = source,
848988 .stat = file.stat,
849989 };
850990
851 // Keep track of inode, file size, mtime, hash so we can detect which files
852 // have been modified when an incremental update is requested.
853 var f = try file.mod.root.openFile(file.sub_file_path, .{});
991 var f = f: {
992 const dir, const sub_path = file.path.openInfo(zcu.comp.dirs);
993 break :f try dir.openFile(sub_path, .{});
994 };
854995 defer f.close();
855996
856997 const stat = try f.stat();
......@@ -882,28 +1023,14 @@ pub const File = struct {
8821023 };
8831024 }
8841025
885 pub fn getTree(file: *File, gpa: Allocator) !*const Ast {
1026 pub fn getTree(file: *File, zcu: *const Zcu) !*const Ast {
8861027 if (file.tree) |*tree| return tree;
8871028
888 const source = try file.getSource(gpa);
889 file.tree = try .parse(gpa, source.bytes, file.getMode());
1029 const source = try file.getSource(zcu);
1030 file.tree = try .parse(zcu.gpa, source.bytes, file.getMode());
8901031 return &file.tree.?;
8911032 }
8921033
893 pub fn getZoir(file: *File, zcu: *Zcu) !*const Zoir {
894 if (file.zoir) |*zoir| return zoir;
895
896 const tree = file.tree.?;
897 assert(tree.mode == .zon);
898
899 file.zoir = try ZonGen.generate(zcu.gpa, tree, .{});
900 if (file.zoir.?.hasCompileErrors()) {
901 try zcu.failed_files.putNoClobber(zcu.gpa, file, null);
902 return error.AnalysisFail;
903 }
904 return &file.zoir.?;
905 }
906
9071034 pub fn fullyQualifiedNameLen(file: File) usize {
9081035 const ext = std.fs.path.extension(file.sub_file_path);
9091036 return file.sub_file_path.len - ext.len;
......@@ -937,85 +1064,49 @@ pub const File = struct {
9371064 return ip.getOrPutTrailingString(gpa, pt.tid, @intCast(slice[0].len), .no_embedded_nulls);
9381065 }
9391066
940 pub fn fullPath(file: File, ally: Allocator) ![]u8 {
941 return file.mod.root.joinString(ally, file.sub_file_path);
942 }
943
944 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
945 const loc = std.zig.findLineColumn(file.source.bytes, src);
946 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
947 }
948
949 /// Add a reference to this file during AstGen.
950 pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
951 // Don't add the same module root twice. Note that since we always add module roots at the
952 // front of the references array (see below), this loop is actually O(1) on valid code.
953 if (ref == .root) {
954 for (file.references.items) |other| {
955 switch (other) {
956 .root => |r| if (ref.root == r) return,
957 else => break, // reached the end of the "is-root" references
958 }
959 }
960 }
961
962 switch (ref) {
963 // We put root references at the front of the list both to make the above loop fast and
964 // to make multi-module errors more helpful (since "root-of" notes are generally more
965 // informative than "imported-from" notes). This path is hit very rarely, so the speed
966 // of the insert operation doesn't matter too much.
967 .root => try file.references.insert(zcu.gpa, 0, ref),
968
969 // Other references we'll just put at the end.
970 else => try file.references.append(zcu.gpa, ref),
971 }
1067 pub const Index = InternPool.FileIndex;
9721068
973 const mod = switch (ref) {
974 .import => |import| zcu.fileByIndex(import.file).mod,
975 .root => |mod| mod,
976 };
977 if (mod != file.mod) file.multi_pkg = true;
1069 pub fn errorBundleWholeFileSrc(
1070 file: *File,
1071 zcu: *const Zcu,
1072 eb: *std.zig.ErrorBundle.Wip,
1073 ) !std.zig.ErrorBundle.SourceLocationIndex {
1074 return eb.addSourceLocation(.{
1075 .src_path = try eb.printString("{}", .{file.path.fmt(zcu.comp)}),
1076 .span_start = 0,
1077 .span_main = 0,
1078 .span_end = 0,
1079 .line = 0,
1080 .column = 0,
1081 .source_line = 0,
1082 });
9781083 }
979
980 /// Mark this file and every file referenced by it as multi_pkg and report an
981 /// astgen_failure error for them. AstGen must have completed in its entirety.
982 pub fn recursiveMarkMultiPkg(file: *File, pt: Zcu.PerThread) void {
983 file.multi_pkg = true;
984 file.status = .astgen_failure;
985
986 // We can only mark children as failed if the ZIR is loaded, which may not
987 // be the case if there were other astgen failures in this file
988 if (file.zir == null) return;
989
990 const imports_index = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
991 if (imports_index == 0) return;
992 const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_index);
993
994 var extra_index = extra.end;
995 for (0..extra.data.imports_len) |_| {
996 const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
997 extra_index = item.end;
998
999 const import_path = file.zir.?.nullTerminatedString(item.data.name);
1000 if (mem.eql(u8, import_path, "builtin")) continue;
1001
1002 const res = pt.importFile(file, import_path) catch continue;
1003 if (!res.is_pkg and !res.file.multi_pkg) {
1004 res.file.recursiveMarkMultiPkg(pt);
1005 }
1006 }
1084 pub fn errorBundleTokenSrc(
1085 file: *File,
1086 tok: Ast.TokenIndex,
1087 zcu: *const Zcu,
1088 eb: *std.zig.ErrorBundle.Wip,
1089 ) !std.zig.ErrorBundle.SourceLocationIndex {
1090 const source = try file.getSource(zcu);
1091 const tree = try file.getTree(zcu);
1092 const start = tree.tokenStart(tok);
1093 const end = start + tree.tokenSlice(tok).len;
1094 const loc = std.zig.findLineColumn(source.bytes, start);
1095 return eb.addSourceLocation(.{
1096 .src_path = try eb.printString("{}", .{file.path.fmt(zcu.comp)}),
1097 .span_start = start,
1098 .span_main = start,
1099 .span_end = @intCast(end),
1100 .line = @intCast(loc.line),
1101 .column = @intCast(loc.column),
1102 .source_line = try eb.addString(loc.source_line),
1103 });
10071104 }
1008
1009 pub const Index = InternPool.FileIndex;
10101105};
10111106
10121107/// Represents the contents of a file loaded with `@embedFile`.
10131108pub const EmbedFile = struct {
1014 /// Module that this file is a part of, managed externally.
1015 owner: *Package.Module,
1016 /// Relative to the owning module's root directory.
1017 sub_file_path: InternPool.NullTerminatedString,
1018
1109 path: Compilation.Path,
10191110 /// `.none` means the file was not loaded, so `stat` is undefined.
10201111 val: InternPool.Index,
10211112 /// If this is `null` and `val` is `.none`, the file has never been loaded.
......@@ -1025,7 +1116,7 @@ pub const EmbedFile = struct {
10251116 pub const Index = enum(u32) {
10261117 _,
10271118 pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile {
1028 return zcu.embed_table.values()[@intFromEnum(idx)];
1119 return zcu.embed_table.keys()[@intFromEnum(idx)];
10291120 }
10301121 };
10311122};
......@@ -1103,32 +1194,31 @@ pub const SrcLoc = struct {
11031194
11041195 pub const Span = Ast.Span;
11051196
1106 pub fn span(src_loc: SrcLoc, gpa: Allocator) !Span {
1197 pub fn span(src_loc: SrcLoc, zcu: *const Zcu) !Span {
11071198 switch (src_loc.lazy) {
11081199 .unneeded => unreachable,
1109 .entire_file => return Span{ .start = 0, .end = 1, .main = 0 },
11101200
11111201 .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index },
11121202
11131203 .token_abs => |tok_index| {
1114 const tree = try src_loc.file_scope.getTree(gpa);
1204 const tree = try src_loc.file_scope.getTree(zcu);
11151205 const start = tree.tokenStart(tok_index);
11161206 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
11171207 return Span{ .start = start, .end = end, .main = start };
11181208 },
11191209 .node_abs => |node| {
1120 const tree = try src_loc.file_scope.getTree(gpa);
1210 const tree = try src_loc.file_scope.getTree(zcu);
11211211 return tree.nodeToSpan(node);
11221212 },
11231213 .byte_offset => |byte_off| {
1124 const tree = try src_loc.file_scope.getTree(gpa);
1214 const tree = try src_loc.file_scope.getTree(zcu);
11251215 const tok_index = src_loc.baseSrcToken();
11261216 const start = tree.tokenStart(tok_index) + byte_off;
11271217 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
11281218 return Span{ .start = start, .end = end, .main = start };
11291219 },
11301220 .token_offset => |tok_off| {
1131 const tree = try src_loc.file_scope.getTree(gpa);
1221 const tree = try src_loc.file_scope.getTree(zcu);
11321222 const tok_index = tok_off.toAbsolute(src_loc.baseSrcToken());
11331223 const start = tree.tokenStart(tok_index);
11341224 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len));
......@@ -1136,23 +1226,23 @@ pub const SrcLoc = struct {
11361226 },
11371227 .node_offset => |traced_off| {
11381228 const node_off = traced_off.x;
1139 const tree = try src_loc.file_scope.getTree(gpa);
1229 const tree = try src_loc.file_scope.getTree(zcu);
11401230 const node = node_off.toAbsolute(src_loc.base_node);
11411231 return tree.nodeToSpan(node);
11421232 },
11431233 .node_offset_main_token => |node_off| {
1144 const tree = try src_loc.file_scope.getTree(gpa);
1234 const tree = try src_loc.file_scope.getTree(zcu);
11451235 const node = node_off.toAbsolute(src_loc.base_node);
11461236 const main_token = tree.nodeMainToken(node);
11471237 return tree.tokensToSpan(main_token, main_token, main_token);
11481238 },
11491239 .node_offset_bin_op => |node_off| {
1150 const tree = try src_loc.file_scope.getTree(gpa);
1240 const tree = try src_loc.file_scope.getTree(zcu);
11511241 const node = node_off.toAbsolute(src_loc.base_node);
11521242 return tree.nodeToSpan(node);
11531243 },
11541244 .node_offset_initializer => |node_off| {
1155 const tree = try src_loc.file_scope.getTree(gpa);
1245 const tree = try src_loc.file_scope.getTree(zcu);
11561246 const node = node_off.toAbsolute(src_loc.base_node);
11571247 return tree.tokensToSpan(
11581248 tree.firstToken(node) - 3,
......@@ -1161,7 +1251,7 @@ pub const SrcLoc = struct {
11611251 );
11621252 },
11631253 .node_offset_var_decl_ty => |node_off| {
1164 const tree = try src_loc.file_scope.getTree(gpa);
1254 const tree = try src_loc.file_scope.getTree(zcu);
11651255 const node = node_off.toAbsolute(src_loc.base_node);
11661256 const full = switch (tree.nodeTag(node)) {
11671257 .global_var_decl,
......@@ -1183,7 +1273,7 @@ pub const SrcLoc = struct {
11831273 return Span{ .start = start, .end = end, .main = start };
11841274 },
11851275 .node_offset_var_decl_align => |node_off| {
1186 const tree = try src_loc.file_scope.getTree(gpa);
1276 const tree = try src_loc.file_scope.getTree(zcu);
11871277 const node = node_off.toAbsolute(src_loc.base_node);
11881278 var buf: [1]Ast.Node.Index = undefined;
11891279 const align_node = if (tree.fullVarDecl(node)) |v|
......@@ -1195,7 +1285,7 @@ pub const SrcLoc = struct {
11951285 return tree.nodeToSpan(align_node);
11961286 },
11971287 .node_offset_var_decl_section => |node_off| {
1198 const tree = try src_loc.file_scope.getTree(gpa);
1288 const tree = try src_loc.file_scope.getTree(zcu);
11991289 const node = node_off.toAbsolute(src_loc.base_node);
12001290 var buf: [1]Ast.Node.Index = undefined;
12011291 const section_node = if (tree.fullVarDecl(node)) |v|
......@@ -1207,7 +1297,7 @@ pub const SrcLoc = struct {
12071297 return tree.nodeToSpan(section_node);
12081298 },
12091299 .node_offset_var_decl_addrspace => |node_off| {
1210 const tree = try src_loc.file_scope.getTree(gpa);
1300 const tree = try src_loc.file_scope.getTree(zcu);
12111301 const node = node_off.toAbsolute(src_loc.base_node);
12121302 var buf: [1]Ast.Node.Index = undefined;
12131303 const addrspace_node = if (tree.fullVarDecl(node)) |v|
......@@ -1219,7 +1309,7 @@ pub const SrcLoc = struct {
12191309 return tree.nodeToSpan(addrspace_node);
12201310 },
12211311 .node_offset_var_decl_init => |node_off| {
1222 const tree = try src_loc.file_scope.getTree(gpa);
1312 const tree = try src_loc.file_scope.getTree(zcu);
12231313 const node = node_off.toAbsolute(src_loc.base_node);
12241314 const init_node = switch (tree.nodeTag(node)) {
12251315 .global_var_decl,
......@@ -1233,14 +1323,14 @@ pub const SrcLoc = struct {
12331323 return tree.nodeToSpan(init_node);
12341324 },
12351325 .node_offset_builtin_call_arg => |builtin_arg| {
1236 const tree = try src_loc.file_scope.getTree(gpa);
1326 const tree = try src_loc.file_scope.getTree(zcu);
12371327 const node = builtin_arg.builtin_call_node.toAbsolute(src_loc.base_node);
12381328 var buf: [2]Ast.Node.Index = undefined;
12391329 const params = tree.builtinCallParams(&buf, node).?;
12401330 return tree.nodeToSpan(params[builtin_arg.arg_index]);
12411331 },
12421332 .node_offset_ptrcast_operand => |node_off| {
1243 const tree = try src_loc.file_scope.getTree(gpa);
1333 const tree = try src_loc.file_scope.getTree(zcu);
12441334
12451335 var node = node_off.toAbsolute(src_loc.base_node);
12461336 while (true) {
......@@ -1273,7 +1363,7 @@ pub const SrcLoc = struct {
12731363 return tree.nodeToSpan(node);
12741364 },
12751365 .node_offset_array_access_index => |node_off| {
1276 const tree = try src_loc.file_scope.getTree(gpa);
1366 const tree = try src_loc.file_scope.getTree(zcu);
12771367 const node = node_off.toAbsolute(src_loc.base_node);
12781368 return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]);
12791369 },
......@@ -1282,7 +1372,7 @@ pub const SrcLoc = struct {
12821372 .node_offset_slice_end,
12831373 .node_offset_slice_sentinel,
12841374 => |node_off| {
1285 const tree = try src_loc.file_scope.getTree(gpa);
1375 const tree = try src_loc.file_scope.getTree(zcu);
12861376 const node = node_off.toAbsolute(src_loc.base_node);
12871377 const full = tree.fullSlice(node).?;
12881378 const part_node = switch (src_loc.lazy) {
......@@ -1295,14 +1385,14 @@ pub const SrcLoc = struct {
12951385 return tree.nodeToSpan(part_node);
12961386 },
12971387 .node_offset_call_func => |node_off| {
1298 const tree = try src_loc.file_scope.getTree(gpa);
1388 const tree = try src_loc.file_scope.getTree(zcu);
12991389 const node = node_off.toAbsolute(src_loc.base_node);
13001390 var buf: [1]Ast.Node.Index = undefined;
13011391 const full = tree.fullCall(&buf, node).?;
13021392 return tree.nodeToSpan(full.ast.fn_expr);
13031393 },
13041394 .node_offset_field_name => |node_off| {
1305 const tree = try src_loc.file_scope.getTree(gpa);
1395 const tree = try src_loc.file_scope.getTree(zcu);
13061396 const node = node_off.toAbsolute(src_loc.base_node);
13071397 var buf: [1]Ast.Node.Index = undefined;
13081398 const tok_index = switch (tree.nodeTag(node)) {
......@@ -1326,7 +1416,7 @@ pub const SrcLoc = struct {
13261416 return Span{ .start = start, .end = end, .main = start };
13271417 },
13281418 .node_offset_field_name_init => |node_off| {
1329 const tree = try src_loc.file_scope.getTree(gpa);
1419 const tree = try src_loc.file_scope.getTree(zcu);
13301420 const node = node_off.toAbsolute(src_loc.base_node);
13311421 const tok_index = tree.firstToken(node) - 2;
13321422 const start = tree.tokenStart(tok_index);
......@@ -1334,18 +1424,18 @@ pub const SrcLoc = struct {
13341424 return Span{ .start = start, .end = end, .main = start };
13351425 },
13361426 .node_offset_deref_ptr => |node_off| {
1337 const tree = try src_loc.file_scope.getTree(gpa);
1427 const tree = try src_loc.file_scope.getTree(zcu);
13381428 const node = node_off.toAbsolute(src_loc.base_node);
13391429 return tree.nodeToSpan(node);
13401430 },
13411431 .node_offset_asm_source => |node_off| {
1342 const tree = try src_loc.file_scope.getTree(gpa);
1432 const tree = try src_loc.file_scope.getTree(zcu);
13431433 const node = node_off.toAbsolute(src_loc.base_node);
13441434 const full = tree.fullAsm(node).?;
13451435 return tree.nodeToSpan(full.ast.template);
13461436 },
13471437 .node_offset_asm_ret_ty => |node_off| {
1348 const tree = try src_loc.file_scope.getTree(gpa);
1438 const tree = try src_loc.file_scope.getTree(zcu);
13491439 const node = node_off.toAbsolute(src_loc.base_node);
13501440 const full = tree.fullAsm(node).?;
13511441 const asm_output = full.outputs[0];
......@@ -1353,7 +1443,7 @@ pub const SrcLoc = struct {
13531443 },
13541444
13551445 .node_offset_if_cond => |node_off| {
1356 const tree = try src_loc.file_scope.getTree(gpa);
1446 const tree = try src_loc.file_scope.getTree(zcu);
13571447 const node = node_off.toAbsolute(src_loc.base_node);
13581448 const src_node = switch (tree.nodeTag(node)) {
13591449 .if_simple,
......@@ -1381,14 +1471,14 @@ pub const SrcLoc = struct {
13811471 return tree.nodeToSpan(src_node);
13821472 },
13831473 .for_input => |for_input| {
1384 const tree = try src_loc.file_scope.getTree(gpa);
1474 const tree = try src_loc.file_scope.getTree(zcu);
13851475 const node = for_input.for_node_offset.toAbsolute(src_loc.base_node);
13861476 const for_full = tree.fullFor(node).?;
13871477 const src_node = for_full.ast.inputs[for_input.input_index];
13881478 return tree.nodeToSpan(src_node);
13891479 },
13901480 .for_capture_from_input => |node_off| {
1391 const tree = try src_loc.file_scope.getTree(gpa);
1481 const tree = try src_loc.file_scope.getTree(zcu);
13921482 const input_node = node_off.toAbsolute(src_loc.base_node);
13931483 // We have to actually linear scan the whole AST to find the for loop
13941484 // that contains this input.
......@@ -1429,7 +1519,7 @@ pub const SrcLoc = struct {
14291519 } else unreachable;
14301520 },
14311521 .call_arg => |call_arg| {
1432 const tree = try src_loc.file_scope.getTree(gpa);
1522 const tree = try src_loc.file_scope.getTree(zcu);
14331523 const node = call_arg.call_node_offset.toAbsolute(src_loc.base_node);
14341524 var buf: [2]Ast.Node.Index = undefined;
14351525 const call_full = tree.fullCall(buf[0..1], node) orelse {
......@@ -1466,7 +1556,7 @@ pub const SrcLoc = struct {
14661556 return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]);
14671557 },
14681558 .fn_proto_param, .fn_proto_param_type => |fn_proto_param| {
1469 const tree = try src_loc.file_scope.getTree(gpa);
1559 const tree = try src_loc.file_scope.getTree(zcu);
14701560 const node = fn_proto_param.fn_proto_node_offset.toAbsolute(src_loc.base_node);
14711561 var buf: [1]Ast.Node.Index = undefined;
14721562 const full = tree.fullFnProto(&buf, node).?;
......@@ -1494,17 +1584,17 @@ pub const SrcLoc = struct {
14941584 unreachable;
14951585 },
14961586 .node_offset_bin_lhs => |node_off| {
1497 const tree = try src_loc.file_scope.getTree(gpa);
1587 const tree = try src_loc.file_scope.getTree(zcu);
14981588 const node = node_off.toAbsolute(src_loc.base_node);
14991589 return tree.nodeToSpan(tree.nodeData(node).node_and_node[0]);
15001590 },
15011591 .node_offset_bin_rhs => |node_off| {
1502 const tree = try src_loc.file_scope.getTree(gpa);
1592 const tree = try src_loc.file_scope.getTree(zcu);
15031593 const node = node_off.toAbsolute(src_loc.base_node);
15041594 return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]);
15051595 },
15061596 .array_cat_lhs, .array_cat_rhs => |cat| {
1507 const tree = try src_loc.file_scope.getTree(gpa);
1597 const tree = try src_loc.file_scope.getTree(zcu);
15081598 const node = cat.array_cat_offset.toAbsolute(src_loc.base_node);
15091599 const arr_node = if (src_loc.lazy == .array_cat_lhs)
15101600 tree.nodeData(node).node_and_node[0]
......@@ -1530,20 +1620,20 @@ pub const SrcLoc = struct {
15301620 },
15311621
15321622 .node_offset_try_operand => |node_off| {
1533 const tree = try src_loc.file_scope.getTree(gpa);
1623 const tree = try src_loc.file_scope.getTree(zcu);
15341624 const node = node_off.toAbsolute(src_loc.base_node);
15351625 return tree.nodeToSpan(tree.nodeData(node).node);
15361626 },
15371627
15381628 .node_offset_switch_operand => |node_off| {
1539 const tree = try src_loc.file_scope.getTree(gpa);
1629 const tree = try src_loc.file_scope.getTree(zcu);
15401630 const node = node_off.toAbsolute(src_loc.base_node);
15411631 const condition, _ = tree.nodeData(node).node_and_extra;
15421632 return tree.nodeToSpan(condition);
15431633 },
15441634
15451635 .node_offset_switch_special_prong => |node_off| {
1546 const tree = try src_loc.file_scope.getTree(gpa);
1636 const tree = try src_loc.file_scope.getTree(zcu);
15471637 const switch_node = node_off.toAbsolute(src_loc.base_node);
15481638 _, const extra_index = tree.nodeData(switch_node).node_and_extra;
15491639 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index);
......@@ -1560,7 +1650,7 @@ pub const SrcLoc = struct {
15601650 },
15611651
15621652 .node_offset_switch_range => |node_off| {
1563 const tree = try src_loc.file_scope.getTree(gpa);
1653 const tree = try src_loc.file_scope.getTree(zcu);
15641654 const switch_node = node_off.toAbsolute(src_loc.base_node);
15651655 _, const extra_index = tree.nodeData(switch_node).node_and_extra;
15661656 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index);
......@@ -1580,28 +1670,28 @@ pub const SrcLoc = struct {
15801670 } else unreachable;
15811671 },
15821672 .node_offset_fn_type_align => |node_off| {
1583 const tree = try src_loc.file_scope.getTree(gpa);
1673 const tree = try src_loc.file_scope.getTree(zcu);
15841674 const node = node_off.toAbsolute(src_loc.base_node);
15851675 var buf: [1]Ast.Node.Index = undefined;
15861676 const full = tree.fullFnProto(&buf, node).?;
15871677 return tree.nodeToSpan(full.ast.align_expr.unwrap().?);
15881678 },
15891679 .node_offset_fn_type_addrspace => |node_off| {
1590 const tree = try src_loc.file_scope.getTree(gpa);
1680 const tree = try src_loc.file_scope.getTree(zcu);
15911681 const node = node_off.toAbsolute(src_loc.base_node);
15921682 var buf: [1]Ast.Node.Index = undefined;
15931683 const full = tree.fullFnProto(&buf, node).?;
15941684 return tree.nodeToSpan(full.ast.addrspace_expr.unwrap().?);
15951685 },
15961686 .node_offset_fn_type_section => |node_off| {
1597 const tree = try src_loc.file_scope.getTree(gpa);
1687 const tree = try src_loc.file_scope.getTree(zcu);
15981688 const node = node_off.toAbsolute(src_loc.base_node);
15991689 var buf: [1]Ast.Node.Index = undefined;
16001690 const full = tree.fullFnProto(&buf, node).?;
16011691 return tree.nodeToSpan(full.ast.section_expr.unwrap().?);
16021692 },
16031693 .node_offset_fn_type_cc => |node_off| {
1604 const tree = try src_loc.file_scope.getTree(gpa);
1694 const tree = try src_loc.file_scope.getTree(zcu);
16051695 const node = node_off.toAbsolute(src_loc.base_node);
16061696 var buf: [1]Ast.Node.Index = undefined;
16071697 const full = tree.fullFnProto(&buf, node).?;
......@@ -1609,14 +1699,14 @@ pub const SrcLoc = struct {
16091699 },
16101700
16111701 .node_offset_fn_type_ret_ty => |node_off| {
1612 const tree = try src_loc.file_scope.getTree(gpa);
1702 const tree = try src_loc.file_scope.getTree(zcu);
16131703 const node = node_off.toAbsolute(src_loc.base_node);
16141704 var buf: [1]Ast.Node.Index = undefined;
16151705 const full = tree.fullFnProto(&buf, node).?;
16161706 return tree.nodeToSpan(full.ast.return_type.unwrap().?);
16171707 },
16181708 .node_offset_param => |node_off| {
1619 const tree = try src_loc.file_scope.getTree(gpa);
1709 const tree = try src_loc.file_scope.getTree(zcu);
16201710 const node = node_off.toAbsolute(src_loc.base_node);
16211711
16221712 var first_tok = tree.firstToken(node);
......@@ -1631,7 +1721,7 @@ pub const SrcLoc = struct {
16311721 );
16321722 },
16331723 .token_offset_param => |token_off| {
1634 const tree = try src_loc.file_scope.getTree(gpa);
1724 const tree = try src_loc.file_scope.getTree(zcu);
16351725 const main_token = tree.nodeMainToken(src_loc.base_node);
16361726 const tok_index = token_off.toAbsolute(main_token);
16371727
......@@ -1648,14 +1738,14 @@ pub const SrcLoc = struct {
16481738 },
16491739
16501740 .node_offset_anyframe_type => |node_off| {
1651 const tree = try src_loc.file_scope.getTree(gpa);
1741 const tree = try src_loc.file_scope.getTree(zcu);
16521742 const parent_node = node_off.toAbsolute(src_loc.base_node);
16531743 _, const child_type = tree.nodeData(parent_node).token_and_node;
16541744 return tree.nodeToSpan(child_type);
16551745 },
16561746
16571747 .node_offset_lib_name => |node_off| {
1658 const tree = try src_loc.file_scope.getTree(gpa);
1748 const tree = try src_loc.file_scope.getTree(zcu);
16591749 const parent_node = node_off.toAbsolute(src_loc.base_node);
16601750 var buf: [1]Ast.Node.Index = undefined;
16611751 const full = tree.fullFnProto(&buf, parent_node).?;
......@@ -1666,75 +1756,75 @@ pub const SrcLoc = struct {
16661756 },
16671757
16681758 .node_offset_array_type_len => |node_off| {
1669 const tree = try src_loc.file_scope.getTree(gpa);
1759 const tree = try src_loc.file_scope.getTree(zcu);
16701760 const parent_node = node_off.toAbsolute(src_loc.base_node);
16711761
16721762 const full = tree.fullArrayType(parent_node).?;
16731763 return tree.nodeToSpan(full.ast.elem_count);
16741764 },
16751765 .node_offset_array_type_sentinel => |node_off| {
1676 const tree = try src_loc.file_scope.getTree(gpa);
1766 const tree = try src_loc.file_scope.getTree(zcu);
16771767 const parent_node = node_off.toAbsolute(src_loc.base_node);
16781768
16791769 const full = tree.fullArrayType(parent_node).?;
16801770 return tree.nodeToSpan(full.ast.sentinel.unwrap().?);
16811771 },
16821772 .node_offset_array_type_elem => |node_off| {
1683 const tree = try src_loc.file_scope.getTree(gpa);
1773 const tree = try src_loc.file_scope.getTree(zcu);
16841774 const parent_node = node_off.toAbsolute(src_loc.base_node);
16851775
16861776 const full = tree.fullArrayType(parent_node).?;
16871777 return tree.nodeToSpan(full.ast.elem_type);
16881778 },
16891779 .node_offset_un_op => |node_off| {
1690 const tree = try src_loc.file_scope.getTree(gpa);
1780 const tree = try src_loc.file_scope.getTree(zcu);
16911781 const node = node_off.toAbsolute(src_loc.base_node);
16921782 return tree.nodeToSpan(tree.nodeData(node).node);
16931783 },
16941784 .node_offset_ptr_elem => |node_off| {
1695 const tree = try src_loc.file_scope.getTree(gpa);
1785 const tree = try src_loc.file_scope.getTree(zcu);
16961786 const parent_node = node_off.toAbsolute(src_loc.base_node);
16971787
16981788 const full = tree.fullPtrType(parent_node).?;
16991789 return tree.nodeToSpan(full.ast.child_type);
17001790 },
17011791 .node_offset_ptr_sentinel => |node_off| {
1702 const tree = try src_loc.file_scope.getTree(gpa);
1792 const tree = try src_loc.file_scope.getTree(zcu);
17031793 const parent_node = node_off.toAbsolute(src_loc.base_node);
17041794
17051795 const full = tree.fullPtrType(parent_node).?;
17061796 return tree.nodeToSpan(full.ast.sentinel.unwrap().?);
17071797 },
17081798 .node_offset_ptr_align => |node_off| {
1709 const tree = try src_loc.file_scope.getTree(gpa);
1799 const tree = try src_loc.file_scope.getTree(zcu);
17101800 const parent_node = node_off.toAbsolute(src_loc.base_node);
17111801
17121802 const full = tree.fullPtrType(parent_node).?;
17131803 return tree.nodeToSpan(full.ast.align_node.unwrap().?);
17141804 },
17151805 .node_offset_ptr_addrspace => |node_off| {
1716 const tree = try src_loc.file_scope.getTree(gpa);
1806 const tree = try src_loc.file_scope.getTree(zcu);
17171807 const parent_node = node_off.toAbsolute(src_loc.base_node);
17181808
17191809 const full = tree.fullPtrType(parent_node).?;
17201810 return tree.nodeToSpan(full.ast.addrspace_node.unwrap().?);
17211811 },
17221812 .node_offset_ptr_bitoffset => |node_off| {
1723 const tree = try src_loc.file_scope.getTree(gpa);
1813 const tree = try src_loc.file_scope.getTree(zcu);
17241814 const parent_node = node_off.toAbsolute(src_loc.base_node);
17251815
17261816 const full = tree.fullPtrType(parent_node).?;
17271817 return tree.nodeToSpan(full.ast.bit_range_start.unwrap().?);
17281818 },
17291819 .node_offset_ptr_hostsize => |node_off| {
1730 const tree = try src_loc.file_scope.getTree(gpa);
1820 const tree = try src_loc.file_scope.getTree(zcu);
17311821 const parent_node = node_off.toAbsolute(src_loc.base_node);
17321822
17331823 const full = tree.fullPtrType(parent_node).?;
17341824 return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?);
17351825 },
17361826 .node_offset_container_tag => |node_off| {
1737 const tree = try src_loc.file_scope.getTree(gpa);
1827 const tree = try src_loc.file_scope.getTree(zcu);
17381828 const parent_node = node_off.toAbsolute(src_loc.base_node);
17391829
17401830 switch (tree.nodeTag(parent_node)) {
......@@ -1757,7 +1847,7 @@ pub const SrcLoc = struct {
17571847 }
17581848 },
17591849 .node_offset_field_default => |node_off| {
1760 const tree = try src_loc.file_scope.getTree(gpa);
1850 const tree = try src_loc.file_scope.getTree(zcu);
17611851 const parent_node = node_off.toAbsolute(src_loc.base_node);
17621852
17631853 const full: Ast.full.ContainerField = switch (tree.nodeTag(parent_node)) {
......@@ -1768,7 +1858,7 @@ pub const SrcLoc = struct {
17681858 return tree.nodeToSpan(full.ast.value_expr.unwrap().?);
17691859 },
17701860 .node_offset_init_ty => |node_off| {
1771 const tree = try src_loc.file_scope.getTree(gpa);
1861 const tree = try src_loc.file_scope.getTree(zcu);
17721862 const parent_node = node_off.toAbsolute(src_loc.base_node);
17731863
17741864 var buf: [2]Ast.Node.Index = undefined;
......@@ -1779,7 +1869,7 @@ pub const SrcLoc = struct {
17791869 return tree.nodeToSpan(type_expr);
17801870 },
17811871 .node_offset_store_ptr => |node_off| {
1782 const tree = try src_loc.file_scope.getTree(gpa);
1872 const tree = try src_loc.file_scope.getTree(zcu);
17831873 const node = node_off.toAbsolute(src_loc.base_node);
17841874
17851875 switch (tree.nodeTag(node)) {
......@@ -1806,7 +1896,7 @@ pub const SrcLoc = struct {
18061896 }
18071897 },
18081898 .node_offset_store_operand => |node_off| {
1809 const tree = try src_loc.file_scope.getTree(gpa);
1899 const tree = try src_loc.file_scope.getTree(zcu);
18101900 const node = node_off.toAbsolute(src_loc.base_node);
18111901
18121902 switch (tree.nodeTag(node)) {
......@@ -1833,7 +1923,7 @@ pub const SrcLoc = struct {
18331923 }
18341924 },
18351925 .node_offset_return_operand => |node_off| {
1836 const tree = try src_loc.file_scope.getTree(gpa);
1926 const tree = try src_loc.file_scope.getTree(zcu);
18371927 const node = node_off.toAbsolute(src_loc.base_node);
18381928 if (tree.nodeTag(node) == .@"return") {
18391929 if (tree.nodeData(node).opt_node.unwrap()) |lhs| {
......@@ -1847,7 +1937,7 @@ pub const SrcLoc = struct {
18471937 .container_field_type,
18481938 .container_field_align,
18491939 => |field_idx| {
1850 const tree = try src_loc.file_scope.getTree(gpa);
1940 const tree = try src_loc.file_scope.getTree(zcu);
18511941 const node = src_loc.base_node;
18521942 var buf: [2]Ast.Node.Index = undefined;
18531943 const container_decl = tree.fullContainerDecl(&buf, node) orelse
......@@ -1875,7 +1965,7 @@ pub const SrcLoc = struct {
18751965 } else unreachable;
18761966 },
18771967 .tuple_field_type, .tuple_field_init => |field_info| {
1878 const tree = try src_loc.file_scope.getTree(gpa);
1968 const tree = try src_loc.file_scope.getTree(zcu);
18791969 const node = src_loc.base_node;
18801970 var buf: [2]Ast.Node.Index = undefined;
18811971 const container_decl = tree.fullContainerDecl(&buf, node) orelse
......@@ -1889,7 +1979,7 @@ pub const SrcLoc = struct {
18891979 });
18901980 },
18911981 .init_elem => |init_elem| {
1892 const tree = try src_loc.file_scope.getTree(gpa);
1982 const tree = try src_loc.file_scope.getTree(zcu);
18931983 const init_node = init_elem.init_node_offset.toAbsolute(src_loc.base_node);
18941984 var buf: [2]Ast.Node.Index = undefined;
18951985 if (tree.fullArrayInit(&buf, init_node)) |full| {
......@@ -1928,7 +2018,7 @@ pub const SrcLoc = struct {
19282018 .init_field_dll_import => "dll_import",
19292019 else => unreachable,
19302020 };
1931 const tree = try src_loc.file_scope.getTree(gpa);
2021 const tree = try src_loc.file_scope.getTree(zcu);
19322022 const node = builtin_call_node.toAbsolute(src_loc.base_node);
19332023 var builtin_buf: [2]Ast.Node.Index = undefined;
19342024 const args = tree.builtinCallParams(&builtin_buf, node).?;
......@@ -1967,7 +2057,7 @@ pub const SrcLoc = struct {
19672057 else => unreachable,
19682058 };
19692059
1970 const tree = try src_loc.file_scope.getTree(gpa);
2060 const tree = try src_loc.file_scope.getTree(zcu);
19712061 const switch_node = switch_node_offset.toAbsolute(src_loc.base_node);
19722062 _, const extra_index = tree.nodeData(switch_node).node_and_extra;
19732063 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index);
......@@ -2062,7 +2152,7 @@ pub const SrcLoc = struct {
20622152 }
20632153 },
20642154 .func_decl_param_comptime => |param_idx| {
2065 const tree = try src_loc.file_scope.getTree(gpa);
2155 const tree = try src_loc.file_scope.getTree(zcu);
20662156 var buf: [1]Ast.Node.Index = undefined;
20672157 const full = tree.fullFnProto(&buf, src_loc.base_node).?;
20682158 var param_it = full.iterate(tree);
......@@ -2071,7 +2161,7 @@ pub const SrcLoc = struct {
20712161 return tree.tokenToSpan(param.comptime_noalias.?);
20722162 },
20732163 .func_decl_param_ty => |param_idx| {
2074 const tree = try src_loc.file_scope.getTree(gpa);
2164 const tree = try src_loc.file_scope.getTree(zcu);
20752165 var buf: [1]Ast.Node.Index = undefined;
20762166 const full = tree.fullFnProto(&buf, src_loc.base_node).?;
20772167 var param_it = full.iterate(tree);
......@@ -2100,9 +2190,6 @@ pub const LazySrcLoc = struct {
21002190 /// value is being set to this tag.
21012191 /// `base_node_inst` is unused.
21022192 unneeded,
2103 /// Means the source location points to an entire file; not any particular
2104 /// location within the file. `file_scope` union field will be active.
2105 entire_file,
21062193 /// The source location points to a byte offset within a source file,
21072194 /// offset from 0. The source file is determined contextually.
21082195 byte_abs: u32,
......@@ -2521,10 +2608,7 @@ pub const LazySrcLoc = struct {
25212608
25222609 /// Like `upgrade`, but returns `null` if the source location has been lost across incremental updates.
25232610 pub fn upgradeOrLost(lazy: LazySrcLoc, zcu: *Zcu) ?SrcLoc {
2524 const file, const base_node: Ast.Node.Index = if (lazy.offset == .entire_file) .{
2525 zcu.fileByIndex(lazy.base_node_inst.resolveFile(&zcu.intern_pool)),
2526 .root,
2527 } else resolveBaseNode(lazy.base_node_inst, zcu) orelse return null;
2611 const file, const base_node: Ast.Node.Index = resolveBaseNode(lazy.base_node_inst, zcu) orelse return null;
25282612 return .{
25292613 .file_scope = file,
25302614 .base_node = base_node,
......@@ -2544,15 +2628,16 @@ pub const LazySrcLoc = struct {
25442628 return true;
25452629 };
25462630 if (lhs_src.file_scope != rhs_src.file_scope) {
2547 return std.mem.order(
2548 u8,
2549 lhs_src.file_scope.sub_file_path,
2550 rhs_src.file_scope.sub_file_path,
2551 ).compare(.lt);
2631 const lhs_path = lhs_src.file_scope.path;
2632 const rhs_path = rhs_src.file_scope.path;
2633 if (lhs_path.root != rhs_path.root) {
2634 return @intFromEnum(lhs_path.root) < @intFromEnum(rhs_path.root);
2635 }
2636 return std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).compare(.lt);
25522637 }
25532638
2554 const lhs_span = try lhs_src.span(zcu.gpa);
2555 const rhs_span = try rhs_src.span(zcu.gpa);
2639 const lhs_span = try lhs_src.span(zcu);
2640 const rhs_span = try rhs_src.span(zcu);
25562641 return lhs_span.main < rhs_span.main;
25572642 }
25582643};
......@@ -2583,16 +2668,16 @@ pub fn deinit(zcu: *Zcu) void {
25832668
25842669 if (zcu.llvm_object) |llvm_object| llvm_object.deinit();
25852670
2586 for (zcu.import_table.keys()) |key| {
2587 gpa.free(key);
2588 }
2589 for (zcu.import_table.values()) |file_index| {
2671 zcu.builtin_modules.deinit(gpa);
2672 zcu.module_roots.deinit(gpa);
2673 for (zcu.import_table.keys()) |file_index| {
25902674 pt.destroyFile(file_index);
25912675 }
25922676 zcu.import_table.deinit(gpa);
2677 zcu.alive_files.deinit(gpa);
25932678
2594 for (zcu.embed_table.keys(), zcu.embed_table.values()) |path, embed_file| {
2595 gpa.free(path);
2679 for (zcu.embed_table.keys()) |embed_file| {
2680 embed_file.path.deinit(gpa);
25962681 gpa.destroy(embed_file);
25972682 }
25982683 zcu.embed_table.deinit(gpa);
......@@ -2610,9 +2695,10 @@ pub fn deinit(zcu: *Zcu) void {
26102695 zcu.failed_types.deinit(gpa);
26112696
26122697 for (zcu.failed_files.values()) |value| {
2613 if (value) |msg| msg.destroy(gpa);
2698 if (value) |msg| gpa.free(msg);
26142699 }
26152700 zcu.failed_files.deinit(gpa);
2701 zcu.failed_imports.deinit(gpa);
26162702
26172703 for (zcu.failed_exports.values()) |value| {
26182704 value.destroy(gpa);
......@@ -3407,27 +3493,21 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void
34073493 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
34083494}
34093495
3410pub const ImportFileResult = struct {
3411 file: *File,
3412 file_index: File.Index,
3496pub const ImportResult = struct {
3497 /// Whether `file` has been newly created; in other words, whether this is the first import of
3498 /// this file. This should only be `true` when importing files during AstGen. After that, all
3499 /// files should have already been discovered.
34133500 is_new: bool,
3414 is_pkg: bool,
3415};
34163501
3417pub fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8) Cache.BinDigest {
3418 const want_local_cache = mod == zcu.main_mod;
3419 var path_hash: Cache.HashHelper = .{};
3420 path_hash.addBytes(build_options.version);
3421 path_hash.add(builtin.zig_backend);
3422 if (!want_local_cache) {
3423 path_hash.addOptionalBytes(mod.root.root_dir.path);
3424 path_hash.addBytes(mod.root.sub_path);
3425 }
3426 path_hash.addBytes(sub_file_path);
3427 var bin: Cache.BinDigest = undefined;
3428 path_hash.hasher.final(&bin);
3429 return bin;
3430}
3502 /// `file.mod` is not populated by this function, so if `is_new`, then it is `undefined`.
3503 file: *Zcu.File,
3504 file_index: File.Index,
3505
3506 /// If this import was a simple file path, this is `null`; the imported file should exist within
3507 /// the importer's module. Otherwise, it's the module which the import resolved to. This module
3508 /// could match the module of `cur_file`, since a module can depend on itself.
3509 module: ?*Package.Module,
3510};
34313511
34323512/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
34333513/// this `AnalUnit` will cause them to be re-created (or not).
......@@ -3941,15 +4021,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
39414021
39424022 try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots.len);
39434023 for (zcu.analysis_roots.slice()) |mod| {
3944 // Logic ripped from `Zcu.PerThread.importPkg`.
3945 // TODO: this is silly, `Module` should just store a reference to its root `File`.
3946 const resolved_path = try std.fs.path.resolve(gpa, &.{
3947 mod.root.root_dir.path orelse ".",
3948 mod.root.sub_path,
3949 mod.root_src_path,
3950 });
3951 defer gpa.free(resolved_path);
3952 const file = zcu.import_table.get(resolved_path).?;
4024 const file = zcu.module_roots.get(mod).?.unwrap() orelse continue;
39534025 const root_ty = zcu.fileRootType(file);
39544026 if (root_ty == .none) continue;
39554027 type_queue.putAssumeCapacityNoClobber(root_ty, null);
......@@ -4229,8 +4301,8 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
42294301 .@"comptime" => |cu_id| {
42304302 const cu = ip.getComptimeUnit(cu_id);
42314303 if (cu.zir_index.resolveFull(ip)) |resolved| {
4232 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
4233 return writer.print("comptime(inst=('{s}', %{}) [{}])", .{ file_path, @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
4304 const file_path = zcu.fileByIndex(resolved.file).path;
4305 return writer.print("comptime(inst=('{}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
42344306 } else {
42354307 return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)});
42364308 }
......@@ -4254,8 +4326,8 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
42544326 const info = ti.resolveFull(ip) orelse {
42554327 return writer.writeAll("inst(<lost>)");
42564328 };
4257 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4258 return writer.print("inst('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) });
4329 const file_path = zcu.fileByIndex(info.file).path;
4330 return writer.print("inst('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
42594331 },
42604332 .nav_val => |nav| {
42614333 const fqn = ip.getNav(nav).fqn;
......@@ -4271,30 +4343,26 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
42714343 else => unreachable,
42724344 },
42734345 .zon_file => |file| {
4274 const file_path = zcu.fileByIndex(file).sub_file_path;
4275 return writer.print("zon_file('{s}')", .{file_path});
4346 const file_path = zcu.fileByIndex(file).path;
4347 return writer.print("zon_file('{}')", .{file_path.fmt(zcu.comp)});
42764348 },
42774349 .embed_file => |ef_idx| {
42784350 const ef = ef_idx.get(zcu);
4279 return writer.print("embed_file('{s}')", .{std.fs.path.fmtJoin(&.{
4280 ef.owner.root.root_dir.path orelse "",
4281 ef.owner.root.sub_path,
4282 ef.sub_file_path.toSlice(ip),
4283 })});
4351 return writer.print("embed_file('{}')", .{ef.path.fmt(zcu.comp)});
42844352 },
42854353 .namespace => |ti| {
42864354 const info = ti.resolveFull(ip) orelse {
42874355 return writer.writeAll("namespace(<lost>)");
42884356 };
4289 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4290 return writer.print("namespace('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) });
4357 const file_path = zcu.fileByIndex(info.file).path;
4358 return writer.print("namespace('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
42914359 },
42924360 .namespace_name => |k| {
42934361 const info = k.namespace.resolveFull(ip) orelse {
42944362 return writer.print("namespace(<lost>, '{}')", .{k.name.fmt(ip)});
42954363 };
4296 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4297 return writer.print("namespace('{s}', %{d}, '{}')", .{ file_path, @intFromEnum(info.inst), k.name.fmt(ip) });
4364 const file_path = zcu.fileByIndex(info.file).path;
4365 return writer.print("namespace('{}', %{d}, '{}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) });
42984366 },
42994367 .memoized_state => return writer.writeAll("memoized_state"),
43004368 }
......@@ -4511,3 +4579,114 @@ pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg)
45114579 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg);
45124580 return error.CodegenFail;
45134581}
4582
4583/// Asserts that `zcu.multi_module_err != null`.
4584pub fn addFileInMultipleModulesError(
4585 zcu: *Zcu,
4586 eb: *std.zig.ErrorBundle.Wip,
4587) !void {
4588 const gpa = zcu.gpa;
4589
4590 const info = zcu.multi_module_err.?;
4591 const file = info.file;
4592
4593 // error: file exists in modules 'root.foo' and 'root.bar'
4594 // note: files must belong to only one module
4595 // note: file is imported here
4596 // note: which is imported here
4597 // note: which is the root of module 'root.foo' imported here
4598 // note: file is the root of module 'root.bar' imported here
4599
4600 const file_src = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb);
4601 const root_msg = try eb.printString("file exists in modules '{s}' and '{s}'", .{
4602 info.modules[0].fully_qualified_name,
4603 info.modules[1].fully_qualified_name,
4604 });
4605
4606 var notes: std.ArrayListUnmanaged(std.zig.ErrorBundle.MessageIndex) = .empty;
4607 defer notes.deinit(gpa);
4608
4609 try notes.append(gpa, try eb.addErrorMessage(.{
4610 .msg = try eb.addString("files must belong to only one module"),
4611 .src_loc = file_src,
4612 }));
4613
4614 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[0], info.refs[0]);
4615 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[1], info.refs[1]);
4616
4617 try eb.addRootErrorMessage(.{
4618 .msg = root_msg,
4619 .src_loc = file_src,
4620 .notes_len = @intCast(notes.items.len),
4621 });
4622 const notes_start = try eb.reserveNotes(@intCast(notes.items.len));
4623 const notes_slice: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]);
4624 @memcpy(notes_slice, notes.items);
4625}
4626
4627fn explainWhyFileIsInModule(
4628 zcu: *Zcu,
4629 eb: *std.zig.ErrorBundle.Wip,
4630 notes_out: *std.ArrayListUnmanaged(std.zig.ErrorBundle.MessageIndex),
4631 file: File.Index,
4632 in_module: *Package.Module,
4633 ref: File.Reference,
4634) !void {
4635 const gpa = zcu.gpa;
4636
4637 // error: file is the root of module 'foo'
4638 //
4639 // error: file is imported here by the root of module 'foo'
4640 //
4641 // error: file is imported here
4642 // note: which is imported here
4643 // note: which is imported here by the root of module 'foo'
4644
4645 var import = switch (ref) {
4646 .analysis_root => |mod| {
4647 assert(mod == in_module);
4648 try notes_out.append(gpa, try eb.addErrorMessage(.{
4649 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}),
4650 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb),
4651 }));
4652 return;
4653 },
4654 .import => |import| if (import.module) |mod| {
4655 assert(mod == in_module);
4656 try notes_out.append(gpa, try eb.addErrorMessage(.{
4657 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}),
4658 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb),
4659 }));
4660 return;
4661 } else import,
4662 };
4663
4664 var is_first = true;
4665 while (true) {
4666 const thing: []const u8 = if (is_first) "file" else "which";
4667 is_first = false;
4668
4669 const import_src = try zcu.fileByIndex(import.importer).errorBundleTokenSrc(import.tok, zcu, eb);
4670
4671 const importer_ref = zcu.alive_files.get(import.importer).?;
4672 const importer_root: ?*Package.Module = switch (importer_ref) {
4673 .analysis_root => |mod| mod,
4674 .import => |i| i.module,
4675 };
4676
4677 if (importer_root) |m| {
4678 try notes_out.append(gpa, try eb.addErrorMessage(.{
4679 .msg = try eb.printString("{s} is imported here by the root of module '{s}'", .{ thing, m.fully_qualified_name }),
4680 .src_loc = import_src,
4681 }));
4682 return;
4683 }
4684
4685 try notes_out.append(gpa, try eb.addErrorMessage(.{
4686 .msg = try eb.printString("{s} is imported here", .{thing}),
4687 .src_loc = import_src,
4688 }));
4689
4690 import = importer_ref.import;
4691 }
4692}
src/Zcu/PerThread.zig+529-334
......@@ -8,23 +8,26 @@ const Ast = std.zig.Ast;
88const AstGen = std.zig.AstGen;
99const BigIntConst = std.math.big.int.Const;
1010const BigIntMutable = std.math.big.int.Mutable;
11const Builtin = @import("../Builtin.zig");
1112const build_options = @import("build_options");
1213const builtin = @import("builtin");
1314const Cache = std.Build.Cache;
1415const dev = @import("../dev.zig");
1516const InternPool = @import("../InternPool.zig");
1617const AnalUnit = InternPool.AnalUnit;
17const isUpDir = @import("../introspect.zig").isUpDir;
18const introspect = @import("../introspect.zig");
1819const Liveness = @import("../Liveness.zig");
1920const log = std.log.scoped(.zcu);
2021const Module = @import("../Package.zig").Module;
2122const Sema = @import("../Sema.zig");
2223const std = @import("std");
24const mem = std.mem;
2325const target_util = @import("../target.zig");
2426const trace = @import("../tracy.zig").trace;
2527const Type = @import("../Type.zig");
2628const Value = @import("../Value.zig");
2729const Zcu = @import("../Zcu.zig");
30const Compilation = @import("../Compilation.zig");
2831const Zir = std.zig.Zir;
2932const Zoir = std.zig.Zoir;
3033const ZonGen = std.zig.ZonGen;
......@@ -50,16 +53,9 @@ fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
5053 const zcu = pt.zcu;
5154 const gpa = zcu.gpa;
5255 const file = zcu.fileByIndex(file_index);
53 const is_builtin = file.mod.isBuiltin();
54 log.debug("deinit File {s}", .{file.sub_file_path});
55 if (is_builtin) {
56 file.unloadTree(gpa);
57 file.unloadZir(gpa);
58 } else {
59 gpa.free(file.sub_file_path);
60 file.unload(gpa);
61 }
62 file.references.deinit(gpa);
56 log.debug("deinit File {}", .{file.path.fmt(zcu.comp)});
57 file.path.deinit(gpa);
58 file.unload(gpa);
6359 if (file.prev_zir) |prev_zir| {
6460 prev_zir.deinit(gpa);
6561 gpa.destroy(prev_zir);
......@@ -70,20 +66,19 @@ fn deinitFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
7066pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
7167 const gpa = pt.zcu.gpa;
7268 const file = pt.zcu.fileByIndex(file_index);
73 const is_builtin = file.mod.isBuiltin();
7469 pt.deinitFile(file_index);
75 if (!is_builtin) gpa.destroy(file);
70 gpa.destroy(file);
7671}
7772
7873/// Ensures that `file` has up-to-date ZIR. If not, loads the ZIR cache or runs
79/// AstGen as needed. Also updates `file.status`.
74/// AstGen as needed. Also updates `file.status`. Does not assume that `file.mod`
75/// is populated. Does not return `error.AnalysisFail` on AstGen failures.
8076pub fn updateFile(
8177 pt: Zcu.PerThread,
78 file_index: Zcu.File.Index,
8279 file: *Zcu.File,
83 path_digest: Cache.BinDigest,
8480) !void {
8581 dev.check(.ast_gen);
86 assert(!file.mod.isBuiltin());
8782
8883 const tracy = trace(@src());
8984 defer tracy.end();
......@@ -93,13 +88,20 @@ pub fn updateFile(
9388 const gpa = zcu.gpa;
9489
9590 // In any case we need to examine the stat of the file to determine the course of action.
96 var source_file = try file.mod.root.openFile(file.sub_file_path, .{});
91 var source_file = f: {
92 const dir, const sub_path = file.path.openInfo(comp.dirs);
93 break :f try dir.openFile(sub_path, .{});
94 };
9795 defer source_file.close();
9896
9997 const stat = try source_file.stat();
10098
101 const want_local_cache = file.mod == zcu.main_mod;
102 const hex_digest = Cache.binToHex(path_digest);
99 const want_local_cache = switch (file.path.root) {
100 .none, .local_cache => true,
101 .global_cache, .zig_lib => false,
102 };
103
104 const hex_digest = Cache.binToHex(file.path.digest());
103105 const cache_directory = if (want_local_cache) zcu.local_zir_cache else zcu.global_zir_cache;
104106 const zir_dir = cache_directory.handle;
105107
......@@ -107,8 +109,8 @@ pub fn updateFile(
107109 var lock: std.fs.File.Lock = switch (file.status) {
108110 .never_loaded, .retryable_failure => lock: {
109111 // First, load the cached ZIR code, if any.
110 log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
111 file.sub_file_path, want_local_cache, &hex_digest,
112 log.debug("AstGen checking cache: {} (local={}, digest={s})", .{
113 file.path.fmt(comp), want_local_cache, &hex_digest,
112114 });
113115
114116 break :lock .shared;
......@@ -120,18 +122,18 @@ pub fn updateFile(
120122 stat.inode == file.stat.inode;
121123
122124 if (unchanged_metadata) {
123 log.debug("unmodified metadata of file: {s}", .{file.sub_file_path});
125 log.debug("unmodified metadata of file: {}", .{file.path.fmt(comp)});
124126 return;
125127 }
126128
127 log.debug("metadata changed: {s}", .{file.sub_file_path});
129 log.debug("metadata changed: {}", .{file.path.fmt(comp)});
128130
129131 break :lock .exclusive;
130132 },
131133 };
132134
133135 // The old compile error, if any, is no longer relevant.
134 pt.lockAndClearFileCompileError(file);
136 pt.lockAndClearFileCompileError(file_index, file);
135137
136138 // If `zir` is not null, and `prev_zir` is null, then `TrackedInst`s are associated with `zir`.
137139 // We need to keep it around!
......@@ -211,12 +213,12 @@ pub fn updateFile(
211213 };
212214 switch (result) {
213215 .success => {
214 log.debug("AstGen cached success: {s}", .{file.sub_file_path});
216 log.debug("AstGen cached success: {}", .{file.path.fmt(comp)});
215217 break false;
216218 },
217219 .invalid => {},
218 .truncated => log.warn("unexpected EOF reading cached ZIR for {s}", .{file.sub_file_path}),
219 .stale => log.debug("AstGen cache stale: {s}", .{file.sub_file_path}),
220 .truncated => log.warn("unexpected EOF reading cached ZIR for {}", .{file.path.fmt(comp)}),
221 .stale => log.debug("AstGen cache stale: {}", .{file.path.fmt(comp)}),
220222 }
221223
222224 // If we already have the exclusive lock then it is our job to update.
......@@ -255,22 +257,22 @@ pub fn updateFile(
255257 file.zir = try AstGen.generate(gpa, file.tree.?);
256258 Zcu.saveZirCache(gpa, cache_file, stat, file.zir.?) catch |err| switch (err) {
257259 error.OutOfMemory => |e| return e,
258 else => log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{
259 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
260 else => log.warn("unable to write cached ZIR code for {} to {}{s}: {s}", .{
261 file.path.fmt(comp), cache_directory, &hex_digest, @errorName(err),
260262 }),
261263 };
262264 },
263265 .zon => {
264266 file.zoir = try ZonGen.generate(gpa, file.tree.?, .{});
265267 Zcu.saveZoirCache(cache_file, stat, file.zoir.?) catch |err| {
266 log.warn("unable to write cached ZOIR code for {}{s} to {}{s}: {s}", .{
267 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
268 log.warn("unable to write cached ZOIR code for {} to {}{s}: {s}", .{
269 file.path.fmt(comp), cache_directory, &hex_digest, @errorName(err),
268270 });
269271 };
270272 },
271273 }
272274
273 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
275 log.debug("AstGen fresh success: {}", .{file.path.fmt(comp)});
274276 }
275277
276278 file.stat = .{
......@@ -287,7 +289,7 @@ pub fn updateFile(
287289 if (file.zir.?.hasCompileErrors()) {
288290 comp.mutex.lock();
289291 defer comp.mutex.unlock();
290 try zcu.failed_files.putNoClobber(gpa, file, null);
292 try zcu.failed_files.putNoClobber(gpa, file_index, null);
291293 }
292294 if (file.zir.?.loweringFailed()) {
293295 file.status = .astgen_failure;
......@@ -300,7 +302,7 @@ pub fn updateFile(
300302 file.status = .astgen_failure;
301303 comp.mutex.lock();
302304 defer comp.mutex.unlock();
303 try zcu.failed_files.putNoClobber(gpa, file, null);
305 try zcu.failed_files.putNoClobber(gpa, file_index, null);
304306 } else {
305307 file.status = .success;
306308 }
......@@ -310,8 +312,7 @@ pub fn updateFile(
310312 switch (file.status) {
311313 .never_loaded => unreachable,
312314 .retryable_failure => unreachable,
313 .astgen_failure => return error.AnalysisFail,
314 .success => return,
315 .astgen_failure, .success => {},
315316 }
316317}
317318
......@@ -388,9 +389,18 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
388389 var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .empty;
389390 defer cleanupUpdatedFiles(gpa, &updated_files);
390391
391 for (zcu.import_table.values()) |file_index| {
392 for (zcu.import_table.keys()) |file_index| {
393 if (!zcu.alive_files.contains(file_index)) continue;
392394 const file = zcu.fileByIndex(file_index);
393395 assert(file.status == .success);
396 if (file.module_changed) {
397 try updated_files.putNoClobber(gpa, file_index, .{
398 .file = file,
399 // We intentionally don't map any instructions here; that's the point, the whole file is outdated!
400 .inst_map = .{},
401 });
402 continue;
403 }
394404 switch (file.getMode()) {
395405 .zig => {}, // logic below
396406 .zon => {
......@@ -540,10 +550,12 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
540550 for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
541551 const file = updated_file.file;
542552
543 const prev_zir = file.prev_zir.?;
544 file.prev_zir = null;
545 prev_zir.deinit(gpa);
546 gpa.destroy(prev_zir);
553 if (file.prev_zir) |prev_zir| {
554 prev_zir.deinit(gpa);
555 gpa.destroy(prev_zir);
556 file.prev_zir = null;
557 }
558 file.module_changed = false;
547559
548560 // For every file which has changed, re-scan the namespace of the file's root struct type.
549561 // These types are special-cased because they don't have an enclosing declaration which will
......@@ -661,9 +673,9 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage)
661673 // * The type `std`, and its namespace
662674 // * The type `std.builtin`, and its namespace
663675 // * A semi-reasonable source location
664 const std_file_imported = pt.importPkg(zcu.std_mod) catch return error.AnalysisFail;
665 try pt.ensureFileAnalyzed(std_file_imported.file_index);
666 const std_type: Type = .fromInterned(zcu.fileRootType(std_file_imported.file_index));
676 const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?;
677 try pt.ensureFileAnalyzed(std_file_index);
678 const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index));
667679 const std_namespace = std_type.getNamespaceIndex(zcu);
668680 try pt.ensureNamespaceUpToDate(std_namespace);
669681 const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
......@@ -675,7 +687,7 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage)
675687 try pt.ensureNamespaceUpToDate(builtin_namespace);
676688 const src: Zcu.LazySrcLoc = .{
677689 .base_node_inst = builtin_type.typeDeclInst(zcu).?,
678 .offset = .entire_file,
690 .offset = .{ .byte_abs = 0 },
679691 };
680692
681693 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
......@@ -1250,7 +1262,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12501262
12511263 if (!try nav_ty.hasRuntimeBitsSema(pt)) {
12521264 if (zcu.comp.config.use_llvm) break :queue_codegen;
1253 if (file.mod.strip) break :queue_codegen;
1265 if (file.mod.?.strip) break :queue_codegen;
12541266 }
12551267
12561268 // This job depends on any resolve_type_fully jobs queued up before it.
......@@ -1730,13 +1742,12 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: Ai
17301742 }
17311743}
17321744
1733/// https://github.com/ziglang/zig/issues/14307
1734pub fn semaPkg(pt: Zcu.PerThread, pkg: *Module) !void {
1745pub fn semaMod(pt: Zcu.PerThread, mod: *Module) !void {
17351746 dev.check(.sema);
1736 const import_file_result = try pt.importPkg(pkg);
1737 const root_type = pt.zcu.fileRootType(import_file_result.file_index);
1747 const file_index = pt.zcu.module_roots.get(mod).?.unwrap().?;
1748 const root_type = pt.zcu.fileRootType(file_index);
17381749 if (root_type == .none) {
1739 return pt.semaFile(import_file_result.file_index);
1750 return pt.semaFile(file_index);
17401751 }
17411752}
17421753
......@@ -1808,7 +1819,7 @@ fn createFileRootStruct(
18081819 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
18091820 codegen_type: {
18101821 if (zcu.comp.config.use_llvm) break :codegen_type;
1811 if (file.mod.strip) break :codegen_type;
1822 if (file.mod.?.strip) break :codegen_type;
18121823 // This job depends on any resolve_type_fully jobs queued up before it.
18131824 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
18141825 }
......@@ -1829,7 +1840,7 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
18291840 if (file_root_type == .none) return;
18301841
18311842 log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{
1832 file.mod.fully_qualified_name,
1843 file.mod.?.fully_qualified_name,
18331844 file.sub_file_path,
18341845 });
18351846
......@@ -1872,211 +1883,464 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
18721883 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
18731884}
18741885
1875pub fn importPkg(pt: Zcu.PerThread, mod: *Module) Allocator.Error!Zcu.ImportFileResult {
1886/// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is
1887/// then responsible for queueing a new AstGen job for the new file.
1888/// Assumes that `comp.mutex` is NOT locked. It will be locked by this function where necessary.
1889pub fn discoverImport(
1890 pt: Zcu.PerThread,
1891 importer_path: Compilation.Path,
1892 import_string: []const u8,
1893) Allocator.Error!union(enum) {
1894 module,
1895 existing_file: Zcu.File.Index,
1896 new_file: struct {
1897 index: Zcu.File.Index,
1898 file: *Zcu.File,
1899 },
1900} {
18761901 const zcu = pt.zcu;
18771902 const gpa = zcu.gpa;
18781903
1879 // The resolved path is used as the key in the import table, to detect if
1880 // an import refers to the same as another, despite different relative paths
1881 // or differently mapped package names.
1882 const resolved_path = try std.fs.path.resolve(gpa, &.{
1883 mod.root.root_dir.path orelse ".",
1884 mod.root.sub_path,
1885 mod.root_src_path,
1886 });
1887 var keep_resolved_path = false;
1888 defer if (!keep_resolved_path) gpa.free(resolved_path);
1904 if (!mem.endsWith(u8, import_string, ".zig") and !mem.endsWith(u8, import_string, ".zon")) {
1905 return .module;
1906 }
18891907
1890 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
1908 const new_path = try importer_path.upJoin(gpa, zcu.comp.dirs, import_string);
1909 errdefer new_path.deinit(gpa);
1910
1911 // We're about to do a GOP on `import_table`, so we need the mutex.
1912 zcu.comp.mutex.lock();
1913 defer zcu.comp.mutex.unlock();
1914
1915 const gop = try zcu.import_table.getOrPutAdapted(gpa, new_path, Zcu.ImportTableAdapter{ .zcu = zcu });
18911916 errdefer _ = zcu.import_table.pop();
18921917 if (gop.found_existing) {
1893 const file_index = gop.value_ptr.*;
1894 const file = zcu.fileByIndex(file_index);
1895 try file.addReference(zcu, .{ .root = mod });
1896 return .{
1897 .file = file,
1898 .file_index = file_index,
1899 .is_new = false,
1900 .is_pkg = true,
1901 };
1902 }
1903
1904 const ip = &zcu.intern_pool;
1905 if (mod.builtin_file) |builtin_file| {
1906 const path_digest = Zcu.computePathDigest(zcu, mod, builtin_file.sub_file_path);
1907 const file_index = try ip.createFile(gpa, pt.tid, .{
1908 .bin_digest = path_digest,
1909 .file = builtin_file,
1910 .root_type = .none,
1911 });
1912 keep_resolved_path = true; // It's now owned by import_table.
1913 gop.value_ptr.* = file_index;
1914 try builtin_file.addReference(zcu, .{ .root = mod });
1915 return .{
1916 .file = builtin_file,
1917 .file_index = file_index,
1918 .is_new = false,
1919 .is_pkg = true,
1920 };
1918 new_path.deinit(gpa); // we didn't need it for `File.path`
1919 return .{ .existing_file = gop.key_ptr.* };
19211920 }
19221921
1923 const sub_file_path = try gpa.dupe(u8, mod.root_src_path);
1924 errdefer gpa.free(sub_file_path);
1925
1926 const comp = zcu.comp;
1927 if (comp.file_system_inputs) |fsi|
1928 try comp.appendFileSystemInput(fsi, mod.root, sub_file_path);
1922 zcu.import_table.lockPointers();
1923 defer zcu.import_table.unlockPointers();
19291924
19301925 const new_file = try gpa.create(Zcu.File);
19311926 errdefer gpa.destroy(new_file);
19321927
1933 const path_digest = zcu.computePathDigest(mod, sub_file_path);
1934 const new_file_index = try ip.createFile(gpa, pt.tid, .{
1935 .bin_digest = path_digest,
1928 const new_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
1929 .bin_digest = new_path.digest(),
19361930 .file = new_file,
19371931 .root_type = .none,
19381932 });
1939 keep_resolved_path = true; // It's now owned by import_table.
1940 gop.value_ptr.* = new_file_index;
1933 errdefer comptime unreachable; // because we don't remove the file from the internpool
1934
1935 gop.key_ptr.* = new_file_index;
19411936 new_file.* = .{
1942 .sub_file_path = sub_file_path,
1937 .status = .never_loaded,
1938 .path = new_path,
19431939 .stat = undefined,
1940 .is_builtin = false,
19441941 .source = null,
19451942 .tree = null,
19461943 .zir = null,
19471944 .zoir = null,
1948 .status = .never_loaded,
1949 .mod = mod,
1945 .mod = null,
1946 .sub_file_path = undefined,
1947 .module_changed = false,
1948 .prev_zir = null,
1949 .zoir_invalidated = false,
19501950 };
19511951
1952 try new_file.addReference(zcu, .{ .root = mod });
1953 return .{
1952 return .{ .new_file = .{
1953 .index = new_file_index,
19541954 .file = new_file,
1955 .file_index = new_file_index,
1956 .is_new = true,
1957 .is_pkg = true,
1958 };
1955 } };
19591956}
19601957
1961/// Called from a worker thread during AstGen (with the Compilation mutex held).
1962/// Also called from Sema during semantic analysis.
1963/// Does not attempt to load the file from disk; just returns a corresponding `*Zcu.File`.
1964pub fn importFile(
1958pub fn doImport(
19651959 pt: Zcu.PerThread,
1966 cur_file: *Zcu.File,
1960 /// This file must have its `mod` populated.
1961 importer: *Zcu.File,
19671962 import_string: []const u8,
19681963) error{
19691964 OutOfMemory,
19701965 ModuleNotFound,
1971 ImportOutsideModulePath,
1972 CurrentWorkingDirectoryUnlinked,
1973}!Zcu.ImportFileResult {
1966 IllegalZigImport,
1967}!struct {
1968 file: Zcu.File.Index,
1969 module_root: ?*Module,
1970} {
19741971 const zcu = pt.zcu;
1975 const mod = cur_file.mod;
1976
1977 if (std.mem.eql(u8, import_string, "std")) {
1978 return pt.importPkg(zcu.std_mod);
1979 }
1980 if (std.mem.eql(u8, import_string, "root")) {
1981 return pt.importPkg(zcu.root_mod);
1982 }
1983 if (mod.deps.get(import_string)) |pkg| {
1984 return pt.importPkg(pkg);
1972 const gpa = zcu.gpa;
1973 const imported_mod: ?*Module = m: {
1974 if (mem.eql(u8, import_string, "std")) break :m zcu.std_mod;
1975 if (mem.eql(u8, import_string, "root")) break :m zcu.root_mod;
1976 if (mem.eql(u8, import_string, "builtin")) {
1977 const opts = importer.mod.?.getBuiltinOptions(zcu.comp.config);
1978 break :m zcu.builtin_modules.get(opts.hash()).?;
1979 }
1980 break :m importer.mod.?.deps.get(import_string);
1981 };
1982 if (imported_mod) |mod| {
1983 if (zcu.module_roots.get(mod).?.unwrap()) |file_index| {
1984 return .{
1985 .file = file_index,
1986 .module_root = mod,
1987 };
1988 }
19851989 }
19861990 if (!std.mem.endsWith(u8, import_string, ".zig") and
19871991 !std.mem.endsWith(u8, import_string, ".zon"))
19881992 {
19891993 return error.ModuleNotFound;
19901994 }
1995 const path = try importer.path.upJoin(gpa, zcu.comp.dirs, import_string);
1996 defer path.deinit(gpa);
1997 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {
1998 return error.IllegalZigImport;
1999 }
2000 return .{
2001 .file = zcu.import_table.getKeyAdapted(path, Zcu.ImportTableAdapter{ .zcu = zcu }).?,
2002 .module_root = null,
2003 };
2004}
2005/// This is called once during `Compilation.create` and never again. "builtin" modules don't yet
2006/// exist, so are not added to `module_roots` here. They must be added when they are created.
2007pub fn populateModuleRootTable(pt: Zcu.PerThread) error{
2008 OutOfMemory,
2009 /// One of the specified modules had its root source file at an illegal path.
2010 IllegalZigImport,
2011}!void {
2012 const zcu = pt.zcu;
19912013 const gpa = zcu.gpa;
19922014
1993 // The resolved path is used as the key in the import table, to detect if
1994 // an import refers to the same as another, despite different relative paths
1995 // or differently mapped package names.
1996 const resolved_path = try std.fs.path.resolve(gpa, &.{
1997 mod.root.root_dir.path orelse ".",
1998 mod.root.sub_path,
1999 cur_file.sub_file_path,
2000 "..",
2001 import_string,
2002 });
2015 // We'll initially add [mod, undefined] pairs, and when we reach the pair while
2016 // iterating, rewrite the undefined value.
2017 const roots = &zcu.module_roots;
2018 roots.clearRetainingCapacity();
2019
2020 // Start with:
2021 // * `std_mod`, which is the main root of analysis
2022 // * `root_mod`, which is `@import("root")`
2023 // * `main_mod`, which is a special analysis root in tests (and otherwise equal to `root_mod`)
2024 // All other modules will be found by traversing their dependency tables.
2025 try roots.ensureTotalCapacity(gpa, 3);
2026 roots.putAssumeCapacity(zcu.std_mod, undefined);
2027 roots.putAssumeCapacity(zcu.root_mod, undefined);
2028 roots.putAssumeCapacity(zcu.main_mod, undefined);
2029 var i: usize = 0;
2030 while (i < roots.count()) {
2031 const mod = roots.keys()[i];
2032 try roots.ensureUnusedCapacity(gpa, mod.deps.count());
2033 for (mod.deps.values()) |dep| {
2034 const gop = roots.getOrPutAssumeCapacity(dep);
2035 _ = gop; // we want to leave the value undefined if it was added
2036 }
20032037
2004 var keep_resolved_path = false;
2005 defer if (!keep_resolved_path) gpa.free(resolved_path);
2038 const root_file_out = &roots.values()[i];
2039 roots.lockPointers();
2040 defer roots.unlockPointers();
20062041
2007 const gop = try zcu.import_table.getOrPut(gpa, resolved_path);
2008 errdefer _ = zcu.import_table.pop();
2009 if (gop.found_existing) {
2010 const file_index = gop.value_ptr.*;
2011 return .{
2012 .file = zcu.fileByIndex(file_index),
2013 .file_index = file_index,
2014 .is_new = false,
2015 .is_pkg = false,
2042 i += 1;
2043
2044 if (Zcu.File.modeFromPath(mod.root_src_path) == null) {
2045 root_file_out.* = .none;
2046 continue;
2047 }
2048
2049 const path = try mod.root.join(gpa, zcu.comp.dirs, mod.root_src_path);
2050 errdefer path.deinit(gpa);
2051
2052 if (try path.isIllegalZigImport(gpa, zcu.comp.dirs)) {
2053 return error.IllegalZigImport;
2054 }
2055
2056 const gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu });
2057 errdefer _ = zcu.import_table.pop();
2058
2059 if (gop.found_existing) {
2060 path.deinit(gpa);
2061 root_file_out.* = gop.key_ptr.*.toOptional();
2062 continue;
2063 }
2064
2065 zcu.import_table.lockPointers();
2066 defer zcu.import_table.unlockPointers();
2067
2068 const new_file = try gpa.create(Zcu.File);
2069 errdefer gpa.destroy(new_file);
2070
2071 const new_file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
2072 .bin_digest = path.digest(),
2073 .file = new_file,
2074 .root_type = .none,
2075 });
2076 errdefer comptime unreachable; // because we don't remove the file from the internpool
2077
2078 gop.key_ptr.* = new_file_index;
2079 root_file_out.* = new_file_index.toOptional();
2080 new_file.* = .{
2081 .status = .never_loaded,
2082 .path = path,
2083 .stat = undefined,
2084 .is_builtin = false,
2085 .source = null,
2086 .tree = null,
2087 .zir = null,
2088 .zoir = null,
2089 .mod = null,
2090 .sub_file_path = undefined,
2091 .module_changed = false,
2092 .prev_zir = null,
2093 .zoir_invalidated = false,
20162094 };
20172095 }
2096}
20182097
2019 const ip = &zcu.intern_pool;
2098/// Clears and re-populates `pt.zcu.alive_files`, and determines the module identity of every alive
2099/// file. If a file's module changes, its `module_changed` flag is set for `updateZirRefs` to see.
2100/// Also clears and re-populates `failed_imports` and `multi_module_err` based on the set of alive
2101/// files.
2102///
2103/// Live files are also added as file system inputs if necessary.
2104///
2105/// Returns whether there is any live file which is failed. Howewver, this function does *not*
2106/// modify `pt.zcu.skip_analysis_this_update`.
2107///
2108/// If an error is returned, `pt.zcu.alive_files` might contain undefined values.
2109pub fn computeAliveFiles(pt: Zcu.PerThread) Allocator.Error!bool {
2110 const zcu = pt.zcu;
2111 const comp = zcu.comp;
2112 const gpa = zcu.gpa;
20202113
2021 const new_file = try gpa.create(Zcu.File);
2022 errdefer gpa.destroy(new_file);
2114 var any_fatal_files = false;
2115 zcu.multi_module_err = null;
2116 zcu.failed_imports.clearRetainingCapacity();
2117 zcu.alive_files.clearRetainingCapacity();
2118
2119 // This function will iterate the keys of `alive_files`, adding new entries as it discovers
2120 // imports. Once a file is in `alive_files`, it has its `mod` field up-to-date. If conflicting
2121 // imports are discovered for a file, we will set `multi_module_err`. Crucially, this traversal
2122 // is single-threaded, and depends only on the order of the imports map from AstGen, which makes
2123 // its behavior (in terms of which multi module errors are discovered) entirely consistent in a
2124 // multi-threaded environment (where things like file indices could differ between compiler runs).
2125
2126 // The roots of our file liveness analysis will be the analysis roots.
2127 try zcu.alive_files.ensureTotalCapacity(gpa, zcu.analysis_roots.len);
2128 for (zcu.analysis_roots.slice()) |mod| {
2129 const file_index = zcu.module_roots.get(mod).?.unwrap() orelse continue;
2130 const file = zcu.fileByIndex(file_index);
20232131
2024 const resolved_root_path = try std.fs.path.resolve(gpa, &.{
2025 mod.root.root_dir.path orelse ".",
2026 mod.root.sub_path,
2027 });
2028 defer gpa.free(resolved_root_path);
2132 file.mod = mod;
2133 file.sub_file_path = mod.root_src_path;
20292134
2030 const sub_file_path = p: {
2031 const relative = std.fs.path.relative(gpa, resolved_root_path, resolved_path) catch |err| switch (err) {
2032 error.Unexpected => unreachable,
2033 else => |e| return e,
2034 };
2035 errdefer gpa.free(relative);
2135 zcu.alive_files.putAssumeCapacityNoClobber(file_index, .{ .analysis_root = mod });
2136 }
2137
2138 var live_check_idx: usize = 0;
2139 while (live_check_idx < zcu.alive_files.count()) {
2140 const file_idx = zcu.alive_files.keys()[live_check_idx];
2141 const file = zcu.fileByIndex(file_idx);
2142 live_check_idx += 1;
20362143
2037 if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
2038 break :p relative;
2144 switch (file.status) {
2145 .never_loaded => unreachable, // everything reachable is loaded by the AstGen workers
2146 .retryable_failure, .astgen_failure => any_fatal_files = true,
2147 .success => {},
20392148 }
2040 return error.ImportOutsideModulePath;
2041 };
2042 errdefer gpa.free(sub_file_path);
20432149
2044 log.debug("new importFile. resolved_root_path={s}, resolved_path={s}, sub_file_path={s}, import_string={s}", .{
2045 resolved_root_path, resolved_path, sub_file_path, import_string,
2046 });
2150 try comp.appendFileSystemInput(file.path);
2151
2152 switch (file.getMode()) {
2153 .zig => {}, // continue to logic below
2154 .zon => continue, // ZON can't import anything
2155 }
2156
2157 if (file.status != .success) continue; // ZIR not valid if there was a file failure
2158
2159 const zir = file.zir.?;
2160 const imports_index = zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
2161 if (imports_index == 0) continue; // this Zig file has no imports
2162 const extra = zir.extraData(Zir.Inst.Imports, imports_index);
2163 var extra_index = extra.end;
2164 try zcu.alive_files.ensureUnusedCapacity(gpa, extra.data.imports_len);
2165 for (0..extra.data.imports_len) |_| {
2166 const item = zir.extraData(Zir.Inst.Imports.Item, extra_index);
2167 extra_index = item.end;
2168 const import_path = zir.nullTerminatedString(item.data.name);
2169
2170 if (std.mem.eql(u8, import_path, "builtin")) {
2171 // We've not necessarily generated builtin modules yet, so `doImport` could fail. Instead,
2172 // create the module here. Then, since we know that `builtin.zig` doesn't have an error and
2173 // has no imports other than 'std', we can just continue onto the next import.
2174 try pt.updateBuiltinModule(file.mod.?.getBuiltinOptions(comp.config));
2175 continue;
2176 }
2177
2178 const res = pt.doImport(file, import_path) catch |err| switch (err) {
2179 error.OutOfMemory => |e| return e,
2180 error.ModuleNotFound => {
2181 // It'd be nice if this were a file-level error, but allowing this turns out to
2182 // be quite important in practice, e.g. for optional dependencies whose import
2183 // is behind a comptime condition. So, the error here happens in `Sema` instead.
2184 continue;
2185 },
2186 error.IllegalZigImport => {
2187 try zcu.failed_imports.append(gpa, .{
2188 .file_index = file_idx,
2189 .import_string = item.data.name,
2190 .import_token = item.data.token,
2191 .kind = .illegal_zig_import,
2192 });
2193 continue;
2194 },
2195 };
2196
2197 // If the import was not of a module, we propagate our own module.
2198 const imported_mod = res.module_root orelse file.mod.?;
2199 const imported_file = zcu.fileByIndex(res.file);
2200
2201 const imported_ref: Zcu.File.Reference = .{ .import = .{
2202 .importer = file_idx,
2203 .tok = item.data.token,
2204 .module = res.module_root,
2205 } };
2206
2207 const gop = zcu.alive_files.getOrPutAssumeCapacity(res.file);
2208 if (gop.found_existing) {
2209 // This means `imported_file.mod` is already populated. If it doesn't match
2210 // `imported_mod`, then this file exists in multiple modules.
2211 if (imported_file.mod.? != imported_mod) {
2212 // We only report the first multi-module error we see. Thanks to this traversal
2213 // being deterministic, this doesn't raise consistency issues. Moreover, it's a
2214 // useful behavior; we know that this error can be reached *without* realising
2215 // that any other files are multi-module, so it's probably approximately where
2216 // the problem "begins". Any compilation with a multi-module file is likely to
2217 // have a huge number of them by transitive imports, so just reporting this one
2218 // hopefully keeps the error focused.
2219 zcu.multi_module_err = .{
2220 .file = file_idx,
2221 .modules = .{ imported_file.mod.?, imported_mod },
2222 .refs = .{ gop.value_ptr.*, imported_ref },
2223 };
2224 // If we discover a multi-module error, it's the only error which matters, and we
2225 // can't discern any useful information about the file's own imports; so just do
2226 // an early exit now we've populated `zcu.multi_module_err`.
2227 return any_fatal_files;
2228 }
2229 continue;
2230 }
2231 // We're the first thing we've found referencing `res.file`.
2232 gop.value_ptr.* = imported_ref;
2233 if (imported_file.mod) |m| {
2234 if (m == imported_mod) {
2235 // Great, the module and sub path are already populated correctly.
2236 continue;
2237 }
2238 }
2239 // We need to set the file's module, meaning we also need to compute its sub path.
2240 // This string is externally managed and has a lifetime at least equal to the
2241 // lifetime of `imported_file`. `null` means the file is outside its module root.
2242 switch (imported_file.path.isNested(imported_mod.root)) {
2243 .yes => |sub_path| {
2244 if (imported_file.mod != null) {
2245 // There was a module from a previous update; instruct `updateZirRefs` to
2246 // invalidate everything.
2247 imported_file.module_changed = true;
2248 }
2249 imported_file.mod = imported_mod;
2250 imported_file.sub_file_path = sub_path;
2251 },
2252 .different_roots, .no => {
2253 try zcu.failed_imports.append(gpa, .{
2254 .file_index = file_idx,
2255 .import_string = item.data.name,
2256 .import_token = item.data.token,
2257 .kind = .file_outside_module_root,
2258 });
2259 _ = zcu.alive_files.pop(); // we failed to populate `mod`/`sub_file_path`
2260 },
2261 }
2262 }
2263 }
20472264
2265 return any_fatal_files;
2266}
2267
2268/// Ensures that the `@import("builtin")` module corresponding to `opts` is available in
2269/// `builtin_modules`, and that its file is populated. Also ensures the file on disk is
2270/// up-to-date, setting a misc failure if updating it fails.
2271/// Asserts that the imported `builtin.zig` has no ZIR errors, and that it has only one
2272/// import, which is 'std'.
2273pub fn updateBuiltinModule(pt: Zcu.PerThread, opts: Builtin) Allocator.Error!void {
2274 const zcu = pt.zcu;
20482275 const comp = zcu.comp;
2049 if (comp.file_system_inputs) |fsi|
2050 try comp.appendFileSystemInput(fsi, mod.root, sub_file_path);
2276 const gpa = zcu.gpa;
20512277
2052 const path_digest = zcu.computePathDigest(mod, sub_file_path);
2053 const new_file_index = try ip.createFile(gpa, pt.tid, .{
2054 .bin_digest = path_digest,
2055 .file = new_file,
2056 .root_type = .none,
2057 });
2058 keep_resolved_path = true; // It's now owned by import_table.
2059 gop.value_ptr.* = new_file_index;
2060 new_file.* = .{
2061 .sub_file_path = sub_file_path,
2278 const gop = try zcu.builtin_modules.getOrPut(gpa, opts.hash());
2279 if (gop.found_existing) return; // the `File` is up-to-date
2280 errdefer _ = zcu.builtin_modules.pop();
2281
2282 const mod: *Module = try .createBuiltin(comp.arena, opts, comp.dirs);
2283 assert(std.mem.eql(u8, &mod.getBuiltinOptions(comp.config).hash(), gop.key_ptr)); // builtin is its own builtin
2284
2285 const path = try mod.root.join(gpa, comp.dirs, "builtin.zig");
2286 errdefer path.deinit(gpa);
20622287
2288 const file_gop = try zcu.import_table.getOrPutAdapted(gpa, path, Zcu.ImportTableAdapter{ .zcu = zcu });
2289 // `Compilation.Path.isIllegalZigImport` checks guard file creation, so
2290 // there isn't an `import_table` entry for this path yet.
2291 assert(!file_gop.found_existing);
2292 errdefer _ = zcu.import_table.pop();
2293
2294 try zcu.module_roots.ensureUnusedCapacity(gpa, 1);
2295
2296 const file = try gpa.create(Zcu.File);
2297 errdefer gpa.destroy(file);
2298
2299 file.* = .{
20632300 .status = .never_loaded,
20642301 .stat = undefined,
2065
2302 .path = path,
2303 .is_builtin = true,
20662304 .source = null,
20672305 .tree = null,
20682306 .zir = null,
20692307 .zoir = null,
2070
20712308 .mod = mod,
2309 .sub_file_path = "builtin.zig",
2310 .module_changed = false,
2311 .prev_zir = null,
2312 .zoir_invalidated = false,
20722313 };
20732314
2074 return .{
2075 .file = new_file,
2076 .file_index = new_file_index,
2077 .is_new = true,
2078 .is_pkg = false,
2079 };
2315 const file_index = try zcu.intern_pool.createFile(gpa, pt.tid, .{
2316 .bin_digest = path.digest(),
2317 .file = file,
2318 .root_type = .none,
2319 });
2320
2321 gop.value_ptr.* = mod;
2322 file_gop.key_ptr.* = file_index;
2323 zcu.module_roots.putAssumeCapacityNoClobber(mod, file_index.toOptional());
2324 try opts.populateFile(gpa, file);
2325
2326 assert(file.status == .success);
2327 assert(!file.zir.?.hasCompileErrors());
2328 {
2329 // Check that it has only one import, which is 'std'.
2330 const imports_idx = file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
2331 assert(imports_idx != 0); // there is an import
2332 const extra = file.zir.?.extraData(Zir.Inst.Imports, imports_idx);
2333 assert(extra.data.imports_len == 1); // there is exactly one import
2334 const item = file.zir.?.extraData(Zir.Inst.Imports.Item, extra.end);
2335 const import_path = file.zir.?.nullTerminatedString(item.data.name);
2336 assert(mem.eql(u8, import_path, "std")); // the single import is of 'std'
2337 }
2338
2339 Builtin.updateFileOnDisk(file, comp) catch |err| comp.setMiscFailure(
2340 .write_builtin_zig,
2341 "unable to write '{}': {s}",
2342 .{ file.path.fmt(comp), @errorName(err) },
2343 );
20802344}
20812345
20822346pub fn embedFile(
......@@ -2091,63 +2355,49 @@ pub fn embedFile(
20912355 const zcu = pt.zcu;
20922356 const gpa = zcu.gpa;
20932357
2094 if (cur_file.mod.deps.get(import_string)) |mod| {
2095 const resolved_path = try std.fs.path.resolve(gpa, &.{
2096 mod.root.root_dir.path orelse ".",
2097 mod.root.sub_path,
2098 mod.root_src_path,
2099 });
2100 errdefer gpa.free(resolved_path);
2101
2102 const gop = try zcu.embed_table.getOrPut(gpa, resolved_path);
2103 errdefer assert(std.mem.eql(u8, zcu.embed_table.pop().?.key, resolved_path));
2358 const opt_mod: ?*Module = m: {
2359 if (mem.eql(u8, import_string, "std")) break :m zcu.std_mod;
2360 if (mem.eql(u8, import_string, "root")) break :m zcu.root_mod;
2361 if (mem.eql(u8, import_string, "builtin")) {
2362 const opts = cur_file.mod.?.getBuiltinOptions(zcu.comp.config);
2363 break :m zcu.builtin_modules.get(opts.hash()).?;
2364 }
2365 break :m cur_file.mod.?.deps.get(import_string);
2366 };
2367 if (opt_mod) |mod| {
2368 const path = try mod.root.join(gpa, zcu.comp.dirs, mod.root_src_path);
2369 errdefer path.deinit(gpa);
21042370
2371 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});
21052372 if (gop.found_existing) {
2106 gpa.free(resolved_path); // we're not using this key
2373 path.deinit(gpa); // we're not using this key
21072374 return @enumFromInt(gop.index);
21082375 }
2109
2110 gop.value_ptr.* = try pt.newEmbedFile(mod, mod.root_src_path, resolved_path);
2376 errdefer _ = zcu.embed_table.pop();
2377 gop.key_ptr.* = try pt.newEmbedFile(path);
21112378 return @enumFromInt(gop.index);
21122379 }
21132380
2114 // The resolved path is used as the key in the table, to detect if a file
2115 // refers to the same as another, despite different relative paths.
2116 const resolved_path = try std.fs.path.resolve(gpa, &.{
2117 cur_file.mod.root.root_dir.path orelse ".",
2118 cur_file.mod.root.sub_path,
2119 cur_file.sub_file_path,
2120 "..",
2121 import_string,
2122 });
2123 errdefer gpa.free(resolved_path);
2124
2125 const gop = try zcu.embed_table.getOrPut(gpa, resolved_path);
2126 errdefer assert(std.mem.eql(u8, zcu.embed_table.pop().?.key, resolved_path));
2127
2128 if (gop.found_existing) {
2129 gpa.free(resolved_path); // we're not using this key
2130 return @enumFromInt(gop.index);
2131 }
2132
2133 const resolved_root_path = try std.fs.path.resolve(gpa, &.{
2134 cur_file.mod.root.root_dir.path orelse ".",
2135 cur_file.mod.root.sub_path,
2136 });
2137 defer gpa.free(resolved_root_path);
2138
2139 const sub_file_path = std.fs.path.relative(gpa, resolved_root_path, resolved_path) catch |err| switch (err) {
2140 error.Unexpected => unreachable,
2141 else => |e| return e,
2381 const embed_file: *Zcu.EmbedFile, const embed_file_idx: Zcu.EmbedFile.Index = ef: {
2382 const path = try cur_file.path.upJoin(gpa, zcu.comp.dirs, import_string);
2383 errdefer path.deinit(gpa);
2384 const gop = try zcu.embed_table.getOrPutAdapted(gpa, path, Zcu.EmbedTableAdapter{});
2385 if (gop.found_existing) {
2386 path.deinit(gpa); // we're not using this key
2387 break :ef .{ gop.key_ptr.*, @enumFromInt(gop.index) };
2388 } else {
2389 errdefer _ = zcu.embed_table.pop();
2390 gop.key_ptr.* = try pt.newEmbedFile(path);
2391 break :ef .{ gop.key_ptr.*, @enumFromInt(gop.index) };
2392 }
21422393 };
2143 defer gpa.free(sub_file_path);
21442394
2145 if (isUpDir(sub_file_path) or std.fs.path.isAbsolute(sub_file_path)) {
2146 return error.ImportOutsideModulePath;
2395 switch (embed_file.path.isNested(cur_file.mod.?.root)) {
2396 .yes => {},
2397 .different_roots, .no => return error.ImportOutsideModulePath,
21472398 }
21482399
2149 gop.value_ptr.* = try pt.newEmbedFile(cur_file.mod, sub_file_path, resolved_path);
2150 return @enumFromInt(gop.index);
2400 return embed_file_idx;
21512401}
21522402
21532403pub fn updateEmbedFile(
......@@ -2177,7 +2427,10 @@ fn updateEmbedFileInner(
21772427 const gpa = zcu.gpa;
21782428 const ip = &zcu.intern_pool;
21792429
2180 var file = try ef.owner.root.openFile(ef.sub_file_path.toSlice(ip), .{});
2430 var file = f: {
2431 const dir, const sub_path = ef.path.openInfo(zcu.comp.dirs);
2432 break :f try dir.openFile(sub_path, .{});
2433 };
21812434 defer file.close();
21822435
21832436 const stat: Cache.File.Stat = .fromFs(try file.stat());
......@@ -2232,28 +2485,21 @@ fn updateEmbedFileInner(
22322485 ef.stat = stat;
22332486}
22342487
2488/// Assumes that `path` is allocated into `gpa`. Takes ownership of `path` on success.
22352489fn newEmbedFile(
22362490 pt: Zcu.PerThread,
2237 mod: *Module,
2238 /// The path of the file to embed relative to the root of `mod`.
2239 sub_file_path: []const u8,
2240 /// The resolved path of the file to embed.
2241 resolved_path: []const u8,
2491 path: Compilation.Path,
22422492) !*Zcu.EmbedFile {
22432493 const zcu = pt.zcu;
22442494 const comp = zcu.comp;
22452495 const gpa = zcu.gpa;
22462496 const ip = &zcu.intern_pool;
22472497
2248 if (comp.file_system_inputs) |fsi|
2249 try comp.appendFileSystemInput(fsi, mod.root, sub_file_path);
2250
22512498 const new_file = try gpa.create(Zcu.EmbedFile);
22522499 errdefer gpa.destroy(new_file);
22532500
22542501 new_file.* = .{
2255 .owner = mod,
2256 .sub_file_path = try ip.getOrPutString(gpa, pt.tid, sub_file_path, .no_embedded_nulls),
2502 .path = path,
22572503 .val = .none,
22582504 .err = null,
22592505 .stat = undefined,
......@@ -2262,6 +2508,8 @@ fn newEmbedFile(
22622508 var opt_ip_str: ?InternPool.String = null;
22632509 try pt.updateEmbedFile(new_file, &opt_ip_str);
22642510
2511 try comp.appendFileSystemInput(path);
2512
22652513 // Add the file contents to the `whole` cache manifest if necessary.
22662514 cache: {
22672515 const whole = switch (zcu.comp.cache_use) {
......@@ -2269,17 +2517,18 @@ fn newEmbedFile(
22692517 .incremental => break :cache,
22702518 };
22712519 const man = whole.cache_manifest orelse break :cache;
2272 const ip_str = opt_ip_str orelse break :cache;
2273
2274 const copied_resolved_path = try gpa.dupe(u8, resolved_path);
2275 errdefer gpa.free(copied_resolved_path);
2520 const ip_str = opt_ip_str orelse break :cache; // this will be a compile error
22762521
22772522 const array_len = Value.fromInterned(new_file.val).typeOf(zcu).childType(zcu).arrayLen(zcu);
2523 const contents = ip_str.toSlice(array_len, ip);
2524
2525 const path_str = try path.toAbsolute(comp.dirs, gpa);
2526 defer gpa.free(path_str);
22782527
22792528 whole.cache_manifest_mutex.lock();
22802529 defer whole.cache_manifest_mutex.unlock();
22812530
2282 man.addFilePostContents(copied_resolved_path, ip_str.toSlice(array_len, ip), new_file.stat) catch |err| switch (err) {
2531 man.addFilePostContents(path_str, contents, new_file.stat) catch |err| switch (err) {
22832532 error.Unexpected => unreachable,
22842533 else => |e| return e,
22852534 };
......@@ -2805,7 +3054,7 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err
28053054
28063055/// Removes any entry from `Zcu.failed_files` associated with `file`. Acquires `Compilation.mutex` as needed.
28073056/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.
2808fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
3057fn lockAndClearFileCompileError(pt: Zcu.PerThread, file_index: Zcu.File.Index, file: *Zcu.File) void {
28093058 const maybe_has_error = switch (file.status) {
28103059 .never_loaded => false,
28113060 .retryable_failure => true,
......@@ -2829,9 +3078,9 @@ fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
28293078
28303079 pt.zcu.comp.mutex.lock();
28313080 defer pt.zcu.comp.mutex.unlock();
2832 if (pt.zcu.failed_files.fetchSwapRemove(file)) |kv| {
3081 if (pt.zcu.failed_files.fetchSwapRemove(file_index)) |kv| {
28333082 assert(maybe_has_error); // the runtime safety case above
2834 if (kv.value) |msg| msg.destroy(pt.zcu.gpa); // delete previous error message
3083 if (kv.value) |msg| pt.zcu.gpa.free(msg); // delete previous error message
28353084 }
28363085}
28373086
......@@ -3009,8 +3258,8 @@ pub fn populateTestFunctions(
30093258 const zcu = pt.zcu;
30103259 const gpa = zcu.gpa;
30113260 const ip = &zcu.intern_pool;
3012 const builtin_mod = zcu.root_mod.getBuiltinDependency();
3013 const builtin_file_index = (pt.importPkg(builtin_mod) catch unreachable).file_index;
3261 const builtin_mod = zcu.builtin_modules.get(zcu.root_mod.getBuiltinOptions(zcu.comp.config).hash()).?;
3262 const builtin_file_index = zcu.module_roots.get(builtin_mod).?.unwrap().?;
30143263 pt.ensureFileAnalyzed(builtin_file_index) catch |err| switch (err) {
30153264 error.AnalysisFail => unreachable, // builtin module is generated so cannot be corrupt
30163265 error.OutOfMemory => |e| return e,
......@@ -3213,54 +3462,8 @@ pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Inde
32133462 }
32143463}
32153464
3216/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
3217pub fn reportRetryableAstGenError(
3218 pt: Zcu.PerThread,
3219 src: Zcu.AstGenSrc,
3220 file_index: Zcu.File.Index,
3221 err: anyerror,
3222) error{OutOfMemory}!void {
3223 const zcu = pt.zcu;
3224 const gpa = zcu.gpa;
3225 const ip = &zcu.intern_pool;
3226
3227 const file = zcu.fileByIndex(file_index);
3228 file.status = .retryable_failure;
3229
3230 const src_loc: Zcu.LazySrcLoc = switch (src) {
3231 .root => .{
3232 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
3233 .file = file_index,
3234 .inst = .main_struct_inst,
3235 }),
3236 .offset = .entire_file,
3237 },
3238 .import => |info| .{
3239 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
3240 .file = info.importing_file,
3241 .inst = .main_struct_inst,
3242 }),
3243 .offset = .{ .token_abs = info.import_tok },
3244 },
3245 };
3246
3247 const err_msg = try Zcu.ErrorMsg.create(gpa, src_loc, "unable to load '{}/{s}': {s}", .{
3248 file.mod.root, file.sub_file_path, @errorName(err),
3249 });
3250 errdefer err_msg.destroy(gpa);
3251
3252 zcu.comp.mutex.lock();
3253 defer zcu.comp.mutex.unlock();
3254 const gop = try zcu.failed_files.getOrPut(gpa, file);
3255 if (gop.found_existing) {
3256 if (gop.value_ptr.*) |old_err_msg| {
3257 old_err_msg.destroy(gpa);
3258 }
3259 }
3260 gop.value_ptr.* = err_msg;
3261}
3262
3263/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
3465/// Stores an error in `pt.zcu.failed_files` for this file, and sets the file
3466/// status to `retryable_failure`.
32643467pub fn reportRetryableFileError(
32653468 pt: Zcu.PerThread,
32663469 file_index: Zcu.File.Index,
......@@ -3269,35 +3472,27 @@ pub fn reportRetryableFileError(
32693472) error{OutOfMemory}!void {
32703473 const zcu = pt.zcu;
32713474 const gpa = zcu.gpa;
3272 const ip = &zcu.intern_pool;
32733475
32743476 const file = zcu.fileByIndex(file_index);
3477
32753478 file.status = .retryable_failure;
32763479
3277 const err_msg = try Zcu.ErrorMsg.create(
3278 gpa,
3279 .{
3280 .base_node_inst = try ip.trackZir(gpa, pt.tid, .{
3281 .file = file_index,
3282 .inst = .main_struct_inst,
3283 }),
3284 .offset = .entire_file,
3285 },
3286 format,
3287 args,
3288 );
3289 errdefer err_msg.destroy(gpa);
3480 const msg = try std.fmt.allocPrint(gpa, format, args);
3481 errdefer gpa.free(msg);
32903482
3291 zcu.comp.mutex.lock();
3292 defer zcu.comp.mutex.unlock();
3483 const old_msg: ?[]u8 = old_msg: {
3484 zcu.comp.mutex.lock();
3485 defer zcu.comp.mutex.unlock();
32933486
3294 const gop = try zcu.failed_files.getOrPut(gpa, file);
3295 if (gop.found_existing) {
3296 if (gop.value_ptr.*) |old_err_msg| {
3297 old_err_msg.destroy(gpa);
3298 }
3299 }
3300 gop.value_ptr.* = err_msg;
3487 const gop = try zcu.failed_files.getOrPut(gpa, file_index);
3488 const old: ?[]u8 = if (gop.found_existing) old: {
3489 break :old gop.value_ptr.*;
3490 } else null;
3491 gop.value_ptr.* = msg;
3492
3493 break :old_msg old;
3494 };
3495 if (old_msg) |m| gpa.free(m);
33013496}
33023497
33033498/// Shortcut for calling `intern_pool.get`.
......@@ -3850,7 +4045,7 @@ fn recreateStructType(
38504045
38514046 codegen_type: {
38524047 if (zcu.comp.config.use_llvm) break :codegen_type;
3853 if (file.mod.strip) break :codegen_type;
4048 if (file.mod.?.strip) break :codegen_type;
38544049 // This job depends on any resolve_type_fully jobs queued up before it.
38554050 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
38564051 }
......@@ -3946,7 +4141,7 @@ fn recreateUnionType(
39464141
39474142 codegen_type: {
39484143 if (zcu.comp.config.use_llvm) break :codegen_type;
3949 if (file.mod.strip) break :codegen_type;
4144 if (file.mod.?.strip) break :codegen_type;
39504145 // This job depends on any resolve_type_fully jobs queued up before it.
39514146 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });
39524147 }
src/arch/aarch64/CodeGen.zig+1-1
......@@ -333,7 +333,7 @@ pub fn generate(
333333 const func = zcu.funcInfo(func_index);
334334 const fn_type = Type.fromInterned(func.ty);
335335 const file_scope = zcu.navFileScope(func.owner_nav);
336 const target = &file_scope.mod.resolved_target.result;
336 const target = &file_scope.mod.?.resolved_target.result;
337337
338338 var branch_stack = std.ArrayList(Branch).init(gpa);
339339 defer {
src/arch/arm/CodeGen.zig+1-1
......@@ -342,7 +342,7 @@ pub fn generate(
342342 const func = zcu.funcInfo(func_index);
343343 const func_ty = Type.fromInterned(func.ty);
344344 const file_scope = zcu.navFileScope(func.owner_nav);
345 const target = &file_scope.mod.resolved_target.result;
345 const target = &file_scope.mod.?.resolved_target.result;
346346
347347 var branch_stack = std.ArrayList(Branch).init(gpa);
348348 defer {
src/arch/riscv64/CodeGen.zig+1-1
......@@ -767,7 +767,7 @@ pub fn generate(
767767 const ip = &zcu.intern_pool;
768768 const func = zcu.funcInfo(func_index);
769769 const fn_type = Type.fromInterned(func.ty);
770 const mod = zcu.navFileScope(func.owner_nav).mod;
770 const mod = zcu.navFileScope(func.owner_nav).mod.?;
771771
772772 var branch_stack = std.ArrayList(Branch).init(gpa);
773773 defer {
src/arch/sparc64/CodeGen.zig+1-1
......@@ -275,7 +275,7 @@ pub fn generate(
275275 const func = zcu.funcInfo(func_index);
276276 const func_ty = Type.fromInterned(func.ty);
277277 const file_scope = zcu.navFileScope(func.owner_nav);
278 const target = &file_scope.mod.resolved_target.result;
278 const target = &file_scope.mod.?.resolved_target.result;
279279
280280 var branch_stack = std.ArrayList(Branch).init(gpa);
281281 defer {
src/arch/wasm/CodeGen.zig+1-1
......@@ -1268,7 +1268,7 @@ pub fn function(
12681268 const gpa = zcu.gpa;
12691269 const cg = zcu.funcInfo(func_index);
12701270 const file_scope = zcu.navFileScope(cg.owner_nav);
1271 const target = &file_scope.mod.resolved_target.result;
1271 const target = &file_scope.mod.?.resolved_target.result;
12721272 const fn_ty = zcu.navValue(cg.owner_nav).typeOf(zcu);
12731273 const fn_info = zcu.typeToFunc(fn_ty).?;
12741274 const ip = &zcu.intern_pool;
src/arch/x86_64/CodeGen.zig+1-1
......@@ -888,7 +888,7 @@ pub fn generate(
888888 const ip = &zcu.intern_pool;
889889 const func = zcu.funcInfo(func_index);
890890 const fn_type: Type = .fromInterned(func.ty);
891 const mod = zcu.navFileScope(func.owner_nav).mod;
891 const mod = zcu.navFileScope(func.owner_nav).mod.?;
892892
893893 var function: CodeGen = .{
894894 .gpa = gpa,
src/codegen.zig+4-4
......@@ -56,7 +56,7 @@ pub fn generateFunction(
5656) CodeGenError!void {
5757 const zcu = pt.zcu;
5858 const func = zcu.funcInfo(func_index);
59 const target = zcu.navFileScope(func.owner_nav).mod.resolved_target.result;
59 const target = zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result;
6060 switch (target_util.zigBackend(target, false)) {
6161 else => unreachable,
6262 inline .stage2_aarch64,
......@@ -81,7 +81,7 @@ pub fn generateLazyFunction(
8181) CodeGenError!void {
8282 const zcu = pt.zcu;
8383 const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index|
84 zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.resolved_target.result
84 zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result
8585 else
8686 zcu.getTarget();
8787 switch (target_util.zigBackend(target, false)) {
......@@ -722,7 +722,7 @@ fn lowerNavRef(
722722 const zcu = pt.zcu;
723723 const gpa = zcu.gpa;
724724 const ip = &zcu.intern_pool;
725 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
725 const target = zcu.navFileScope(nav_index).mod.?.resolved_target.result;
726726 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
727727 const is_obj = lf.comp.config.output_mode == .Obj;
728728 const nav_ty = Type.fromInterned(ip.getNav(nav_index).typeOf(ip));
......@@ -884,7 +884,7 @@ fn genNavRef(
884884 else
885885 .{ false, .none, nav.isThreadlocal(ip) };
886886
887 const single_threaded = zcu.navFileScope(nav_index).mod.single_threaded;
887 const single_threaded = zcu.navFileScope(nav_index).mod.?.single_threaded;
888888 const name = nav.name;
889889 if (lf.cast(.elf)) |elf_file| {
890890 const zo = elf_file.zigObjectPtr().?;
src/codegen/c.zig+1-1
......@@ -2670,7 +2670,7 @@ pub fn genTypeDecl(
26702670 _ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
26712671 try writer.writeByte(';');
26722672 const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip);
2673 if (!zcu.fileByIndex(file_scope).mod.strip) try writer.print(" /* {} */", .{
2673 if (!zcu.fileByIndex(file_scope).mod.?.strip) try writer.print(" /* {} */", .{
26742674 ty.containerTypeName(ip).fmt(ip),
26752675 });
26762676 try writer.writeByte('\n');
src/codegen/llvm.zig+17-30
......@@ -587,13 +587,8 @@ pub const Object = struct {
587587 // into the garbage can by converting into absolute paths. What
588588 // a terrible tragedy.
589589 const compile_unit_dir = blk: {
590 if (comp.zcu) |zcu| m: {
591 const d = try zcu.main_mod.root.joinString(arena, "");
592 if (d.len == 0) break :m;
593 if (std.fs.path.isAbsolute(d)) break :blk d;
594 break :blk std.fs.realpathAlloc(arena, d) catch break :blk d;
595 }
596 break :blk try std.process.getCwdAlloc(arena);
590 const zcu = comp.zcu orelse break :blk comp.dirs.cwd;
591 break :blk try zcu.main_mod.root.toAbsolute(comp.dirs, arena);
597592 };
598593
599594 const debug_file = try builder.debugFile(
......@@ -1135,7 +1130,7 @@ pub const Object = struct {
11351130 const func = zcu.funcInfo(func_index);
11361131 const nav = ip.getNav(func.owner_nav);
11371132 const file_scope = zcu.navFileScopeIndex(func.owner_nav);
1138 const owner_mod = zcu.fileByIndex(file_scope).mod;
1133 const owner_mod = zcu.fileByIndex(file_scope).mod.?;
11391134 const fn_ty = Type.fromInterned(func.ty);
11401135 const fn_info = zcu.typeToFunc(fn_ty).?;
11411136 const target = owner_mod.resolved_target.result;
......@@ -1735,20 +1730,14 @@ pub const Object = struct {
17351730 const gop = try o.debug_file_map.getOrPut(gpa, file_index);
17361731 errdefer assert(o.debug_file_map.remove(file_index));
17371732 if (gop.found_existing) return gop.value_ptr.*;
1738 const file = o.pt.zcu.fileByIndex(file_index);
1733 const zcu = o.pt.zcu;
1734 const path = zcu.fileByIndex(file_index).path;
1735 const abs_path = try path.toAbsolute(zcu.comp.dirs, gpa);
1736 defer gpa.free(abs_path);
1737
17391738 gop.value_ptr.* = try o.builder.debugFile(
1740 try o.builder.metadataString(std.fs.path.basename(file.sub_file_path)),
1741 dir_path: {
1742 const sub_path = std.fs.path.dirname(file.sub_file_path) orelse "";
1743 const dir_path = try file.mod.root.joinString(gpa, sub_path);
1744 defer gpa.free(dir_path);
1745 if (std.fs.path.isAbsolute(dir_path))
1746 break :dir_path try o.builder.metadataString(dir_path);
1747 var abs_buffer: [std.fs.max_path_bytes]u8 = undefined;
1748 const abs_path = std.fs.realpath(dir_path, &abs_buffer) catch
1749 break :dir_path try o.builder.metadataString(dir_path);
1750 break :dir_path try o.builder.metadataString(abs_path);
1751 },
1739 try o.builder.metadataString(std.fs.path.basename(abs_path)),
1740 try o.builder.metadataString(std.fs.path.dirname(abs_path) orelse ""),
17521741 );
17531742 return gop.value_ptr.*;
17541743 }
......@@ -2646,11 +2635,9 @@ pub const Object = struct {
26462635 const zcu = pt.zcu;
26472636 const ip = &zcu.intern_pool;
26482637
2649 const std_mod = zcu.std_mod;
2650 const std_file_imported = pt.importPkg(std_mod) catch unreachable;
2651
2638 const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?;
26522639 const builtin_str = try ip.getOrPutString(zcu.gpa, pt.tid, "builtin", .no_embedded_nulls);
2653 const std_file_root_type = Type.fromInterned(zcu.fileRootType(std_file_imported.file_index));
2640 const std_file_root_type = Type.fromInterned(zcu.fileRootType(std_file_index));
26542641 const std_namespace = ip.namespacePtr(std_file_root_type.getNamespaceIndex(zcu));
26552642 const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }).?;
26562643
......@@ -2683,7 +2670,7 @@ pub const Object = struct {
26832670 const ip = &zcu.intern_pool;
26842671 const gpa = o.gpa;
26852672 const nav = ip.getNav(nav_index);
2686 const owner_mod = zcu.navFileScope(nav_index).mod;
2673 const owner_mod = zcu.navFileScope(nav_index).mod.?;
26872674 const ty: Type = .fromInterned(nav.typeOf(ip));
26882675 const gop = try o.nav_map.getOrPut(gpa, nav_index);
26892676 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.function;
......@@ -3013,7 +3000,7 @@ pub const Object = struct {
30133000 if (is_extern) {
30143001 variable_index.setLinkage(.external, &o.builder);
30153002 variable_index.setUnnamedAddr(.default, &o.builder);
3016 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.single_threaded)
3003 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
30173004 variable_index.setThreadLocal(.generaldynamic, &o.builder);
30183005 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
30193006 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
......@@ -4514,7 +4501,7 @@ pub const NavGen = struct {
45144501 err_msg: ?*Zcu.ErrorMsg,
45154502
45164503 fn ownerModule(ng: NavGen) *Package.Module {
4517 return ng.object.pt.zcu.navFileScope(ng.nav_index).mod;
4504 return ng.object.pt.zcu.navFileScope(ng.nav_index).mod.?;
45184505 }
45194506
45204507 fn todo(ng: *NavGen, comptime format: []const u8, args: anytype) Error {
......@@ -4557,7 +4544,7 @@ pub const NavGen = struct {
45574544 }, &o.builder);
45584545
45594546 const file_scope = zcu.navFileScopeIndex(nav_index);
4560 const mod = zcu.fileByIndex(file_scope).mod;
4547 const mod = zcu.fileByIndex(file_scope).mod.?;
45614548 if (is_threadlocal and !mod.single_threaded)
45624549 variable_index.setThreadLocal(.generaldynamic, &o.builder);
45634550
......@@ -5121,7 +5108,7 @@ pub const FuncGen = struct {
51215108 const func = zcu.funcInfo(inline_func);
51225109 const nav = ip.getNav(func.owner_nav);
51235110 const file_scope = zcu.navFileScopeIndex(func.owner_nav);
5124 const mod = zcu.fileByIndex(file_scope).mod;
5111 const mod = zcu.fileByIndex(file_scope).mod.?;
51255112
51265113 self.file = try o.getDebugFile(file_scope);
51275114
src/codegen/spirv.zig+1-1
......@@ -201,7 +201,7 @@ pub const Object = struct {
201201 ) !void {
202202 const zcu = pt.zcu;
203203 const gpa = zcu.gpa;
204 const structured_cfg = zcu.navFileScope(nav_index).mod.structured_cfg;
204 const structured_cfg = zcu.navFileScope(nav_index).mod.?.structured_cfg;
205205
206206 var nav_gen = NavGen{
207207 .gpa = gpa,
src/crash_report.zig+13-27
......@@ -86,15 +86,12 @@ fn dumpStatusReport() !void {
8686
8787 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu) orelse {
8888 const file = zcu.fileByIndex(block.src_base_inst.resolveFile(&zcu.intern_pool));
89 try stderr.writeAll("Analyzing lost instruction in file '");
90 try writeFilePath(file, stderr);
91 try stderr.writeAll("'. This should not happen!\n\n");
89 try stderr.print("Analyzing lost instruction in file '{}'. This should not happen!\n\n", .{file.path.fmt(zcu.comp)});
9290 return;
9391 };
9492
9593 try stderr.writeAll("Analyzing ");
96 try writeFilePath(file, stderr);
97 try stderr.writeAll("\n");
94 try stderr.print("Analyzing '{}'\n", .{file.path.fmt(zcu.comp)});
9895
9996 print_zir.renderInstructionContext(
10097 allocator,
......@@ -108,23 +105,24 @@ fn dumpStatusReport() !void {
108105 error.OutOfMemory => try stderr.writeAll(" <out of memory dumping zir>\n"),
109106 else => |e| return e,
110107 };
111 try stderr.writeAll(" For full context, use the command\n zig ast-check -t ");
112 try writeFilePath(file, stderr);
113 try stderr.writeAll("\n\n");
108 try stderr.print(
109 \\ For full context, use the command
110 \\ zig ast-check -t {}
111 \\
112 \\
113 , .{file.path.fmt(zcu.comp)});
114114
115115 var parent = anal.parent;
116116 while (parent) |curr| {
117117 fba.reset();
118 try stderr.writeAll(" in ");
119 const cur_block_file, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu) orelse {
120 const cur_block_file = zcu.fileByIndex(curr.block.src_base_inst.resolveFile(&zcu.intern_pool));
121 try writeFilePath(cur_block_file, stderr);
122 try stderr.writeAll("\n > [lost instruction; this should not happen]\n");
118 const cur_block_file = zcu.fileByIndex(curr.block.src_base_inst.resolveFile(&zcu.intern_pool));
119 try stderr.print(" in {}\n", .{cur_block_file.path.fmt(zcu.comp)});
120 _, const cur_block_src_base_node = Zcu.LazySrcLoc.resolveBaseNode(curr.block.src_base_inst, zcu) orelse {
121 try stderr.writeAll(" > [lost instruction; this should not happen]\n");
123122 parent = curr.parent;
124123 continue;
125124 };
126 try writeFilePath(cur_block_file, stderr);
127 try stderr.writeAll("\n > ");
125 try stderr.writeAll(" > ");
128126 print_zir.renderSingleInstruction(
129127 allocator,
130128 curr.body[curr.body_index],
......@@ -146,18 +144,6 @@ fn dumpStatusReport() !void {
146144
147145var crash_heap: [16 * 4096]u8 = undefined;
148146
149fn writeFilePath(file: *Zcu.File, writer: anytype) !void {
150 if (file.mod.root.root_dir.path) |path| {
151 try writer.writeAll(path);
152 try writer.writeAll(std.fs.path.sep_str);
153 }
154 if (file.mod.root.sub_path.len > 0) {
155 try writer.writeAll(file.mod.root.sub_path);
156 try writer.writeAll(std.fs.path.sep_str);
157 }
158 try writer.writeAll(file.sub_file_path);
159}
160
161147pub fn compilerPanic(msg: []const u8, maybe_ret_addr: ?usize) noreturn {
162148 @branchHint(.cold);
163149 PanicSwitch.preDispatch();
src/introspect.zig+129-60
......@@ -1,15 +1,18 @@
11const std = @import("std");
22const builtin = @import("builtin");
33const mem = std.mem;
4const Allocator = mem.Allocator;
45const os = std.os;
56const fs = std.fs;
7const Cache = std.Build.Cache;
68const Compilation = @import("Compilation.zig");
9const Package = @import("Package.zig");
710const build_options = @import("build_options");
811
912/// Returns the sub_path that worked, or `null` if none did.
1013/// The path of the returned Directory is relative to `base`.
1114/// The handle of the returned Directory is open.
12fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory {
15fn testZigInstallPrefix(base_dir: fs.Dir) ?Cache.Directory {
1316 const test_index_file = "std" ++ fs.path.sep_str ++ "std.zig";
1417
1518 zig_dir: {
......@@ -21,7 +24,7 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory {
2124 break :zig_dir;
2225 };
2326 file.close();
24 return Compilation.Directory{ .handle = test_zig_dir, .path = lib_zig };
27 return .{ .handle = test_zig_dir, .path = lib_zig };
2528 }
2629
2730 // Try lib/std/std.zig
......@@ -31,37 +34,50 @@ fn testZigInstallPrefix(base_dir: fs.Dir) ?Compilation.Directory {
3134 return null;
3235 };
3336 file.close();
34 return Compilation.Directory{ .handle = test_zig_dir, .path = "lib" };
35}
36
37/// This is a small wrapper around selfExePathAlloc that adds support for WASI
38/// based on a hard-coded Preopen directory ("/zig")
39pub fn findZigExePath(allocator: mem.Allocator) ![]u8 {
40 if (builtin.os.tag == .wasi) {
41 @compileError("this function is unsupported on WASI");
42 }
43
44 return fs.selfExePathAlloc(allocator);
37 return .{ .handle = test_zig_dir, .path = "lib" };
4538}
4639
4740/// Both the directory handle and the path are newly allocated resources which the caller now owns.
48pub fn findZigLibDir(gpa: mem.Allocator) !Compilation.Directory {
49 const self_exe_path = try findZigExePath(gpa);
41pub fn findZigLibDir(gpa: Allocator) !Cache.Directory {
42 const cwd_path = try getResolvedCwd(gpa);
43 defer gpa.free(cwd_path);
44 const self_exe_path = try fs.selfExePathAlloc(gpa);
5045 defer gpa.free(self_exe_path);
5146
52 return findZigLibDirFromSelfExe(gpa, self_exe_path);
47 return findZigLibDirFromSelfExe(gpa, cwd_path, self_exe_path);
5348}
5449
55/// Both the directory handle and the path are newly allocated resources which the caller now owns.
56pub fn findZigLibDirFromSelfExe(
57 allocator: mem.Allocator,
58 self_exe_path: []const u8,
59) error{
50/// Like `std.process.getCwdAlloc`, but also resolves the path with `std.fs.path.resolve`. This
51/// means the path has no repeated separators, no "." or ".." components, and no trailing separator.
52/// On WASI, "" is returned instead of ".".
53pub fn getResolvedCwd(gpa: Allocator) error{
6054 OutOfMemory,
61 FileNotFound,
6255 CurrentWorkingDirectoryUnlinked,
6356 Unexpected,
64}!Compilation.Directory {
57}![]u8 {
58 if (builtin.target.os.tag == .wasi) {
59 if (std.debug.runtime_safety) {
60 const cwd = try std.process.getCwdAlloc(gpa);
61 defer gpa.free(cwd);
62 std.debug.assert(mem.eql(u8, cwd, "."));
63 }
64 return "";
65 }
66 const cwd = try std.process.getCwdAlloc(gpa);
67 defer gpa.free(cwd);
68 const resolved = try fs.path.resolve(gpa, &.{cwd});
69 std.debug.assert(fs.path.isAbsolute(resolved));
70 return resolved;
71}
72
73/// Both the directory handle and the path are newly allocated resources which the caller now owns.
74pub fn findZigLibDirFromSelfExe(
75 allocator: Allocator,
76 /// The return value of `getResolvedCwd`.
77 /// Passed as an argument to avoid pointlessly repeating the call.
78 cwd_path: []const u8,
79 self_exe_path: []const u8,
80) error{ OutOfMemory, FileNotFound }!Cache.Directory {
6581 const cwd = fs.cwd();
6682 var cur_path: []const u8 = self_exe_path;
6783 while (fs.path.dirname(cur_path)) |dirname| : (cur_path = dirname) {
......@@ -69,18 +85,20 @@ pub fn findZigLibDirFromSelfExe(
6985 defer base_dir.close();
7086
7187 const sub_directory = testZigInstallPrefix(base_dir) orelse continue;
72 const p = try fs.path.join(allocator, &[_][]const u8{ dirname, sub_directory.path.? });
88 const p = try fs.path.join(allocator, &.{ dirname, sub_directory.path.? });
7389 defer allocator.free(p);
74 return Compilation.Directory{
90
91 const resolved = try resolvePath(allocator, cwd_path, &.{p});
92 return .{
7593 .handle = sub_directory.handle,
76 .path = try resolvePath(allocator, p),
94 .path = if (resolved.len == 0) null else resolved,
7795 };
7896 }
7997 return error.FileNotFound;
8098}
8199
82100/// Caller owns returned memory.
83pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
101pub fn resolveGlobalCacheDir(allocator: Allocator) ![]u8 {
84102 if (builtin.os.tag == .wasi)
85103 @compileError("on WASI the global cache dir must be resolved with preopens");
86104
......@@ -91,56 +109,107 @@ pub fn resolveGlobalCacheDir(allocator: mem.Allocator) ![]u8 {
91109 if (builtin.os.tag != .windows) {
92110 if (std.zig.EnvVar.XDG_CACHE_HOME.getPosix()) |cache_root| {
93111 if (cache_root.len > 0) {
94 return fs.path.join(allocator, &[_][]const u8{ cache_root, appname });
112 return fs.path.join(allocator, &.{ cache_root, appname });
95113 }
96114 }
97115 if (std.zig.EnvVar.HOME.getPosix()) |home| {
98 return fs.path.join(allocator, &[_][]const u8{ home, ".cache", appname });
116 return fs.path.join(allocator, &.{ home, ".cache", appname });
99117 }
100118 }
101119
102120 return fs.getAppDataDir(allocator, appname);
103121}
104122
105/// Similar to std.fs.path.resolve, with a few important differences:
106/// * If the input is an absolute path, check it against the cwd and try to
107/// convert it to a relative path.
108/// * If the resulting path would start with a relative up-dir ("../"), instead
109/// return an absolute path based on the cwd.
110/// * When targeting WASI, fail with an error message if an absolute path is
111/// used.
123/// Similar to `fs.path.resolve`, but converts to a cwd-relative path, or, if that would
124/// start with a relative up-dir (".."), an absolute path based on the cwd. Also, the cwd
125/// returns the empty string ("") instead of ".".
112126pub fn resolvePath(
113 ally: mem.Allocator,
114 p: []const u8,
115) error{
116 OutOfMemory,
117 CurrentWorkingDirectoryUnlinked,
118 Unexpected,
119}![]u8 {
120 if (fs.path.isAbsolute(p)) {
121 const cwd_path = try std.process.getCwdAlloc(ally);
122 defer ally.free(cwd_path);
123 const relative = try fs.path.relative(ally, cwd_path, p);
124 if (isUpDir(relative)) {
125 ally.free(relative);
126 return ally.dupe(u8, p);
127 } else {
128 return relative;
127 gpa: Allocator,
128 /// The return value of `getResolvedCwd`.
129 /// Passed as an argument to avoid pointlessly repeating the call.
130 cwd_resolved: []const u8,
131 paths: []const []const u8,
132) Allocator.Error![]u8 {
133 if (builtin.target.os.tag == .wasi) {
134 std.debug.assert(mem.eql(u8, cwd_resolved, ""));
135 const res = try fs.path.resolve(gpa, paths);
136 if (mem.eql(u8, res, ".")) {
137 gpa.free(res);
138 return "";
129139 }
140 return res;
141 }
142
143 // Heuristic for a fast path: if no component is absolute and ".." never appears, we just need to resolve `paths`.
144 for (paths) |p| {
145 if (fs.path.isAbsolute(p)) break; // absolute path
146 if (mem.indexOf(u8, p, "..") != null) break; // may contain up-dir
130147 } else {
131 const resolved = try fs.path.resolve(ally, &.{p});
132 if (isUpDir(resolved)) {
133 ally.free(resolved);
134 const cwd_path = try std.process.getCwdAlloc(ally);
135 defer ally.free(cwd_path);
136 return fs.path.resolve(ally, &.{ cwd_path, p });
137 } else {
138 return resolved;
148 // no absolute path, no "..".
149 const res = try fs.path.resolve(gpa, paths);
150 if (mem.eql(u8, res, ".")) {
151 gpa.free(res);
152 return "";
139153 }
154 std.debug.assert(!fs.path.isAbsolute(res));
155 std.debug.assert(!isUpDir(res));
156 return res;
157 }
158
159 // The fast path failed; resolve the whole thing.
160 // Optimization: `paths` often has just one element.
161 const path_resolved = switch (paths.len) {
162 0 => unreachable,
163 1 => try fs.path.resolve(gpa, &.{ cwd_resolved, paths[0] }),
164 else => r: {
165 const all_paths = try gpa.alloc([]const u8, paths.len + 1);
166 defer gpa.free(all_paths);
167 all_paths[0] = cwd_resolved;
168 @memcpy(all_paths[1..], paths);
169 break :r try fs.path.resolve(gpa, all_paths);
170 },
171 };
172 errdefer gpa.free(path_resolved);
173
174 std.debug.assert(fs.path.isAbsolute(path_resolved));
175 std.debug.assert(fs.path.isAbsolute(cwd_resolved));
176
177 if (!std.mem.startsWith(u8, path_resolved, cwd_resolved)) return path_resolved; // not in cwd
178 if (path_resolved.len == cwd_resolved.len) {
179 // equal to cwd
180 gpa.free(path_resolved);
181 return "";
140182 }
183 if (path_resolved[cwd_resolved.len] != std.fs.path.sep) return path_resolved; // not in cwd (last component differs)
184
185 // in cwd; extract sub path
186 const sub_path = try gpa.dupe(u8, path_resolved[cwd_resolved.len + 1 ..]);
187 gpa.free(path_resolved);
188 return sub_path;
141189}
142190
143191/// TODO move this to std.fs.path
144192pub fn isUpDir(p: []const u8) bool {
145193 return mem.startsWith(u8, p, "..") and (p.len == 2 or p[2] == fs.path.sep);
146194}
195
196pub const default_local_zig_cache_basename = ".zig-cache";
197
198/// Searches upwards from `cwd` for a directory containing a `build.zig` file.
199/// If such a directory is found, returns the path to it joined to the `.zig_cache` name.
200/// Otherwise, returns `null`, indicating no suitable local cache location.
201pub fn resolveSuitableLocalCacheDir(arena: Allocator, cwd: []const u8) Allocator.Error!?[]u8 {
202 var cur_dir = cwd;
203 while (true) {
204 const joined = try fs.path.join(arena, &.{ cur_dir, Package.build_zig_basename });
205 if (fs.cwd().access(joined, .{})) |_| {
206 return try fs.path.join(arena, &.{ cur_dir, default_local_zig_cache_basename });
207 } else |err| switch (err) {
208 error.FileNotFound => {
209 cur_dir = fs.path.dirname(cur_dir) orelse return null;
210 continue;
211 },
212 else => return null,
213 }
214 }
215}
src/libs/freebsd.zig+16-22
......@@ -34,7 +34,7 @@ pub fn needsCrt0(output_mode: std.builtin.OutputMode) ?CrtFile {
3434
3535fn includePath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
3636 return path.join(arena, &.{
37 comp.zig_lib_directory.path.?,
37 comp.dirs.zig_lib.path.?,
3838 "libc" ++ path.sep_str ++ "include",
3939 sub_path,
4040 });
......@@ -42,7 +42,7 @@ fn includePath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]co
4242
4343fn csuPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
4444 return path.join(arena, &.{
45 comp.zig_lib_directory.path.?,
45 comp.dirs.zig_lib.path.?,
4646 "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "lib" ++ path.sep_str ++ "csu",
4747 sub_path,
4848 });
......@@ -50,7 +50,7 @@ fn csuPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const
5050
5151fn libcPath(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
5252 return path.join(arena, &.{
53 comp.zig_lib_directory.path.?,
53 comp.dirs.zig_lib.path.?,
5454 "libc" ++ path.sep_str ++ "freebsd" ++ path.sep_str ++ "lib" ++ path.sep_str ++ "libc",
5555 sub_path,
5656 });
......@@ -438,11 +438,11 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
438438 // Use the global cache directory.
439439 var cache: Cache = .{
440440 .gpa = gpa,
441 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
441 .manifest_dir = try comp.dirs.global_cache.handle.makeOpenPath("h", .{}),
442442 };
443443 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
444 cache.addPrefix(comp.zig_lib_directory);
445 cache.addPrefix(comp.global_cache_directory);
444 cache.addPrefix(comp.dirs.zig_lib);
445 cache.addPrefix(comp.dirs.global_cache);
446446 defer cache.manifest_dir.close();
447447
448448 var man = cache.obtain();
......@@ -452,7 +452,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
452452 man.hash.add(target.abi);
453453 man.hash.add(target_version);
454454
455 const full_abilists_path = try comp.zig_lib_directory.join(arena, &.{abilists_path});
455 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
456456 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
457457
458458 if (try man.hit()) {
......@@ -461,7 +461,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
461461 return queueSharedObjects(comp, .{
462462 .lock = man.toOwnedLock(),
463463 .dir_path = .{
464 .root_dir = comp.global_cache_directory,
464 .root_dir = comp.dirs.global_cache,
465465 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
466466 },
467467 });
......@@ -470,9 +470,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
470470 const digest = man.final();
471471 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
472472
473 var o_directory: Compilation.Directory = .{
474 .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}),
475 .path = try comp.global_cache_directory.join(arena, &.{o_sub_path}),
473 var o_directory: Cache.Directory = .{
474 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
475 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
476476 };
477477 defer o_directory.handle.close();
478478
......@@ -974,7 +974,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
974974 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "stdthreads", etc.
975975 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
976976 try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });
977 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);
977 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
978978 }
979979
980980 man.writeManifest() catch |err| {
......@@ -984,7 +984,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
984984 return queueSharedObjects(comp, .{
985985 .lock = man.toOwnedLock(),
986986 .dir_path = .{
987 .root_dir = comp.global_cache_directory,
987 .root_dir = comp.dirs.global_cache,
988988 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
989989 },
990990 });
......@@ -1023,8 +1023,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
10231023fn buildSharedLib(
10241024 comp: *Compilation,
10251025 arena: Allocator,
1026 zig_cache_directory: Compilation.Directory,
1027 bin_directory: Compilation.Directory,
1026 bin_directory: Cache.Directory,
10281027 asm_file_basename: []const u8,
10291028 lib: Lib,
10301029 prog_node: std.Progress.Node,
......@@ -1057,9 +1056,8 @@ fn buildSharedLib(
10571056 });
10581057
10591058 const root_mod = try Module.create(arena, .{
1060 .global_cache_directory = comp.global_cache_directory,
10611059 .paths = .{
1062 .root = .{ .root_dir = comp.zig_lib_directory },
1060 .root = .zig_lib_root,
10631061 .root_src_path = "",
10641062 },
10651063 .fully_qualified_name = "root",
......@@ -1079,8 +1077,6 @@ fn buildSharedLib(
10791077 .global = config,
10801078 .cc_argv = &.{},
10811079 .parent = null,
1082 .builtin_mod = null,
1083 .builtin_modules = null, // there is only one module in this compilation
10841080 });
10851081
10861082 const c_source_files = [1]Compilation.CSourceFile{
......@@ -1091,9 +1087,7 @@ fn buildSharedLib(
10911087 };
10921088
10931089 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
1094 .local_cache_directory = zig_cache_directory,
1095 .global_cache_directory = comp.global_cache_directory,
1096 .zig_lib_directory = comp.zig_lib_directory,
1090 .dirs = comp.dirs.withoutLocalCache(),
10971091 .thread_pool = comp.thread_pool,
10981092 .self_exe_path = comp.self_exe_path,
10991093 .cache_mode = .incremental,
src/libs/glibc.zig+19-29
......@@ -365,7 +365,7 @@ fn start_asm_path(comp: *Compilation, arena: Allocator, basename: []const u8) ![
365365 const s = path.sep_str;
366366
367367 var result = std.ArrayList(u8).init(arena);
368 try result.appendSlice(comp.zig_lib_directory.path.?);
368 try result.appendSlice(comp.dirs.zig_lib.path orelse ".");
369369 try result.appendSlice(s ++ "libc" ++ s ++ "glibc" ++ s ++ "sysdeps" ++ s);
370370 if (is_sparc) {
371371 if (is_64) {
......@@ -439,7 +439,7 @@ fn add_include_dirs(comp: *Compilation, arena: Allocator, args: *std.ArrayList([
439439 }
440440 if (opt_nptl) |nptl| {
441441 try args.append("-I");
442 try args.append(try path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, lib_libc_glibc ++ "sysdeps", nptl }));
442 try args.append(try path.join(arena, &.{ comp.dirs.zig_lib.path orelse ".", lib_libc_glibc ++ "sysdeps", nptl }));
443443 }
444444
445445 try args.append("-I");
......@@ -459,11 +459,11 @@ fn add_include_dirs(comp: *Compilation, arena: Allocator, args: *std.ArrayList([
459459 try args.append(try lib_path(comp, arena, lib_libc_glibc ++ "sysdeps" ++ s ++ "generic"));
460460
461461 try args.append("-I");
462 try args.append(try path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, lib_libc ++ "glibc" }));
462 try args.append(try path.join(arena, &[_][]const u8{ comp.dirs.zig_lib.path orelse ".", lib_libc ++ "glibc" }));
463463
464464 try args.append("-I");
465465 try args.append(try std.fmt.allocPrint(arena, "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-{s}-{s}", .{
466 comp.zig_lib_directory.path.?, @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi),
466 comp.dirs.zig_lib.path orelse ".", @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi),
467467 }));
468468
469469 try args.append("-I");
......@@ -472,7 +472,7 @@ fn add_include_dirs(comp: *Compilation, arena: Allocator, args: *std.ArrayList([
472472 const arch_name = std.zig.target.osArchName(target);
473473 try args.append("-I");
474474 try args.append(try std.fmt.allocPrint(arena, "{s}" ++ s ++ "libc" ++ s ++ "include" ++ s ++ "{s}-linux-any", .{
475 comp.zig_lib_directory.path.?, arch_name,
475 comp.dirs.zig_lib.path orelse ".", arch_name,
476476 }));
477477
478478 try args.append("-I");
......@@ -626,15 +626,11 @@ fn add_include_dirs_arch(
626626 }
627627}
628628
629fn path_from_lib(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
630 return path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, sub_path });
631}
632
633629const lib_libc = "libc" ++ path.sep_str;
634630const lib_libc_glibc = lib_libc ++ "glibc" ++ path.sep_str;
635631
636632fn lib_path(comp: *Compilation, arena: Allocator, sub_path: []const u8) ![]const u8 {
637 return path.join(arena, &[_][]const u8{ comp.zig_lib_directory.path.?, sub_path });
633 return path.join(arena, &.{ comp.dirs.zig_lib.path orelse ".", sub_path });
638634}
639635
640636pub const BuiltSharedObjects = struct {
......@@ -678,11 +674,11 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
678674 // Use the global cache directory.
679675 var cache: Cache = .{
680676 .gpa = gpa,
681 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
677 .manifest_dir = try comp.dirs.global_cache.handle.makeOpenPath("h", .{}),
682678 };
683679 cache.addPrefix(.{ .path = null, .handle = fs.cwd() });
684 cache.addPrefix(comp.zig_lib_directory);
685 cache.addPrefix(comp.global_cache_directory);
680 cache.addPrefix(comp.dirs.zig_lib);
681 cache.addPrefix(comp.dirs.global_cache);
686682 defer cache.manifest_dir.close();
687683
688684 var man = cache.obtain();
......@@ -692,7 +688,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
692688 man.hash.add(target.abi);
693689 man.hash.add(target_version);
694690
695 const full_abilists_path = try comp.zig_lib_directory.join(arena, &.{abilists_path});
691 const full_abilists_path = try comp.dirs.zig_lib.join(arena, &.{abilists_path});
696692 const abilists_index = try man.addFile(full_abilists_path, abilists_max_size);
697693
698694 if (try man.hit()) {
......@@ -701,7 +697,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
701697 return queueSharedObjects(comp, .{
702698 .lock = man.toOwnedLock(),
703699 .dir_path = .{
704 .root_dir = comp.global_cache_directory,
700 .root_dir = comp.dirs.global_cache,
705701 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
706702 },
707703 });
......@@ -710,9 +706,9 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
710706 const digest = man.final();
711707 const o_sub_path = try path.join(arena, &[_][]const u8{ "o", &digest });
712708
713 var o_directory: Compilation.Directory = .{
714 .handle = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{}),
715 .path = try comp.global_cache_directory.join(arena, &.{o_sub_path}),
709 var o_directory: Cache.Directory = .{
710 .handle = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{}),
711 .path = try comp.dirs.global_cache.join(arena, &.{o_sub_path}),
716712 };
717713 defer o_directory.handle.close();
718714
......@@ -1112,7 +1108,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
11121108 var lib_name_buf: [32]u8 = undefined; // Larger than each of the names "c", "pthread", etc.
11131109 const asm_file_basename = std.fmt.bufPrint(&lib_name_buf, "{s}.s", .{lib.name}) catch unreachable;
11141110 try o_directory.handle.writeFile(.{ .sub_path = asm_file_basename, .data = stubs_asm.items });
1115 try buildSharedLib(comp, arena, comp.global_cache_directory, o_directory, asm_file_basename, lib, prog_node);
1111 try buildSharedLib(comp, arena, o_directory, asm_file_basename, lib, prog_node);
11161112 }
11171113
11181114 man.writeManifest() catch |err| {
......@@ -1122,7 +1118,7 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
11221118 return queueSharedObjects(comp, .{
11231119 .lock = man.toOwnedLock(),
11241120 .dir_path = .{
1125 .root_dir = comp.global_cache_directory,
1121 .root_dir = comp.dirs.global_cache,
11261122 .sub_path = try gpa.dupe(u8, "o" ++ fs.path.sep_str ++ digest),
11271123 },
11281124 });
......@@ -1174,8 +1170,7 @@ fn queueSharedObjects(comp: *Compilation, so_files: BuiltSharedObjects) void {
11741170fn buildSharedLib(
11751171 comp: *Compilation,
11761172 arena: Allocator,
1177 zig_cache_directory: Compilation.Directory,
1178 bin_directory: Compilation.Directory,
1173 bin_directory: Cache.Directory,
11791174 asm_file_basename: []const u8,
11801175 lib: Lib,
11811176 prog_node: std.Progress.Node,
......@@ -1208,9 +1203,8 @@ fn buildSharedLib(
12081203 });
12091204
12101205 const root_mod = try Module.create(arena, .{
1211 .global_cache_directory = comp.global_cache_directory,
12121206 .paths = .{
1213 .root = .{ .root_dir = comp.zig_lib_directory },
1207 .root = .zig_lib_root,
12141208 .root_src_path = "",
12151209 },
12161210 .fully_qualified_name = "root",
......@@ -1230,8 +1224,6 @@ fn buildSharedLib(
12301224 .global = config,
12311225 .cc_argv = &.{},
12321226 .parent = null,
1233 .builtin_mod = null,
1234 .builtin_modules = null, // there is only one module in this compilation
12351227 });
12361228
12371229 const c_source_files = [1]Compilation.CSourceFile{
......@@ -1242,9 +1234,7 @@ fn buildSharedLib(
12421234 };
12431235
12441236 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
1245 .local_cache_directory = zig_cache_directory,
1246 .global_cache_directory = comp.global_cache_directory,
1247 .zig_lib_directory = comp.zig_lib_directory,
1237 .dirs = comp.dirs.withoutLocalCache(),
12481238 .thread_pool = comp.thread_pool,
12491239 .self_exe_path = comp.self_exe_path,
12501240 .cache_mode = .incremental,
src/libs/libcxx.zig+13-23
......@@ -134,10 +134,10 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
134134 .basename = basename,
135135 };
136136
137 const cxxabi_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", "include" });
138 const cxx_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" });
139 const cxx_src_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "src" });
140 const cxx_libc_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "libc" });
137 const cxxabi_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxxabi", "include" });
138 const cxx_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "include" });
139 const cxx_src_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "src" });
140 const cxx_libc_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "libc" });
141141
142142 const optimize_mode = comp.compilerRtOptMode();
143143 const strip = comp.compilerRtStrip();
......@@ -164,9 +164,8 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
164164 };
165165
166166 const root_mod = Module.create(arena, .{
167 .global_cache_directory = comp.global_cache_directory,
168167 .paths = .{
169 .root = .{ .root_dir = comp.zig_lib_directory },
168 .root = .zig_lib_root,
170169 .root_src_path = "",
171170 },
172171 .fully_qualified_name = "root",
......@@ -188,8 +187,6 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
188187 .global = config,
189188 .cc_argv = &.{},
190189 .parent = null,
191 .builtin_mod = null,
192 .builtin_modules = null, // there is only one module in this compilation
193190 }) catch |err| {
194191 comp.setMiscFailure(
195192 .libcxx,
......@@ -258,7 +255,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
258255 try cache_exempt_flags.append(cxx_libc_include_path);
259256
260257 c_source_files.appendAssumeCapacity(.{
261 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", cxx_src }),
258 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", cxx_src }),
262259 .extra_flags = cflags.items,
263260 .cache_exempt_flags = cache_exempt_flags.items,
264261 .owner = root_mod,
......@@ -266,9 +263,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
266263 }
267264
268265 const sub_compilation = Compilation.create(comp.gpa, arena, .{
269 .local_cache_directory = comp.global_cache_directory,
270 .global_cache_directory = comp.global_cache_directory,
271 .zig_lib_directory = comp.zig_lib_directory,
266 .dirs = comp.dirs.withoutLocalCache(),
272267 .self_exe_path = comp.self_exe_path,
273268 .cache_mode = .whole,
274269 .config = config,
......@@ -344,9 +339,9 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
344339 .basename = basename,
345340 };
346341
347 const cxxabi_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", "include" });
348 const cxx_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "include" });
349 const cxx_src_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxx", "src" });
342 const cxxabi_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxxabi", "include" });
343 const cxx_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "include" });
344 const cxx_src_include_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxx", "src" });
350345
351346 const optimize_mode = comp.compilerRtOptMode();
352347 const strip = comp.compilerRtStrip();
......@@ -378,9 +373,8 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
378373 };
379374
380375 const root_mod = Module.create(arena, .{
381 .global_cache_directory = comp.global_cache_directory,
382376 .paths = .{
383 .root = .{ .root_dir = comp.zig_lib_directory },
377 .root = .zig_lib_root,
384378 .root_src_path = "",
385379 },
386380 .fully_qualified_name = "root",
......@@ -403,8 +397,6 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
403397 .global = config,
404398 .cc_argv = &.{},
405399 .parent = null,
406 .builtin_mod = null,
407 .builtin_modules = null, // there is only one module in this compilation
408400 }) catch |err| {
409401 comp.setMiscFailure(
410402 .libcxxabi,
......@@ -459,7 +451,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
459451 try cache_exempt_flags.append(cxx_src_include_path);
460452
461453 c_source_files.appendAssumeCapacity(.{
462 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libcxxabi", cxxabi_src }),
454 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libcxxabi", cxxabi_src }),
463455 .extra_flags = cflags.items,
464456 .cache_exempt_flags = cache_exempt_flags.items,
465457 .owner = root_mod,
......@@ -467,9 +459,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
467459 }
468460
469461 const sub_compilation = Compilation.create(comp.gpa, arena, .{
470 .local_cache_directory = comp.global_cache_directory,
471 .global_cache_directory = comp.global_cache_directory,
472 .zig_lib_directory = comp.zig_lib_directory,
462 .dirs = comp.dirs.withoutLocalCache(),
473463 .self_exe_path = comp.self_exe_path,
474464 .cache_mode = .whole,
475465 .config = config,
src/libs/libtsan.zig+12-20
......@@ -84,9 +84,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
8484 };
8585
8686 const root_mod = Module.create(arena, .{
87 .global_cache_directory = comp.global_cache_directory,
8887 .paths = .{
89 .root = .{ .root_dir = comp.zig_lib_directory },
88 .root = .zig_lib_root,
9089 .root_src_path = "",
9190 },
9291 .fully_qualified_name = "root",
......@@ -110,8 +109,6 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
110109 .global = config,
111110 .cc_argv = &common_flags,
112111 .parent = null,
113 .builtin_mod = null,
114 .builtin_modules = null, // there is only one module in this compilation
115112 }) catch |err| {
116113 comp.setMiscFailure(
117114 .libtsan,
......@@ -124,7 +121,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
124121 var c_source_files = std.ArrayList(Compilation.CSourceFile).init(arena);
125122 try c_source_files.ensureUnusedCapacity(tsan_sources.len);
126123
127 const tsan_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"libtsan"});
124 const tsan_include_path = try comp.dirs.zig_lib.join(arena, &.{"libtsan"});
128125 for (tsan_sources) |tsan_src| {
129126 var cflags = std.ArrayList([]const u8).init(arena);
130127
......@@ -134,7 +131,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
134131 try addCcArgs(target, &cflags);
135132
136133 c_source_files.appendAssumeCapacity(.{
137 .src_path = try comp.zig_lib_directory.join(arena, &.{ "libtsan", tsan_src }),
134 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libtsan", tsan_src }),
138135 .extra_flags = cflags.items,
139136 .owner = root_mod,
140137 });
......@@ -155,7 +152,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
155152 try addCcArgs(target, &cflags);
156153
157154 c_source_files.appendAssumeCapacity(.{
158 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libtsan", tsan_src }),
155 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libtsan", tsan_src }),
159156 .extra_flags = cflags.items,
160157 .owner = root_mod,
161158 });
......@@ -179,14 +176,14 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
179176 try cflags.append("-DNDEBUG");
180177
181178 c_source_files.appendAssumeCapacity(.{
182 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libtsan", asm_source }),
179 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libtsan", asm_source }),
183180 .extra_flags = cflags.items,
184181 .owner = root_mod,
185182 });
186183 }
187184
188185 try c_source_files.ensureUnusedCapacity(sanitizer_common_sources.len);
189 const sanitizer_common_include_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
186 const sanitizer_common_include_path = try comp.dirs.zig_lib.join(arena, &.{
190187 "libtsan", "sanitizer_common",
191188 });
192189 for (sanitizer_common_sources) |common_src| {
......@@ -200,7 +197,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
200197 try addCcArgs(target, &cflags);
201198
202199 c_source_files.appendAssumeCapacity(.{
203 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
200 .src_path = try comp.dirs.zig_lib.join(arena, &.{
204201 "libtsan", "sanitizer_common", common_src,
205202 }),
206203 .extra_flags = cflags.items,
......@@ -224,7 +221,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
224221 try addCcArgs(target, &cflags);
225222
226223 c_source_files.appendAssumeCapacity(.{
227 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
224 .src_path = try comp.dirs.zig_lib.join(arena, &.{
228225 "libtsan", "sanitizer_common", c_src,
229226 }),
230227 .extra_flags = cflags.items,
......@@ -242,7 +239,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
242239 try addCcArgs(target, &cflags);
243240
244241 c_source_files.appendAssumeCapacity(.{
245 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
242 .src_path = try comp.dirs.zig_lib.join(arena, &.{
246243 "libtsan", "sanitizer_common", c_src,
247244 }),
248245 .extra_flags = cflags.items,
......@@ -250,10 +247,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
250247 });
251248 }
252249
253 const interception_include_path = try comp.zig_lib_directory.join(
254 arena,
255 &[_][]const u8{"interception"},
256 );
250 const interception_include_path = try comp.dirs.zig_lib.join(arena, &.{"interception"});
257251
258252 try c_source_files.ensureUnusedCapacity(interception_sources.len);
259253 for (interception_sources) |c_src| {
......@@ -268,7 +262,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
268262 try addCcArgs(target, &cflags);
269263
270264 c_source_files.appendAssumeCapacity(.{
271 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
265 .src_path = try comp.dirs.zig_lib.join(arena, &.{
272266 "libtsan", "interception", c_src,
273267 }),
274268 .extra_flags = cflags.items,
......@@ -285,9 +279,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
285279 // Workaround for https://github.com/llvm/llvm-project/issues/97627
286280 const headerpad_size: ?u32 = if (target.os.tag.isDarwin()) 32 else null;
287281 const sub_compilation = Compilation.create(comp.gpa, arena, .{
288 .local_cache_directory = comp.global_cache_directory,
289 .global_cache_directory = comp.global_cache_directory,
290 .zig_lib_directory = comp.zig_lib_directory,
282 .dirs = comp.dirs.withoutLocalCache(),
291283 .thread_pool = comp.thread_pool,
292284 .self_exe_path = comp.self_exe_path,
293285 .cache_mode = .whole,
src/libs/libunwind.zig+4-9
......@@ -50,9 +50,8 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
5050 return error.SubCompilationFailed;
5151 };
5252 const root_mod = Module.create(arena, .{
53 .global_cache_directory = comp.global_cache_directory,
5453 .paths = .{
55 .root = .{ .root_dir = comp.zig_lib_directory },
54 .root = .zig_lib_root,
5655 .root_src_path = "",
5756 },
5857 .fully_qualified_name = "root",
......@@ -76,8 +75,6 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
7675 .global = config,
7776 .cc_argv = &.{},
7877 .parent = null,
79 .builtin_mod = null,
80 .builtin_modules = null, // there is only one module in this compilation
8178 }) catch |err| {
8279 comp.setMiscFailure(
8380 .libunwind,
......@@ -118,7 +115,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
118115 else => unreachable, // See `unwind_src_list`.
119116 }
120117 try cflags.append("-I");
121 try cflags.append(try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libunwind", "include" }));
118 try cflags.append(try comp.dirs.zig_lib.join(arena, &.{ "libunwind", "include" }));
122119 try cflags.append("-D_LIBUNWIND_HIDE_SYMBOLS");
123120 try cflags.append("-Wa,--noexecstack");
124121 try cflags.append("-fvisibility=hidden");
......@@ -148,16 +145,14 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
148145 }
149146
150147 c_source_files[i] = .{
151 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{unwind_src}),
148 .src_path = try comp.dirs.zig_lib.join(arena, &.{unwind_src}),
152149 .extra_flags = cflags.items,
153150 .owner = root_mod,
154151 };
155152 }
156153 const sub_compilation = Compilation.create(comp.gpa, arena, .{
154 .dirs = comp.dirs.withoutLocalCache(),
157155 .self_exe_path = comp.self_exe_path,
158 .local_cache_directory = comp.global_cache_directory,
159 .global_cache_directory = comp.global_cache_directory,
160 .zig_lib_directory = comp.zig_lib_directory,
161156 .config = config,
162157 .root_mod = root_mod,
163158 .cache_mode = .whole,
src/libs/mingw.zig+23-23
......@@ -40,7 +40,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
4040 }
4141 var files = [_]Compilation.CSourceFile{
4242 .{
43 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
43 .src_path = try comp.dirs.zig_lib.join(arena, &.{
4444 "libc", "mingw", "crt", "crtexe.c",
4545 }),
4646 .extra_flags = args.items,
......@@ -57,7 +57,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
5757 try addCrtCcArgs(comp, arena, &args);
5858 var files = [_]Compilation.CSourceFile{
5959 .{
60 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
60 .src_path = try comp.dirs.zig_lib.join(arena, &.{
6161 "libc", "mingw", "crt", "crtdll.c",
6262 }),
6363 .extra_flags = args.items,
......@@ -78,7 +78,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
7878
7979 for (mingw32_generic_src) |dep| {
8080 try c_source_files.append(.{
81 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
81 .src_path = try comp.dirs.zig_lib.join(arena, &.{
8282 "libc", "mingw", dep,
8383 }),
8484 .extra_flags = crt_args.items,
......@@ -88,7 +88,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
8888 if (target.cpu.arch.isX86()) {
8989 for (mingw32_x86_src) |dep| {
9090 try c_source_files.append(.{
91 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
91 .src_path = try comp.dirs.zig_lib.join(arena, &.{
9292 "libc", "mingw", dep,
9393 }),
9494 .extra_flags = crt_args.items,
......@@ -98,7 +98,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
9898 if (target.cpu.arch == .x86) {
9999 for (mingw32_x86_32_src) |dep| {
100100 try c_source_files.append(.{
101 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
101 .src_path = try comp.dirs.zig_lib.join(arena, &.{
102102 "libc", "mingw", dep,
103103 }),
104104 .extra_flags = crt_args.items,
......@@ -109,7 +109,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
109109 } else if (target.cpu.arch == .thumb) {
110110 for (mingw32_arm_src) |dep| {
111111 try c_source_files.append(.{
112 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
112 .src_path = try comp.dirs.zig_lib.join(arena, &.{
113113 "libc", "mingw", dep,
114114 }),
115115 .extra_flags = crt_args.items,
......@@ -118,7 +118,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
118118 }
119119 for (mingw32_arm32_src) |dep| {
120120 try c_source_files.append(.{
121 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
121 .src_path = try comp.dirs.zig_lib.join(arena, &.{
122122 "libc", "mingw", dep,
123123 }),
124124 .extra_flags = crt_args.items,
......@@ -128,7 +128,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
128128 } else if (target.cpu.arch == .aarch64) {
129129 for (mingw32_arm_src) |dep| {
130130 try c_source_files.append(.{
131 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
131 .src_path = try comp.dirs.zig_lib.join(arena, &.{
132132 "libc", "mingw", dep,
133133 }),
134134 .extra_flags = crt_args.items,
......@@ -137,7 +137,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
137137 }
138138 for (mingw32_arm64_src) |dep| {
139139 try c_source_files.append(.{
140 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
140 .src_path = try comp.dirs.zig_lib.join(arena, &.{
141141 "libc", "mingw", dep,
142142 }),
143143 .extra_flags = crt_args.items,
......@@ -164,7 +164,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
164164
165165 for (mingw32_winpthreads_src) |dep| {
166166 try c_source_files.append(.{
167 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
167 .src_path = try comp.dirs.zig_lib.join(arena, &.{
168168 "libc", "mingw", dep,
169169 }),
170170 .extra_flags = winpthreads_args.items,
......@@ -192,7 +192,7 @@ fn addCcArgs(
192192 "-D__USE_MINGW_ANSI_STDIO=0",
193193
194194 "-isystem",
195 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", "any-windows-any" }),
195 try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", "any-windows-any" }),
196196 });
197197}
198198
......@@ -219,7 +219,7 @@ fn addCrtCcArgs(
219219 "-DHAVE_CONFIG_H",
220220
221221 "-I",
222 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "include" }),
222 try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "include" }),
223223 });
224224}
225225
......@@ -232,7 +232,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
232232 defer arena_allocator.deinit();
233233 const arena = arena_allocator.allocator();
234234
235 const def_file_path = findDef(arena, comp.getTarget(), comp.zig_lib_directory, lib_name) catch |err| switch (err) {
235 const def_file_path = findDef(arena, comp.getTarget(), comp.dirs.zig_lib, lib_name) catch |err| switch (err) {
236236 error.FileNotFound => {
237237 log.debug("no {s}.def file available to make a DLL import {s}.lib", .{ lib_name, lib_name });
238238 // In this case we will end up putting foo.lib onto the linker line and letting the linker
......@@ -247,15 +247,15 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
247247 // Use the global cache directory.
248248 var cache: Cache = .{
249249 .gpa = gpa,
250 .manifest_dir = try comp.global_cache_directory.handle.makeOpenPath("h", .{}),
250 .manifest_dir = try comp.dirs.global_cache.handle.makeOpenPath("h", .{}),
251251 };
252252 cache.addPrefix(.{ .path = null, .handle = std.fs.cwd() });
253 cache.addPrefix(comp.zig_lib_directory);
254 cache.addPrefix(comp.global_cache_directory);
253 cache.addPrefix(comp.dirs.zig_lib);
254 cache.addPrefix(comp.dirs.global_cache);
255255 defer cache.manifest_dir.close();
256256
257257 cache.hash.addBytes(build_options.version);
258 cache.hash.addOptionalBytes(comp.zig_lib_directory.path);
258 cache.hash.addOptionalBytes(comp.dirs.zig_lib.path);
259259 cache.hash.add(target.cpu.arch);
260260
261261 var man = cache.obtain();
......@@ -276,7 +276,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
276276 try comp.crt_files.ensureUnusedCapacity(gpa, 1);
277277 comp.crt_files.putAssumeCapacityNoClobber(final_lib_basename, .{
278278 .full_object_path = .{
279 .root_dir = comp.global_cache_directory,
279 .root_dir = comp.dirs.global_cache,
280280 .sub_path = sub_path,
281281 },
282282 .lock = man.toOwnedLock(),
......@@ -286,11 +286,11 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
286286
287287 const digest = man.final();
288288 const o_sub_path = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
289 var o_dir = try comp.global_cache_directory.handle.makeOpenPath(o_sub_path, .{});
289 var o_dir = try comp.dirs.global_cache.handle.makeOpenPath(o_sub_path, .{});
290290 defer o_dir.close();
291291
292292 const final_def_basename = try std.fmt.allocPrint(arena, "{s}.def", .{lib_name});
293 const def_final_path = try comp.global_cache_directory.join(arena, &[_][]const u8{
293 const def_final_path = try comp.dirs.global_cache.join(arena, &[_][]const u8{
294294 "o", &digest, final_def_basename,
295295 });
296296
......@@ -306,7 +306,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
306306 var aro_comp = aro.Compilation.init(gpa, std.fs.cwd());
307307 defer aro_comp.deinit();
308308
309 const include_dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "mingw", "def-include" });
309 const include_dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "mingw", "def-include" });
310310
311311 if (comp.verbose_cc) print: {
312312 std.debug.lockStdErr();
......@@ -350,7 +350,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
350350 if (!build_options.have_llvm) return error.ZigCompilerNotBuiltWithLLVMExtensions;
351351 const llvm_bindings = @import("../codegen/llvm/bindings.zig");
352352 const def_final_path_z = try arena.dupeZ(u8, def_final_path);
353 const lib_final_path_z = try comp.global_cache_directory.joinZ(arena, &.{lib_final_path});
353 const lib_final_path_z = try comp.dirs.global_cache.joinZ(arena, &.{lib_final_path});
354354 if (llvm_bindings.WriteImportLibrary(
355355 def_final_path_z.ptr,
356356 @intFromEnum(target.toCoffMachine()),
......@@ -370,7 +370,7 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8) !void {
370370 defer comp.mutex.unlock();
371371 try comp.crt_files.putNoClobber(gpa, final_lib_basename, .{
372372 .full_object_path = .{
373 .root_dir = comp.global_cache_directory,
373 .root_dir = comp.dirs.global_cache,
374374 .sub_path = lib_final_path,
375375 },
376376 .lock = man.toOwnedLock(),
src/libs/musl.zig+16-21
......@@ -34,7 +34,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
3434 try args.append("-DCRT");
3535 var files = [_]Compilation.CSourceFile{
3636 .{
37 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
37 .src_path = try comp.dirs.zig_lib.join(arena, &.{
3838 "libc", "musl", "crt", "crt1.c",
3939 }),
4040 .extra_flags = args.items,
......@@ -54,7 +54,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
5454 try args.append("-DCRT");
5555 var files = [_]Compilation.CSourceFile{
5656 .{
57 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
57 .src_path = try comp.dirs.zig_lib.join(arena, &.{
5858 "libc", "musl", "crt", "rcrt1.c",
5959 }),
6060 .extra_flags = args.items,
......@@ -75,7 +75,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
7575 try args.append("-DCRT");
7676 var files = [_]Compilation.CSourceFile{
7777 .{
78 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
78 .src_path = try comp.dirs.zig_lib.join(arena, &.{
7979 "libc", "musl", "crt", "Scrt1.c",
8080 }),
8181 .extra_flags = args.items,
......@@ -165,7 +165,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
165165 try addCcArgs(comp, arena, &args, ext == .o3);
166166 const c_source_file = try c_source_files.addOne();
167167 c_source_file.* = .{
168 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", src_file }),
168 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libc", src_file }),
169169 .extra_flags = args.items,
170170 .owner = undefined,
171171 };
......@@ -220,9 +220,8 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
220220 &.{ arch_define, family_define };
221221
222222 const root_mod = try Module.create(arena, .{
223 .global_cache_directory = comp.global_cache_directory,
224223 .paths = .{
225 .root = .{ .root_dir = comp.zig_lib_directory },
224 .root = .zig_lib_root,
226225 .root_src_path = "",
227226 },
228227 .fully_qualified_name = "root",
......@@ -242,14 +241,10 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
242241 .global = config,
243242 .cc_argv = cc_argv,
244243 .parent = null,
245 .builtin_mod = null,
246 .builtin_modules = null, // there is only one module in this compilation
247244 });
248245
249246 const sub_compilation = try Compilation.create(comp.gpa, arena, .{
250 .local_cache_directory = comp.global_cache_directory,
251 .global_cache_directory = comp.global_cache_directory,
252 .zig_lib_directory = comp.zig_lib_directory,
247 .dirs = comp.dirs.withoutLocalCache(),
253248 .self_exe_path = comp.self_exe_path,
254249 .cache_mode = .whole,
255250 .config = config,
......@@ -266,9 +261,9 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
266261 .verbose_cimport = comp.verbose_cimport,
267262 .verbose_llvm_cpu_features = comp.verbose_llvm_cpu_features,
268263 .clang_passthrough_mode = comp.clang_passthrough_mode,
269 .c_source_files = &[_]Compilation.CSourceFile{
264 .c_source_files = &.{
270265 .{
271 .src_path = try comp.zig_lib_directory.join(arena, &.{ "libc", "musl", "libc.S" }),
266 .src_path = try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "libc.S" }),
272267 .owner = root_mod,
273268 },
274269 },
......@@ -411,25 +406,25 @@ fn addCcArgs(
411406 "-D_XOPEN_SOURCE=700",
412407
413408 "-I",
414 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "arch", arch_name }),
409 try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "arch", arch_name }),
415410
416411 "-I",
417 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "arch", "generic" }),
412 try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "arch", "generic" }),
418413
419414 "-I",
420 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "src", "include" }),
415 try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "src", "include" }),
421416
422417 "-I",
423 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "src", "internal" }),
418 try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "src", "internal" }),
424419
425420 "-I",
426 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "musl", "include" }),
421 try comp.dirs.zig_lib.join(arena, &.{ "libc", "musl", "include" }),
427422
428423 "-I",
429 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", triple }),
424 try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", triple }),
430425
431426 "-I",
432 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", "generic-musl" }),
427 try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", "generic-musl" }),
433428
434429 o_arg,
435430
......@@ -444,7 +439,7 @@ fn addCcArgs(
444439
445440fn start_asm_path(comp: *Compilation, arena: Allocator, basename: []const u8) ![]const u8 {
446441 const target = comp.getTarget();
447 return comp.zig_lib_directory.join(arena, &[_][]const u8{
442 return comp.dirs.zig_lib.join(arena, &.{
448443 "libc", "musl", "crt", std.zig.target.muslArchName(target.cpu.arch, target.abi), basename,
449444 });
450445}
src/libs/wasi_libc.zig+27-27
......@@ -81,7 +81,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
8181 try addLibcBottomHalfIncludes(comp, arena, &args);
8282 var files = [_]Compilation.CSourceFile{
8383 .{
84 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
84 .src_path = try comp.dirs.zig_lib.join(arena, &.{
8585 "libc", try sanitize(arena, crt1_reactor_src_file),
8686 }),
8787 .extra_flags = args.items,
......@@ -96,7 +96,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
9696 try addLibcBottomHalfIncludes(comp, arena, &args);
9797 var files = [_]Compilation.CSourceFile{
9898 .{
99 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
99 .src_path = try comp.dirs.zig_lib.join(arena, &.{
100100 "libc", try sanitize(arena, crt1_command_src_file),
101101 }),
102102 .extra_flags = args.items,
......@@ -114,7 +114,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
114114 try addCCArgs(comp, arena, &args, .{ .want_O3 = true, .no_strict_aliasing = true });
115115 for (emmalloc_src_files) |file_path| {
116116 try libc_sources.append(.{
117 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
117 .src_path = try comp.dirs.zig_lib.join(arena, &.{
118118 "libc", try sanitize(arena, file_path),
119119 }),
120120 .extra_flags = args.items,
......@@ -131,7 +131,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
131131
132132 for (libc_bottom_half_src_files) |file_path| {
133133 try libc_sources.append(.{
134 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
134 .src_path = try comp.dirs.zig_lib.join(arena, &.{
135135 "libc", try sanitize(arena, file_path),
136136 }),
137137 .extra_flags = args.items,
......@@ -148,7 +148,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
148148
149149 for (libc_top_half_src_files) |file_path| {
150150 try libc_sources.append(.{
151 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
151 .src_path = try comp.dirs.zig_lib.join(arena, &.{
152152 "libc", try sanitize(arena, file_path),
153153 }),
154154 .extra_flags = args.items,
......@@ -168,7 +168,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
168168 var emu_dl_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
169169 for (emulated_dl_src_files) |file_path| {
170170 try emu_dl_sources.append(.{
171 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
171 .src_path = try comp.dirs.zig_lib.join(arena, &.{
172172 "libc", try sanitize(arena, file_path),
173173 }),
174174 .extra_flags = args.items,
......@@ -186,7 +186,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
186186 var emu_clocks_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
187187 for (emulated_process_clocks_src_files) |file_path| {
188188 try emu_clocks_sources.append(.{
189 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
189 .src_path = try comp.dirs.zig_lib.join(arena, &.{
190190 "libc", try sanitize(arena, file_path),
191191 }),
192192 .extra_flags = args.items,
......@@ -203,7 +203,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
203203 var emu_getpid_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
204204 for (emulated_getpid_src_files) |file_path| {
205205 try emu_getpid_sources.append(.{
206 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
206 .src_path = try comp.dirs.zig_lib.join(arena, &.{
207207 "libc", try sanitize(arena, file_path),
208208 }),
209209 .extra_flags = args.items,
......@@ -220,7 +220,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
220220 var emu_mman_sources = std.ArrayList(Compilation.CSourceFile).init(arena);
221221 for (emulated_mman_src_files) |file_path| {
222222 try emu_mman_sources.append(.{
223 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
223 .src_path = try comp.dirs.zig_lib.join(arena, &.{
224224 "libc", try sanitize(arena, file_path),
225225 }),
226226 .extra_flags = args.items,
......@@ -238,7 +238,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
238238
239239 for (emulated_signal_bottom_half_src_files) |file_path| {
240240 try emu_signal_sources.append(.{
241 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
241 .src_path = try comp.dirs.zig_lib.join(arena, &.{
242242 "libc", try sanitize(arena, file_path),
243243 }),
244244 .extra_flags = args.items,
......@@ -255,7 +255,7 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre
255255
256256 for (emulated_signal_top_half_src_files) |file_path| {
257257 try emu_signal_sources.append(.{
258 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
258 .src_path = try comp.dirs.zig_lib.join(arena, &.{
259259 "libc", try sanitize(arena, file_path),
260260 }),
261261 .extra_flags = args.items,
......@@ -316,10 +316,10 @@ fn addCCArgs(
316316 "/",
317317
318318 "-iwithsysroot",
319 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", triple }),
319 try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", triple }),
320320
321321 "-iwithsysroot",
322 try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "include", "generic-musl" }),
322 try comp.dirs.zig_lib.join(arena, &.{ "libc", "include", "generic-musl" }),
323323
324324 "-DBULK_MEMORY_THRESHOLD=32",
325325 });
......@@ -336,7 +336,7 @@ fn addLibcBottomHalfIncludes(
336336) error{OutOfMemory}!void {
337337 try args.appendSlice(&[_][]const u8{
338338 "-I",
339 try comp.zig_lib_directory.join(arena, &[_][]const u8{
339 try comp.dirs.zig_lib.join(arena, &.{
340340 "libc",
341341 "wasi",
342342 "libc-bottom-half",
......@@ -345,7 +345,7 @@ fn addLibcBottomHalfIncludes(
345345 }),
346346
347347 "-I",
348 try comp.zig_lib_directory.join(arena, &[_][]const u8{
348 try comp.dirs.zig_lib.join(arena, &.{
349349 "libc",
350350 "wasi",
351351 "libc-bottom-half",
......@@ -355,7 +355,7 @@ fn addLibcBottomHalfIncludes(
355355 }),
356356
357357 "-I",
358 try comp.zig_lib_directory.join(arena, &[_][]const u8{
358 try comp.dirs.zig_lib.join(arena, &.{
359359 "libc",
360360 "wasi",
361361 "libc-bottom-half",
......@@ -364,7 +364,7 @@ fn addLibcBottomHalfIncludes(
364364 }),
365365
366366 "-I",
367 try comp.zig_lib_directory.join(arena, &[_][]const u8{
367 try comp.dirs.zig_lib.join(arena, &.{
368368 "libc",
369369 "wasi",
370370 "libc-top-half",
......@@ -374,7 +374,7 @@ fn addLibcBottomHalfIncludes(
374374 }),
375375
376376 "-I",
377 try comp.zig_lib_directory.join(arena, &[_][]const u8{
377 try comp.dirs.zig_lib.join(arena, &.{
378378 "libc",
379379 "musl",
380380 "src",
......@@ -382,7 +382,7 @@ fn addLibcBottomHalfIncludes(
382382 }),
383383
384384 "-I",
385 try comp.zig_lib_directory.join(arena, &[_][]const u8{
385 try comp.dirs.zig_lib.join(arena, &.{
386386 "libc",
387387 "wasi",
388388 "libc-top-half",
......@@ -392,7 +392,7 @@ fn addLibcBottomHalfIncludes(
392392 }),
393393
394394 "-I",
395 try comp.zig_lib_directory.join(arena, &[_][]const u8{
395 try comp.dirs.zig_lib.join(arena, &.{
396396 "libc",
397397 "musl",
398398 "src",
......@@ -408,7 +408,7 @@ fn addLibcTopHalfIncludes(
408408) error{OutOfMemory}!void {
409409 try args.appendSlice(&[_][]const u8{
410410 "-I",
411 try comp.zig_lib_directory.join(arena, &[_][]const u8{
411 try comp.dirs.zig_lib.join(arena, &.{
412412 "libc",
413413 "wasi",
414414 "libc-top-half",
......@@ -418,7 +418,7 @@ fn addLibcTopHalfIncludes(
418418 }),
419419
420420 "-I",
421 try comp.zig_lib_directory.join(arena, &[_][]const u8{
421 try comp.dirs.zig_lib.join(arena, &.{
422422 "libc",
423423 "musl",
424424 "src",
......@@ -426,7 +426,7 @@ fn addLibcTopHalfIncludes(
426426 }),
427427
428428 "-I",
429 try comp.zig_lib_directory.join(arena, &[_][]const u8{
429 try comp.dirs.zig_lib.join(arena, &.{
430430 "libc",
431431 "wasi",
432432 "libc-top-half",
......@@ -436,7 +436,7 @@ fn addLibcTopHalfIncludes(
436436 }),
437437
438438 "-I",
439 try comp.zig_lib_directory.join(arena, &[_][]const u8{
439 try comp.dirs.zig_lib.join(arena, &.{
440440 "libc",
441441 "musl",
442442 "src",
......@@ -444,7 +444,7 @@ fn addLibcTopHalfIncludes(
444444 }),
445445
446446 "-I",
447 try comp.zig_lib_directory.join(arena, &[_][]const u8{
447 try comp.dirs.zig_lib.join(arena, &.{
448448 "libc",
449449 "wasi",
450450 "libc-top-half",
......@@ -454,7 +454,7 @@ fn addLibcTopHalfIncludes(
454454 }),
455455
456456 "-I",
457 try comp.zig_lib_directory.join(arena, &[_][]const u8{
457 try comp.dirs.zig_lib.join(arena, &.{
458458 "libc",
459459 "musl",
460460 "arch",
......@@ -462,7 +462,7 @@ fn addLibcTopHalfIncludes(
462462 }),
463463
464464 "-I",
465 try comp.zig_lib_directory.join(arena, &[_][]const u8{
465 try comp.dirs.zig_lib.join(arena, &.{
466466 "libc",
467467 "wasi",
468468 "libc-top-half",
src/link.zig+3-3
......@@ -1675,8 +1675,8 @@ pub fn spawnLld(
16751675 const rand_int = std.crypto.random.int(u64);
16761676 const rsp_path = "tmp" ++ s ++ std.fmt.hex(rand_int) ++ ".rsp";
16771677
1678 const rsp_file = try comp.local_cache_directory.handle.createFileZ(rsp_path, .{});
1679 defer comp.local_cache_directory.handle.deleteFileZ(rsp_path) catch |err|
1678 const rsp_file = try comp.dirs.local_cache.handle.createFileZ(rsp_path, .{});
1679 defer comp.dirs.local_cache.handle.deleteFileZ(rsp_path) catch |err|
16801680 log.warn("failed to delete response file {s}: {s}", .{ rsp_path, @errorName(err) });
16811681 {
16821682 defer rsp_file.close();
......@@ -1700,7 +1700,7 @@ pub fn spawnLld(
17001700 var rsp_child = std.process.Child.init(&.{ argv[0], argv[1], try std.fmt.allocPrint(
17011701 arena,
17021702 "@{s}",
1703 .{try comp.local_cache_directory.join(arena, &.{rsp_path})},
1703 .{try comp.dirs.local_cache.join(arena, &.{rsp_path})},
17041704 ) }, arena);
17051705 if (comp.clang_passthrough_mode) {
17061706 rsp_child.stdin_behavior = .Inherit;
src/link/C.zig+4-4
......@@ -206,7 +206,7 @@ pub fn updateFunc(
206206 .dg = .{
207207 .gpa = gpa,
208208 .pt = pt,
209 .mod = zcu.navFileScope(func.owner_nav).mod,
209 .mod = zcu.navFileScope(func.owner_nav).mod.?,
210210 .error_msg = null,
211211 .pass = .{ .nav = func.owner_nav },
212212 .is_naked_fn = Type.fromInterned(func.ty).fnCallingConvention(zcu) == .naked,
......@@ -337,7 +337,7 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) l
337337 .dg = .{
338338 .gpa = gpa,
339339 .pt = pt,
340 .mod = zcu.navFileScope(nav_index).mod,
340 .mod = zcu.navFileScope(nav_index).mod.?,
341341 .error_msg = null,
342342 .pass = .{ .nav = nav_index },
343343 .is_naked_fn = false,
......@@ -490,7 +490,7 @@ pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
490490
491491 for (self.navs.keys(), self.navs.values()) |nav, *av_block| try self.flushAvBlock(
492492 pt,
493 zcu.navFileScope(nav).mod,
493 zcu.navFileScope(nav).mod.?,
494494 &f,
495495 av_block,
496496 self.exported_navs.getPtr(nav),
......@@ -846,7 +846,7 @@ pub fn updateExports(
846846 const gpa = zcu.gpa;
847847 const mod, const pass: codegen.DeclGen.Pass, const decl_block, const exported_block = switch (exported) {
848848 .nav => |nav| .{
849 zcu.navFileScope(nav).mod,
849 zcu.navFileScope(nav).mod.?,
850850 .{ .nav = nav },
851851 self.navs.getPtr(nav).?,
852852 (try self.exported_navs.getOrPut(gpa, nav)).value_ptr,
src/link/Coff.zig+1-1
......@@ -1392,7 +1392,7 @@ fn updateNavCode(
13921392
13931393 log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
13941394
1395 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
1395 const target = zcu.navFileScope(nav_index).mod.?.resolved_target.result;
13961396 const required_alignment = switch (pt.navAlignment(nav_index)) {
13971397 .none => target_util.defaultFunctionAlignment(target),
13981398 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
src/link/Dwarf.zig+17-27
......@@ -34,9 +34,7 @@ pub const UpdateError = error{
3434 std.fs.File.PReadError ||
3535 std.fs.File.PWriteError;
3636
37pub const FlushError =
38 UpdateError ||
39 std.process.GetCwdError;
37pub const FlushError = UpdateError;
4038
4139pub const RelocError =
4240 std.fs.File.PWriteError;
......@@ -967,7 +965,7 @@ const Entry = struct {
967965 const ip = &zcu.intern_pool;
968966 for (dwarf.types.keys(), dwarf.types.values()) |ty, other_entry| {
969967 const ty_unit: Unit.Index = if (Type.fromInterned(ty).typeDeclInst(zcu)) |inst_index|
970 dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod) catch unreachable
968 dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?) catch unreachable
971969 else
972970 .main;
973971 if (sec.getUnit(ty_unit) == unit and unit.getEntry(other_entry) == entry)
......@@ -977,7 +975,7 @@ const Entry = struct {
977975 });
978976 }
979977 for (dwarf.navs.keys(), dwarf.navs.values()) |nav, other_entry| {
980 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod) catch unreachable;
978 const nav_unit = dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav).srcInst(ip).resolveFile(ip)).mod.?) catch unreachable;
981979 if (sec.getUnit(nav_unit) == unit and unit.getEntry(other_entry) == entry)
982980 log.err("missing Nav({}({d}))", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) });
983981 }
......@@ -1620,7 +1618,7 @@ pub const WipNav = struct {
16201618
16211619 const new_func_info = zcu.funcInfo(func);
16221620 const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav);
1623 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod);
1621 const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?);
16241622
16251623 const dlw = wip_nav.debug_line.writer(dwarf.gpa);
16261624 if (dwarf.incremental()) {
......@@ -1810,7 +1808,7 @@ pub const WipNav = struct {
18101808 fn getNavEntry(wip_nav: *WipNav, nav_index: InternPool.Nav.Index) UpdateError!struct { Unit.Index, Entry.Index } {
18111809 const zcu = wip_nav.pt.zcu;
18121810 const ip = &zcu.intern_pool;
1813 const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod);
1811 const unit = try wip_nav.dwarf.getUnit(zcu.fileByIndex(ip.getNav(nav_index).srcInst(ip).resolveFile(ip)).mod.?);
18141812 const gop = try wip_nav.dwarf.navs.getOrPut(wip_nav.dwarf.gpa, nav_index);
18151813 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
18161814 const entry = try wip_nav.dwarf.addCommonEntry(unit);
......@@ -1828,7 +1826,7 @@ pub const WipNav = struct {
18281826 const ip = &zcu.intern_pool;
18291827 const maybe_inst_index = ty.typeDeclInst(zcu);
18301828 const unit = if (maybe_inst_index) |inst_index|
1831 try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod)
1829 try wip_nav.dwarf.getUnit(zcu.fileByIndex(inst_index.resolveFile(ip)).mod.?)
18321830 else
18331831 .main;
18341832 const gop = try wip_nav.dwarf.types.getOrPut(wip_nav.dwarf.gpa, ty.toIntern());
......@@ -2386,7 +2384,7 @@ fn initWipNavInner(
23862384 else => {},
23872385 }
23882386
2389 const unit = try dwarf.getUnit(file.mod);
2387 const unit = try dwarf.getUnit(file.mod.?);
23902388 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
23912389 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
23922390 if (nav_gop.found_existing) {
......@@ -2514,7 +2512,7 @@ fn initWipNavInner(
25142512 try wip_nav.infoAddrSym(sym_index, 0);
25152513 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
25162514 try diw.writeInt(u32, 0, dwarf.endian);
2517 const target = file.mod.resolved_target.result;
2515 const target = file.mod.?.resolved_target.result;
25182516 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
25192517 .none => target_info.defaultFunctionAlignment(target),
25202518 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
......@@ -2726,7 +2724,7 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
27262724 var wip_nav: WipNav = .{
27272725 .dwarf = dwarf,
27282726 .pt = pt,
2729 .unit = try dwarf.getUnit(file.mod),
2727 .unit = try dwarf.getUnit(file.mod.?),
27302728 .entry = undefined,
27312729 .any_children = false,
27322730 .func = .none,
......@@ -4044,7 +4042,7 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
40444042
40454043 const inst_info = ty.typeDeclInst(zcu).?.resolveFull(ip).?;
40464044 const file = zcu.fileByIndex(inst_info.file);
4047 const unit = try dwarf.getUnit(file.mod);
4045 const unit = try dwarf.getUnit(file.mod.?);
40484046 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, inst_info.file);
40494047 if (inst_info.inst == .main_struct_inst) {
40504048 const type_gop = try dwarf.types.getOrPut(dwarf.gpa, type_index);
......@@ -4348,7 +4346,7 @@ pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, zir_index: InternPool.TrackedI
43484346 var line_buf: [4]u8 = undefined;
43494347 std.mem.writeInt(u32, &line_buf, decl.src_line + 1, dwarf.endian);
43504348
4351 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod) orelse return);
4349 const unit = dwarf.debug_info.section.getUnit(dwarf.getUnitIfExists(file.mod.?) orelse return);
43524350 const entry = unit.getEntry(dwarf.decls.get(zir_index) orelse return);
43534351 try dwarf.getFile().?.pwriteAll(&line_buf, dwarf.debug_info.section.off(dwarf) + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
43544352}
......@@ -4418,18 +4416,10 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
44184416 try wip_nav.updateLazy(.unneeded);
44194417 }
44204418
4421 {
4422 const cwd = try std.process.getCwdAlloc(dwarf.gpa);
4423 defer dwarf.gpa.free(cwd);
4424 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4425 const root_dir_path = try std.fs.path.resolve(dwarf.gpa, &.{
4426 cwd,
4427 mod.root.root_dir.path orelse "",
4428 mod.root.sub_path,
4429 });
4430 defer dwarf.gpa.free(root_dir_path);
4431 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
4432 }
4419 for (dwarf.mods.keys(), dwarf.mods.values()) |mod, *mod_info| {
4420 const root_dir_path = try mod.root.toAbsolute(zcu.comp.dirs, dwarf.gpa);
4421 defer dwarf.gpa.free(root_dir_path);
4422 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
44334423 }
44344424
44354425 var header = std.ArrayList(u8).init(dwarf.gpa);
......@@ -4687,7 +4677,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
46874677 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
46884678 dwarf.writeInt(
46894679 header.addManyAsSliceAssumeCapacity(dir_index_info.bytes),
4690 mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod).?).?,
4680 mod_info.dirs.getIndex(dwarf.getUnitIfExists(file.mod.?).?) orelse 0,
46914681 );
46924682 unit.cross_section_relocs.appendAssumeCapacity(.{
46934683 .source_off = @intCast(header.items.len),
......@@ -4695,7 +4685,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
46954685 .target_unit = StringSection.unit,
46964686 .target_entry = (try dwarf.debug_line_str.addString(
46974687 dwarf,
4698 if (file.mod.builtin_file == file) file.source.? else "",
4688 if (file.is_builtin) file.source.? else "",
46994689 )).toOptional(),
47004690 });
47014691 header.appendNTimesAssumeCapacity(0, dwarf.sectionOffsetBytes());
src/link/Elf/ZigObject.zig+2-2
......@@ -1201,7 +1201,7 @@ fn getNavShdrIndex(
12011201 return osec;
12021202 }
12031203 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
1204 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
1204 return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) {
12051205 .Debug, .ReleaseSafe => {
12061206 if (self.data_index) |symbol_index|
12071207 return self.symbol(symbol_index).outputShndx(elf_file).?;
......@@ -1271,7 +1271,7 @@ fn updateNavCode(
12711271
12721272 log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index });
12731273
1274 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
1274 const target = zcu.navFileScope(nav_index).mod.?.resolved_target.result;
12751275 const required_alignment = switch (pt.navAlignment(nav_index)) {
12761276 .none => target_util.defaultFunctionAlignment(target),
12771277 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
src/link/MachO.zig+3-3
......@@ -867,11 +867,11 @@ pub fn resolveLibSystem(
867867 success: {
868868 if (self.sdk_layout) |sdk_layout| switch (sdk_layout) {
869869 .sdk => {
870 const dir = try fs.path.join(arena, &[_][]const u8{ comp.sysroot.?, "usr", "lib" });
870 const dir = try fs.path.join(arena, &.{ comp.sysroot.?, "usr", "lib" });
871871 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
872872 },
873873 .vendored => {
874 const dir = try comp.zig_lib_directory.join(arena, &[_][]const u8{ "libc", "darwin" });
874 const dir = try comp.dirs.zig_lib.join(arena, &.{ "libc", "darwin" });
875875 if (try accessLibPath(arena, &test_path, &checked_paths, dir, "System")) break :success;
876876 },
877877 };
......@@ -4406,7 +4406,7 @@ fn inferSdkVersion(comp: *Compilation, sdk_layout: SdkLayout) ?std.SemanticVersi
44064406
44074407 const sdk_dir = switch (sdk_layout) {
44084408 .sdk => comp.sysroot.?,
4409 .vendored => fs.path.join(arena, &.{ comp.zig_lib_directory.path.?, "libc", "darwin" }) catch return null,
4409 .vendored => fs.path.join(arena, &.{ comp.dirs.zig_lib.path.?, "libc", "darwin" }) catch return null,
44104410 };
44114411 if (readSdkVersionFromSettings(arena, sdk_dir)) |ver| {
44124412 return parseSdkVersion(ver);
src/link/MachO/ZigObject.zig+2-2
......@@ -954,7 +954,7 @@ fn updateNavCode(
954954
955955 log.debug("updateNavCode {} 0x{x}", .{ nav.fqn.fmt(ip), nav_index });
956956
957 const target = zcu.navFileScope(nav_index).mod.resolved_target.result;
957 const target = zcu.navFileScope(nav_index).mod.?.resolved_target.result;
958958 const required_alignment = switch (pt.navAlignment(nav_index)) {
959959 .none => target_util.defaultFunctionAlignment(target),
960960 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
......@@ -1184,7 +1184,7 @@ fn getNavOutputSection(
11841184 }
11851185 if (is_const) return macho_file.zig_const_sect_index.?;
11861186 if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
1187 return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
1187 return switch (zcu.navFileScope(nav_index).mod.?.optimize_mode) {
11881188 .Debug, .ReleaseSafe => macho_file.zig_data_sect_index.?,
11891189 .ReleaseFast, .ReleaseSmall => macho_file.zig_bss_sect_index.?,
11901190 };
src/link/Plan9.zig+9-13
......@@ -315,8 +315,9 @@ pub fn createEmpty(
315315}
316316
317317fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void {
318 const gpa = self.base.comp.gpa;
319 const zcu = self.base.comp.zcu.?;
318 const comp = self.base.comp;
319 const gpa = comp.gpa;
320 const zcu = comp.zcu.?;
320321 const file_scope = zcu.navFileScopeIndex(nav_index);
321322 const fn_map_res = try self.fn_nav_table.getOrPut(gpa, file_scope);
322323 if (fn_map_res.found_existing) {
......@@ -345,14 +346,11 @@ fn putFn(self: *Plan9, nav_index: InternPool.Nav.Index, out: FnNavOutput) !void
345346 try a.writer().writeInt(u16, 1, .big);
346347
347348 // getting the full file path
348 // TODO don't call getcwd here, that is inappropriate
349 var buf: [std.fs.max_path_bytes]u8 = undefined;
350 const full_path = try std.fs.path.join(arena, &.{
351 file.mod.root.root_dir.path orelse try std.posix.getcwd(&buf),
352 file.mod.root.sub_path,
353 file.sub_file_path,
354 });
355 try self.addPathComponents(full_path, &a);
349 {
350 const full_path = try file.path.toAbsolute(comp.dirs, gpa);
351 defer gpa.free(full_path);
352 try self.addPathComponents(full_path, &a);
353 }
356354
357355 // null terminate
358356 try a.append(0);
......@@ -437,9 +435,7 @@ pub fn updateFunc(
437435 .start_line = dbg_info_output.start_line.?,
438436 .end_line = dbg_info_output.end_line,
439437 };
440 // The awkward error handling here is due to putFn calling `std.posix.getcwd` which it should not do.
441 self.putFn(func.owner_nav, out) catch |err|
442 return zcu.codegenFail(func.owner_nav, "failed to put fn: {s}", .{@errorName(err)});
438 try self.putFn(func.owner_nav, out);
443439 return self.updateFinish(pt, func.owner_nav);
444440}
445441
src/main.zig+228-549
......@@ -63,19 +63,7 @@ pub fn wasi_cwd() std.os.wasi.fd_t {
6363 return cwd_fd;
6464}
6565
66fn getWasiPreopen(name: []const u8) Directory {
67 return .{
68 .path = name,
69 .handle = .{
70 .fd = wasi_preopens.find(name) orelse fatal("WASI preopen not found: '{s}'", .{name}),
71 },
72 };
73}
74
75pub fn fatal(comptime format: []const u8, args: anytype) noreturn {
76 std.log.err(format, args);
77 process.exit(1);
78}
66const fatal = std.process.fatal;
7967
8068/// Shaming all the locations that inappropriately use an O(N) search algorithm.
8169/// Please delete this and fix the compilation errors!
......@@ -136,7 +124,6 @@ const debug_usage = normal_usage ++
136124;
137125
138126const usage = if (build_options.enable_debug_extensions) debug_usage else normal_usage;
139const default_local_zig_cache_basename = ".zig-cache";
140127
141128var log_scopes: std.ArrayListUnmanaged([]const u8) = .empty;
142129
......@@ -377,13 +364,13 @@ fn mainArgs(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
377364 dev.check(.help_command);
378365 return io.getStdOut().writeAll(usage);
379366 } else if (mem.eql(u8, cmd, "ast-check")) {
380 return cmdAstCheck(gpa, arena, cmd_args);
367 return cmdAstCheck(arena, cmd_args);
381368 } else if (mem.eql(u8, cmd, "detect-cpu")) {
382 return cmdDetectCpu(gpa, arena, cmd_args);
369 return cmdDetectCpu(cmd_args);
383370 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "changelist")) {
384 return cmdChangelist(gpa, arena, cmd_args);
371 return cmdChangelist(arena, cmd_args);
385372 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "dump-zir")) {
386 return cmdDumpZir(gpa, arena, cmd_args);
373 return cmdDumpZir(arena, cmd_args);
387374 } else if (build_options.enable_debug_extensions and mem.eql(u8, cmd, "llvm-ints")) {
388375 return cmdDumpLlvmInts(gpa, arena, cmd_args);
389376 } else {
......@@ -809,7 +796,8 @@ const Framework = struct {
809796};
810797
811798const CliModule = struct {
812 paths: Package.Module.CreateOptions.Paths,
799 root_path: []const u8,
800 root_src_path: []const u8,
813801 cc_argv: []const []const u8,
814802 inherited: Package.Module.CreateOptions.Inherited,
815803 target_arch_os_abi: ?[]const u8,
......@@ -976,7 +964,7 @@ fn buildOutputType(
976964 // error output consistent. "root" is special.
977965 var create_module: CreateModule = .{
978966 // Populated just before the call to `createModule`.
979 .global_cache_directory = undefined,
967 .dirs = undefined,
980968 .object_format = null,
981969 .dynamic_linker = null,
982970 .modules = .{},
......@@ -1859,7 +1847,7 @@ fn buildOutputType(
18591847 } else root_src_file = arg;
18601848 },
18611849 .def, .unknown => {
1862 if (std.ascii.eqlIgnoreCase(".xml", std.fs.path.extension(arg))) {
1850 if (std.ascii.eqlIgnoreCase(".xml", fs.path.extension(arg))) {
18631851 warn("embedded manifest files must have the extension '.manifest'", .{});
18641852 }
18651853 fatal("unrecognized file extension of parameter '{s}'", .{arg});
......@@ -2924,13 +2912,14 @@ fn buildOutputType(
29242912 }
29252913
29262914 implicit_root_mod: {
2927 const unresolved_src_path = b: {
2915 const src_path = b: {
29282916 if (root_src_file) |src_path| {
29292917 if (create_module.modules.count() != 0) {
2930 fatal("main module provided both by '-M{s}={}{s}' and by positional argument '{s}'", .{
2918 fatal("main module provided both by '-M{s}={s}{c}{s}' and by positional argument '{s}'", .{
29312919 create_module.modules.keys()[0],
2932 create_module.modules.values()[0].paths.root,
2933 create_module.modules.values()[0].paths.root_src_path,
2920 create_module.modules.values()[0].root_path,
2921 fs.path.sep,
2922 create_module.modules.values()[0].root_src_path,
29342923 src_path,
29352924 });
29362925 }
......@@ -2987,20 +2976,14 @@ fn buildOutputType(
29872976 if (mod_opts.error_tracing == true)
29882977 create_module.opts.any_error_tracing = true;
29892978
2990 const src_path = try introspect.resolvePath(arena, unresolved_src_path);
29912979 const name = switch (arg_mode) {
29922980 .zig_test => "test",
29932981 .build, .cc, .cpp, .translate_c, .zig_test_obj, .run => fs.path.stem(fs.path.basename(src_path)),
29942982 };
29952983
29962984 try create_module.modules.put(arena, name, .{
2997 .paths = .{
2998 .root = .{
2999 .root_dir = Cache.Directory.cwd(),
3000 .sub_path = fs.path.dirname(src_path) orelse "",
3001 },
3002 .root_src_path = fs.path.basename(src_path),
3003 },
2985 .root_path = fs.path.dirname(src_path) orelse ".",
2986 .root_src_path = fs.path.basename(src_path),
30042987 .cc_argv = try cc_argv.toOwnedSlice(arena),
30052988 .inherited = mod_opts,
30062989 .target_arch_os_abi = target_arch_os_abi,
......@@ -3036,85 +3019,50 @@ fn buildOutputType(
30363019 });
30373020 }
30383021
3039 const self_exe_path: ?[]const u8 = if (!process.can_spawn)
3040 null
3041 else
3042 introspect.findZigExePath(arena) catch |err| {
3022 const self_exe_path = switch (native_os) {
3023 .wasi => {},
3024 else => fs.selfExePathAlloc(arena) catch |err| {
30433025 fatal("unable to find zig self exe path: {s}", .{@errorName(err)});
3044 };
3045
3046 var zig_lib_directory: Directory = d: {
3047 if (override_lib_dir) |unresolved_lib_dir| {
3048 const lib_dir = try introspect.resolvePath(arena, unresolved_lib_dir);
3049 break :d .{
3050 .path = lib_dir,
3051 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
3052 fatal("unable to open zig lib directory '{s}': {s}", .{ lib_dir, @errorName(err) });
3053 },
3054 };
3055 } else if (native_os == .wasi) {
3056 break :d getWasiPreopen("/lib");
3057 } else if (self_exe_path) |p| {
3058 break :d introspect.findZigLibDirFromSelfExe(arena, p) catch |err| {
3059 fatal("unable to find zig installation directory '{s}': {s}", .{ p, @errorName(err) });
3060 };
3061 } else {
3062 unreachable;
3063 }
3026 },
30643027 };
3065 defer zig_lib_directory.handle.close();
30663028
3067 var global_cache_directory: Directory = l: {
3068 if (override_global_cache_dir) |p| {
3069 break :l .{
3070 .handle = try fs.cwd().makeOpenPath(p, .{}),
3071 .path = p,
3029 // This `init` calls `fatal` on error.
3030 var dirs: Compilation.Directories = .init(
3031 arena,
3032 override_lib_dir,
3033 override_global_cache_dir,
3034 s: {
3035 if (override_local_cache_dir) |p| break :s .{ .override = p };
3036 break :s switch (arg_mode) {
3037 .run => .global,
3038 else => .search,
30723039 };
3073 }
3074 if (native_os == .wasi) {
3075 break :l getWasiPreopen("/cache");
3076 }
3077 const p = try introspect.resolveGlobalCacheDir(arena);
3078 break :l .{
3079 .handle = try fs.cwd().makeOpenPath(p, .{}),
3080 .path = p,
3081 };
3082 };
3083 defer global_cache_directory.handle.close();
3040 },
3041 if (native_os == .wasi) wasi_preopens,
3042 self_exe_path,
3043 );
3044 defer dirs.deinit();
30843045
30853046 if (linker_optimization) |o| {
30863047 warn("ignoring deprecated linker optimization setting '{s}'", .{o});
30873048 }
30883049
3089 create_module.global_cache_directory = global_cache_directory;
3050 create_module.dirs = dirs;
30903051 create_module.opts.emit_llvm_ir = emit_llvm_ir != .no;
30913052 create_module.opts.emit_llvm_bc = emit_llvm_bc != .no;
30923053 create_module.opts.emit_bin = emit_bin != .no;
30933054 create_module.opts.any_c_source_files = create_module.c_source_files.items.len != 0;
30943055
3095 var builtin_modules: std.StringHashMapUnmanaged(*Package.Module) = .empty;
3096 // `builtin_modules` allocated into `arena`, so no deinit
3097 const main_mod = try createModule(gpa, arena, &create_module, 0, null, zig_lib_directory, &builtin_modules, color);
3056 const main_mod = try createModule(gpa, arena, &create_module, 0, null, color);
30983057 for (create_module.modules.keys(), create_module.modules.values()) |key, cli_mod| {
30993058 if (cli_mod.resolved == null)
31003059 fatal("module '{s}' declared but not used", .{key});
31013060 }
31023061
3103 // When you're testing std, the main module is std. In that case,
3104 // we'll just set the std module to the main one, since avoiding
3105 // the errors caused by duplicating it is more effort than it's
3106 // worth.
3107 const main_mod_is_std = m: {
3108 const std_path = try fs.path.resolve(arena, &.{
3109 zig_lib_directory.path orelse ".", "std", "std.zig",
3110 });
3111 const main_path = try fs.path.resolve(arena, &.{
3112 main_mod.root.root_dir.path orelse ".",
3113 main_mod.root.sub_path,
3114 main_mod.root_src_path,
3115 });
3116 break :m mem.eql(u8, main_path, std_path);
3117 };
3062 // When you're testing std, the main module is std, and we need to avoid duplicating the module.
3063 const main_mod_is_std = main_mod.root.root == .zig_lib and
3064 mem.eql(u8, main_mod.root.sub_path, "std") and
3065 mem.eql(u8, main_mod.root_src_path, "std.zig");
31183066
31193067 const std_mod = m: {
31203068 if (main_mod_is_std) break :m main_mod;
......@@ -3126,12 +3074,8 @@ fn buildOutputType(
31263074 .zig_test, .zig_test_obj => root_mod: {
31273075 const test_mod = if (test_runner_path) |test_runner| test_mod: {
31283076 const test_mod = try Package.Module.create(arena, .{
3129 .global_cache_directory = global_cache_directory,
31303077 .paths = .{
3131 .root = .{
3132 .root_dir = Cache.Directory.cwd(),
3133 .sub_path = fs.path.dirname(test_runner) orelse "",
3134 },
3078 .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(test_runner) orelse "."}),
31353079 .root_src_path = fs.path.basename(test_runner),
31363080 },
31373081 .fully_qualified_name = "root",
......@@ -3139,18 +3083,12 @@ fn buildOutputType(
31393083 .inherited = .{},
31403084 .global = create_module.resolved_options,
31413085 .parent = main_mod,
3142 .builtin_mod = main_mod.getBuiltinDependency(),
3143 .builtin_modules = null, // `builtin_mod` is specified
31443086 });
31453087 test_mod.deps = try main_mod.deps.clone(arena);
31463088 break :test_mod test_mod;
31473089 } else try Package.Module.create(arena, .{
3148 .global_cache_directory = global_cache_directory,
31493090 .paths = .{
3150 .root = .{
3151 .root_dir = zig_lib_directory,
3152 .sub_path = "compiler",
3153 },
3091 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
31543092 .root_src_path = "test_runner.zig",
31553093 },
31563094 .fully_qualified_name = "root",
......@@ -3158,8 +3096,6 @@ fn buildOutputType(
31583096 .inherited = .{},
31593097 .global = create_module.resolved_options,
31603098 .parent = main_mod,
3161 .builtin_mod = main_mod.getBuiltinDependency(),
3162 .builtin_modules = null, // `builtin_mod` is specified
31633099 });
31643100
31653101 break :root_mod test_mod;
......@@ -3469,50 +3405,6 @@ fn buildOutputType(
34693405 });
34703406 defer thread_pool.deinit();
34713407
3472 var cleanup_local_cache_dir: ?fs.Dir = null;
3473 defer if (cleanup_local_cache_dir) |*dir| dir.close();
3474
3475 var local_cache_directory: Directory = l: {
3476 if (override_local_cache_dir) |local_cache_dir_path| {
3477 const dir = try fs.cwd().makeOpenPath(local_cache_dir_path, .{});
3478 cleanup_local_cache_dir = dir;
3479 break :l .{
3480 .handle = dir,
3481 .path = local_cache_dir_path,
3482 };
3483 }
3484 if (arg_mode == .run) {
3485 break :l global_cache_directory;
3486 }
3487
3488 // search upwards from cwd until we find directory with build.zig
3489 const cwd_path = try process.getCwdAlloc(arena);
3490 var dirname: []const u8 = cwd_path;
3491 while (true) {
3492 const joined_path = try fs.path.join(arena, &.{
3493 dirname, Package.build_zig_basename,
3494 });
3495 if (fs.cwd().access(joined_path, .{})) |_| {
3496 const cache_dir_path = try fs.path.join(arena, &.{ dirname, default_local_zig_cache_basename });
3497 const dir = try fs.cwd().makeOpenPath(cache_dir_path, .{});
3498 cleanup_local_cache_dir = dir;
3499 break :l .{ .handle = dir, .path = cache_dir_path };
3500 } else |err| switch (err) {
3501 error.FileNotFound => {
3502 dirname = fs.path.dirname(dirname) orelse {
3503 break :l global_cache_directory;
3504 };
3505 continue;
3506 },
3507 else => break :l global_cache_directory,
3508 }
3509 }
3510
3511 // Otherwise we really don't have a reasonable place to put the local cache directory,
3512 // so we utilize the global one.
3513 break :l global_cache_directory;
3514 };
3515
35163408 for (create_module.c_source_files.items) |*src| {
35173409 if (!mem.eql(u8, src.src_path, "-")) continue;
35183410
......@@ -3524,14 +3416,14 @@ fn buildOutputType(
35243416 const dump_path = try std.fmt.allocPrint(arena, "tmp" ++ sep ++ "{x}-dump-stdin{s}", .{
35253417 std.crypto.random.int(u64), ext.canonicalName(target),
35263418 });
3527 try local_cache_directory.handle.makePath("tmp");
3419 try dirs.local_cache.handle.makePath("tmp");
35283420
35293421 // Note that in one of the happy paths, execve() is used to switch to
35303422 // clang in which case any cleanup logic that exists for this temporary
35313423 // file will not run and this temp file will be leaked. The filename
35323424 // will be a hash of its contents — so multiple invocations of
35333425 // `zig cc -` will result in the same temp file name.
3534 var f = try local_cache_directory.handle.createFile(dump_path, .{});
3426 var f = try dirs.local_cache.handle.createFile(dump_path, .{});
35353427 defer f.close();
35363428
35373429 // Re-using the hasher from Cache, since the functional requirements
......@@ -3550,10 +3442,10 @@ fn buildOutputType(
35503442 std.fmt.fmtSliceHexLower(&bin_digest),
35513443 ext.canonicalName(target),
35523444 });
3553 try local_cache_directory.handle.rename(dump_path, sub_path);
3445 try dirs.local_cache.handle.rename(dump_path, sub_path);
35543446
35553447 // Convert `sub_path` to be relative to current working directory.
3556 src.src_path = try local_cache_directory.join(arena, &.{sub_path});
3448 src.src_path = try dirs.local_cache.join(arena, &.{sub_path});
35573449 }
35583450
35593451 if (build_options.have_llvm and emit_asm != .no) {
......@@ -3595,11 +3487,12 @@ fn buildOutputType(
35953487 defer file_system_inputs.deinit(gpa);
35963488
35973489 const comp = Compilation.create(gpa, arena, .{
3598 .zig_lib_directory = zig_lib_directory,
3599 .local_cache_directory = local_cache_directory,
3600 .global_cache_directory = global_cache_directory,
3490 .dirs = dirs,
36013491 .thread_pool = &thread_pool,
3602 .self_exe_path = self_exe_path,
3492 .self_exe_path = switch (native_os) {
3493 .wasi => null,
3494 else => self_exe_path,
3495 },
36033496 .config = create_module.resolved_options,
36043497 .root_name = root_name,
36053498 .sysroot = create_module.sysroot,
......@@ -3757,14 +3650,17 @@ fn buildOutputType(
37573650 error.ExportTableAndImportTableConflict => {
37583651 fatal("--import-table and --export-table may not be used together", .{});
37593652 },
3653 error.IllegalZigImport => {
3654 fatal("this compiler implementation does not support importing the root source file of a provided module", .{});
3655 },
37603656 else => fatal("unable to create compilation: {s}", .{@errorName(err)}),
37613657 };
37623658 var comp_destroyed = false;
37633659 defer if (!comp_destroyed) comp.destroy();
37643660
37653661 if (show_builtin) {
3766 const builtin_mod = comp.root_mod.getBuiltinDependency();
3767 const source = builtin_mod.builtin_file.?.source.?;
3662 const builtin_opts = comp.root_mod.getBuiltinOptions(comp.config);
3663 const source = try builtin_opts.generate(arena);
37683664 return std.io.getStdOut().writeAll(source);
37693665 }
37703666 switch (listen) {
......@@ -3844,7 +3740,7 @@ fn buildOutputType(
38443740 c_code_directory.path orelse ".", c_code_loc.basename,
38453741 });
38463742 try test_exec_args.appendSlice(arena, &.{ self_exe_path, "run" });
3847 if (zig_lib_directory.path) |p| {
3743 if (dirs.zig_lib.path) |p| {
38483744 try test_exec_args.appendSlice(arena, &.{ "-I", p });
38493745 }
38503746
......@@ -3875,7 +3771,7 @@ fn buildOutputType(
38753771 gpa,
38763772 arena,
38773773 test_exec_args.items,
3878 self_exe_path.?,
3774 self_exe_path,
38793775 arg_mode,
38803776 &target,
38813777 &comp_destroyed,
......@@ -3890,7 +3786,7 @@ fn buildOutputType(
38903786}
38913787
38923788const CreateModule = struct {
3893 global_cache_directory: Cache.Directory,
3789 dirs: Compilation.Directories,
38943790 modules: std.StringArrayHashMapUnmanaged(CliModule),
38953791 opts: Compilation.Config.Options,
38963792 dynamic_linker: ?[]const u8,
......@@ -3937,8 +3833,6 @@ fn createModule(
39373833 create_module: *CreateModule,
39383834 index: usize,
39393835 parent: ?*Package.Module,
3940 zig_lib_directory: Cache.Directory,
3941 builtin_modules: *std.StringHashMapUnmanaged(*Package.Module),
39423836 color: std.zig.Color,
39433837) Allocator.Error!*Package.Module {
39443838 const cli_mod = &create_module.modules.values()[index];
......@@ -4069,7 +3963,7 @@ fn createModule(
40693963 }
40703964
40713965 if (target.isMinGW()) {
4072 const exists = mingw.libExists(arena, target, zig_lib_directory, lib_name) catch |err| {
3966 const exists = mingw.libExists(arena, target, create_module.dirs.zig_lib, lib_name) catch |err| {
40733967 fatal("failed to check zig installation for DLL import libs: {s}", .{
40743968 @errorName(err),
40753969 });
......@@ -4225,17 +4119,19 @@ fn createModule(
42254119 };
42264120 }
42274121
4122 const root: Compilation.Path = try .fromUnresolved(arena, create_module.dirs, &.{cli_mod.root_path});
4123
42284124 const mod = Package.Module.create(arena, .{
4229 .global_cache_directory = create_module.global_cache_directory,
4230 .paths = cli_mod.paths,
4125 .paths = .{
4126 .root = root,
4127 .root_src_path = cli_mod.root_src_path,
4128 },
42314129 .fully_qualified_name = name,
42324130
42334131 .cc_argv = cli_mod.cc_argv,
42344132 .inherited = cli_mod.inherited,
42354133 .global = create_module.resolved_options,
42364134 .parent = parent,
4237 .builtin_mod = null,
4238 .builtin_modules = builtin_modules,
42394135 }) catch |err| switch (err) {
42404136 error.ValgrindUnsupportedOnTarget => fatal("unable to create module '{s}': valgrind does not support the selected target CPU architecture", .{name}),
42414137 error.TargetRequiresSingleThreaded => fatal("unable to create module '{s}': the selected target does not support multithreading", .{name}),
......@@ -4258,7 +4154,7 @@ fn createModule(
42584154 for (cli_mod.deps) |dep| {
42594155 const dep_index = create_module.modules.getIndex(dep.value) orelse
42604156 fatal("module '{s}' depends on non-existent module '{s}'", .{ name, dep.key });
4261 const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, zig_lib_directory, builtin_modules, color);
4157 const dep_mod = try createModule(gpa, arena, create_module, dep_index, mod, color);
42624158 try mod.deps.put(arena, dep.key, dep_mod);
42634159 }
42644160
......@@ -4544,15 +4440,13 @@ fn runOrTestHotSwap(
45444440 // tmp zig-cache and use it to spawn the child process. This way we are free to update
45454441 // the binary with each requested hot update.
45464442 .windows => blk: {
4547 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.local_cache_directory.handle, lf.emit.sub_path, .{});
4548 break :blk try fs.path.join(gpa, &[_][]const u8{
4549 comp.local_cache_directory.path orelse ".", lf.emit.sub_path,
4550 });
4443 try lf.emit.root_dir.handle.copyFile(lf.emit.sub_path, comp.dirs.local_cache.handle, lf.emit.sub_path, .{});
4444 break :blk try fs.path.join(gpa, &.{ comp.dirs.local_cache.path orelse ".", lf.emit.sub_path });
45514445 },
45524446
45534447 // A naive `directory.join` here will indeed get the correct path to the binary,
45544448 // however, in the case of cwd, we actually want `./foo` so that the path can be executed.
4555 else => try fs.path.join(gpa, &[_][]const u8{
4449 else => try fs.path.join(gpa, &.{
45564450 lf.emit.root_dir.path orelse ".", lf.emit.sub_path,
45574451 }),
45584452 };
......@@ -4679,7 +4573,7 @@ fn cmdTranslateC(
46794573 },
46804574 }
46814575
4682 var zig_cache_tmp_dir = try comp.local_cache_directory.handle.makeOpenPath("tmp", .{});
4576 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.makeOpenPath("tmp", .{});
46834577 defer zig_cache_tmp_dir.close();
46844578
46854579 const ext = Compilation.classifyFileExt(c_source_file.src_path);
......@@ -4735,7 +4629,7 @@ fn cmdTranslateC(
47354629 new_argv[argv.items.len + i] = try arena.dupeZ(u8, arg);
47364630 }
47374631
4738 const c_headers_dir_path_z = try comp.zig_lib_directory.joinZ(arena, &[_][]const u8{"include"});
4632 const c_headers_dir_path_z = try comp.dirs.zig_lib.joinZ(arena, &.{"include"});
47394633 var errors = std.zig.ErrorBundle.empty;
47404634 var tree = translate_c.translate(
47414635 comp.gpa,
......@@ -4787,7 +4681,7 @@ fn cmdTranslateC(
47874681
47884682 const o_sub_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest });
47894683
4790 var o_dir = try comp.local_cache_directory.handle.makeOpenPath(o_sub_path, .{});
4684 var o_dir = try comp.dirs.local_cache.handle.makeOpenPath(o_sub_path, .{});
47914685 defer o_dir.close();
47924686
47934687 var zig_file = try o_dir.createFile(translated_zig_basename, .{});
......@@ -4808,9 +4702,9 @@ fn cmdTranslateC(
48084702 p.digest = bin_digest;
48094703 p.errors = std.zig.ErrorBundle.empty;
48104704 } else {
4811 const out_zig_path = try fs.path.join(arena, &[_][]const u8{ "o", &hex_digest, translated_zig_basename });
4812 const zig_file = comp.local_cache_directory.handle.openFile(out_zig_path, .{}) catch |err| {
4813 const path = comp.local_cache_directory.path orelse ".";
4705 const out_zig_path = try fs.path.join(arena, &.{ "o", &hex_digest, translated_zig_basename });
4706 const zig_file = comp.dirs.local_cache.handle.openFile(out_zig_path, .{}) catch |err| {
4707 const path = comp.dirs.local_cache.path orelse ".";
48144708 fatal("unable to open cached translated zig file '{s}{s}{s}': {s}", .{ path, fs.path.sep_str, out_zig_path, @errorName(err) });
48154709 };
48164710 defer zig_file.close();
......@@ -4854,7 +4748,7 @@ fn cmdInit(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
48544748 var templates = findTemplates(gpa, arena);
48554749 defer templates.deinit();
48564750
4857 const cwd_path = try process.getCwdAlloc(arena);
4751 const cwd_path = try introspect.getResolvedCwd(arena);
48584752 const cwd_basename = fs.path.basename(cwd_path);
48594753 const sanitized_root_name = try sanitizeExampleName(arena, cwd_basename);
48604754
......@@ -4952,7 +4846,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
49524846 const argv_index_exe = child_argv.items.len;
49534847 _ = try child_argv.addOne();
49544848
4955 const self_exe_path = try introspect.findZigExePath(arena);
4849 const self_exe_path = try fs.selfExePathAlloc(arena);
49564850 try child_argv.append(self_exe_path);
49574851
49584852 const argv_index_zig_lib_dir = child_argv.items.len;
......@@ -5169,60 +5063,30 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
51695063
51705064 process.raiseFileDescriptorLimit();
51715065
5172 var zig_lib_directory: Directory = if (override_lib_dir) |lib_dir| .{
5173 .path = lib_dir,
5174 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5175 fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
5176 },
5177 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
5178 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
5179 };
5180 defer zig_lib_directory.handle.close();
5181
5182 const cwd_path = try process.getCwdAlloc(arena);
5183 child_argv.items[argv_index_zig_lib_dir] = zig_lib_directory.path orelse cwd_path;
5184
5066 const cwd_path = try introspect.getResolvedCwd(arena);
51855067 const build_root = try findBuildRoot(arena, .{
51865068 .cwd_path = cwd_path,
51875069 .build_file = build_file,
51885070 });
5189 child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
5190
5191 var global_cache_directory: Directory = l: {
5192 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
5193 const dir = fs.cwd().makeOpenPath(p, .{}) catch |err| {
5194 const base_msg = "unable to open or create the global Zig cache at '{s}': {s}.{s}";
5195 const extra = "\nIf this location is not writable then consider specifying an " ++
5196 "alternative with the ZIG_GLOBAL_CACHE_DIR environment variable or the " ++
5197 "--global-cache-dir option.";
5198 const show_extra = err == error.AccessDenied or err == error.ReadOnlyFileSystem;
5199 fatal(base_msg, .{ p, @errorName(err), if (show_extra) extra else "" });
5200 };
5201 break :l .{
5202 .handle = dir,
5203 .path = p,
5204 };
5205 };
5206 defer global_cache_directory.handle.close();
52075071
5208 child_argv.items[argv_index_global_cache_dir] = global_cache_directory.path orelse cwd_path;
5209
5210 var local_cache_directory: Directory = l: {
5211 if (override_local_cache_dir) |local_cache_dir_path| {
5212 break :l .{
5213 .handle = try fs.cwd().makeOpenPath(local_cache_dir_path, .{}),
5214 .path = local_cache_dir_path,
5215 };
5216 }
5217 const cache_dir_path = try build_root.directory.join(arena, &.{default_local_zig_cache_basename});
5218 break :l .{
5219 .handle = try build_root.directory.handle.makeOpenPath(default_local_zig_cache_basename, .{}),
5220 .path = cache_dir_path,
5221 };
5222 };
5223 defer local_cache_directory.handle.close();
5072 // This `init` calls `fatal` on error.
5073 var dirs: Compilation.Directories = .init(
5074 arena,
5075 override_lib_dir,
5076 override_global_cache_dir,
5077 .{ .override = path: {
5078 if (override_local_cache_dir) |d| break :path d;
5079 break :path try build_root.directory.join(arena, &.{introspect.default_local_zig_cache_basename});
5080 } },
5081 {},
5082 self_exe_path,
5083 );
5084 defer dirs.deinit();
52245085
5225 child_argv.items[argv_index_cache_dir] = local_cache_directory.path orelse cwd_path;
5086 child_argv.items[argv_index_zig_lib_dir] = dirs.zig_lib.path orelse cwd_path;
5087 child_argv.items[argv_index_build_file] = build_root.directory.path orelse cwd_path;
5088 child_argv.items[argv_index_global_cache_dir] = dirs.global_cache.path orelse cwd_path;
5089 child_argv.items[argv_index_cache_dir] = dirs.local_cache.path orelse cwd_path;
52265090
52275091 var thread_pool: ThreadPool = undefined;
52285092 try thread_pool.init(.{
......@@ -5250,16 +5114,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52505114 // big block here to ensure the cleanup gets run when we extract out our argv.
52515115 {
52525116 const main_mod_paths: Package.Module.CreateOptions.Paths = if (override_build_runner) |runner| .{
5253 .root = .{
5254 .root_dir = Cache.Directory.cwd(),
5255 .sub_path = fs.path.dirname(runner) orelse "",
5256 },
5117 .root = try .fromUnresolved(arena, dirs, &.{fs.path.dirname(runner) orelse "."}),
52575118 .root_src_path = fs.path.basename(runner),
52585119 } else .{
5259 .root = .{
5260 .root_dir = zig_lib_directory,
5261 .sub_path = "compiler",
5262 },
5120 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
52635121 .root_src_path = "build_runner.zig",
52645122 };
52655123
......@@ -5272,7 +5130,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52725130 });
52735131
52745132 const root_mod = try Package.Module.create(arena, .{
5275 .global_cache_directory = global_cache_directory,
52765133 .paths = main_mod_paths,
52775134 .fully_qualified_name = "root",
52785135 .cc_argv = &.{},
......@@ -5281,16 +5138,11 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52815138 },
52825139 .global = config,
52835140 .parent = null,
5284 .builtin_mod = null,
5285 .builtin_modules = null, // all modules will inherit this one's builtin
52865141 });
52875142
5288 const builtin_mod = root_mod.getBuiltinDependency();
5289
52905143 const build_mod = try Package.Module.create(arena, .{
5291 .global_cache_directory = global_cache_directory,
52925144 .paths = .{
5293 .root = .{ .root_dir = build_root.directory },
5145 .root = try .fromUnresolved(arena, dirs, &.{build_root.directory.path orelse "."}),
52945146 .root_src_path = build_root.build_zig_basename,
52955147 },
52965148 .fully_qualified_name = "root.@build",
......@@ -5298,8 +5150,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
52985150 .inherited = .{},
52995151 .global = config,
53005152 .parent = root_mod,
5301 .builtin_mod = builtin_mod,
5302 .builtin_modules = null, // `builtin_mod` is specified
53035153 });
53045154
53055155 var cleanup_build_dir: ?fs.Dir = null;
......@@ -5312,7 +5162,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53125162 var job_queue: Package.Fetch.JobQueue = .{
53135163 .http_client = &http_client,
53145164 .thread_pool = &thread_pool,
5315 .global_cache = global_cache_directory,
5165 .global_cache = dirs.global_cache,
53165166 .read_only = false,
53175167 .recursive = true,
53185168 .debug_hash = false,
......@@ -5340,14 +5190,16 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53405190 try job_queue.all_fetches.ensureUnusedCapacity(gpa, 1);
53415191 try job_queue.table.ensureUnusedCapacity(gpa, 1);
53425192
5193 const phantom_package_root: Cache.Path = .{ .root_dir = build_root.directory };
5194
53435195 var fetch: Package.Fetch = .{
53445196 .arena = std.heap.ArenaAllocator.init(gpa),
5345 .location = .{ .relative_path = build_mod.root },
5197 .location = .{ .relative_path = phantom_package_root },
53465198 .location_tok = 0,
53475199 .hash_tok = .none,
53485200 .name_tok = 0,
53495201 .lazy_status = .eager,
5350 .parent_package_root = build_mod.root,
5202 .parent_package_root = phantom_package_root,
53515203 .parent_manifest_ast = null,
53525204 .prog_node = fetch_prog_node,
53535205 .job_queue = &job_queue,
......@@ -5371,7 +5223,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53715223 job_queue.all_fetches.appendAssumeCapacity(&fetch);
53725224
53735225 job_queue.table.putAssumeCapacityNoClobber(
5374 Package.Fetch.relativePathDigest(build_mod.root, global_cache_directory),
5226 Package.Fetch.relativePathDigest(phantom_package_root, dirs.global_cache),
53755227 &fetch,
53765228 );
53775229
......@@ -5397,9 +5249,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
53975249 arena,
53985250 source_buf.items,
53995251 root_mod,
5400 global_cache_directory,
5401 local_cache_directory,
5402 builtin_mod,
5252 dirs,
54035253 config,
54045254 );
54055255
......@@ -5416,10 +5266,10 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
54165266 if (!f.has_build_zig)
54175267 continue;
54185268 const hash_slice = hash.toSlice();
5269 const mod_root_path = try f.package_root.toString(arena);
54195270 const m = try Package.Module.create(arena, .{
5420 .global_cache_directory = global_cache_directory,
54215271 .paths = .{
5422 .root = try f.package_root.clone(arena),
5272 .root = try .fromUnresolved(arena, dirs, &.{mod_root_path}),
54235273 .root_src_path = Package.build_zig_basename,
54245274 },
54255275 .fully_qualified_name = try std.fmt.allocPrint(
......@@ -5431,8 +5281,6 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
54315281 .inherited = .{},
54325282 .global = config,
54335283 .parent = root_mod,
5434 .builtin_mod = builtin_mod,
5435 .builtin_modules = null, // `builtin_mod` is specified
54365284 });
54375285 const hash_cloned = try arena.dupe(u8, hash_slice);
54385286 deps_mod.deps.putAssumeCapacityNoClobber(hash_cloned, m);
......@@ -5449,7 +5297,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
54495297 for (dep_names, man.dependencies.values()) |name, dep| {
54505298 const dep_digest = Package.Fetch.depDigest(
54515299 f.package_root,
5452 global_cache_directory,
5300 dirs.global_cache,
54535301 dep,
54545302 ) orelse continue;
54555303 const dep_mod = job_queue.table.get(dep_digest).?.module orelse continue;
......@@ -5461,18 +5309,14 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
54615309 } else try createEmptyDependenciesModule(
54625310 arena,
54635311 root_mod,
5464 global_cache_directory,
5465 local_cache_directory,
5466 builtin_mod,
5312 dirs,
54675313 config,
54685314 );
54695315
54705316 try root_mod.deps.put(arena, "@build", build_mod);
54715317
54725318 const comp = Compilation.create(gpa, arena, .{
5473 .zig_lib_directory = zig_lib_directory,
5474 .local_cache_directory = local_cache_directory,
5475 .global_cache_directory = global_cache_directory,
5319 .dirs = dirs,
54765320 .root_name = "build",
54775321 .config = config,
54785322 .root_mod = root_mod,
......@@ -5507,7 +5351,7 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
55075351 // above, and thus the output file is already closed.
55085352 //try comp.makeBinFileExecutable();
55095353 child_argv.items[argv_index_exe] =
5510 try local_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
5354 try dirs.local_cache.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
55115355 }
55125356
55135357 if (process.can_spawn) {
......@@ -5539,12 +5383,12 @@ fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !void {
55395383 // that are missing.
55405384 const s = fs.path.sep_str;
55415385 const tmp_sub_path = "tmp" ++ s ++ results_tmp_file_nonce;
5542 const stdout = local_cache_directory.handle.readFileAlloc(arena, tmp_sub_path, 50 * 1024 * 1024) catch |err| {
5386 const stdout = dirs.local_cache.handle.readFileAlloc(arena, tmp_sub_path, 50 * 1024 * 1024) catch |err| {
55435387 fatal("unable to read results of configure phase from '{}{s}': {s}", .{
5544 local_cache_directory, tmp_sub_path, @errorName(err),
5388 dirs.local_cache, tmp_sub_path, @errorName(err),
55455389 });
55465390 };
5547 local_cache_directory.handle.deleteFile(tmp_sub_path) catch {};
5391 dirs.local_cache.handle.deleteFile(tmp_sub_path) catch {};
55485392
55495393 var it = mem.splitScalar(u8, stdout, '\n');
55505394 var any_errors = false;
......@@ -5633,7 +5477,7 @@ fn jitCmd(
56335477 .basename = exe_basename,
56345478 };
56355479
5636 const self_exe_path = introspect.findZigExePath(arena) catch |err| {
5480 const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
56375481 fatal("unable to find self exe path: {s}", .{@errorName(err)});
56385482 };
56395483
......@@ -5645,24 +5489,16 @@ fn jitCmd(
56455489 const override_lib_dir: ?[]const u8 = try EnvVar.ZIG_LIB_DIR.get(arena);
56465490 const override_global_cache_dir: ?[]const u8 = try EnvVar.ZIG_GLOBAL_CACHE_DIR.get(arena);
56475491
5648 var zig_lib_directory: Directory = if (override_lib_dir) |lib_dir| .{
5649 .path = lib_dir,
5650 .handle = fs.cwd().openDir(lib_dir, .{}) catch |err| {
5651 fatal("unable to open zig lib directory from 'zig-lib-dir' argument: '{s}': {s}", .{ lib_dir, @errorName(err) });
5652 },
5653 } else introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
5654 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
5655 };
5656 defer zig_lib_directory.handle.close();
5657
5658 var global_cache_directory: Directory = l: {
5659 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
5660 break :l .{
5661 .handle = try fs.cwd().makeOpenPath(p, .{}),
5662 .path = p,
5663 };
5664 };
5665 defer global_cache_directory.handle.close();
5492 // This `init` calls `fatal` on error.
5493 var dirs: Compilation.Directories = .init(
5494 arena,
5495 override_lib_dir,
5496 override_global_cache_dir,
5497 .global,
5498 if (native_os == .wasi) wasi_preopens,
5499 self_exe_path,
5500 );
5501 defer dirs.deinit();
56665502
56675503 var thread_pool: ThreadPool = undefined;
56685504 try thread_pool.init(.{
......@@ -5680,10 +5516,7 @@ fn jitCmd(
56805516 // big block here to ensure the cleanup gets run when we extract out our argv.
56815517 {
56825518 const main_mod_paths: Package.Module.CreateOptions.Paths = .{
5683 .root = .{
5684 .root_dir = zig_lib_directory,
5685 .sub_path = "compiler",
5686 },
5519 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler"),
56875520 .root_src_path = options.root_src_path,
56885521 };
56895522
......@@ -5698,7 +5531,6 @@ fn jitCmd(
56985531 });
56995532
57005533 const root_mod = try Package.Module.create(arena, .{
5701 .global_cache_directory = global_cache_directory,
57025534 .paths = main_mod_paths,
57035535 .fully_qualified_name = "root",
57045536 .cc_argv = &.{},
......@@ -5709,18 +5541,12 @@ fn jitCmd(
57095541 },
57105542 .global = config,
57115543 .parent = null,
5712 .builtin_mod = null,
5713 .builtin_modules = null, // all modules will inherit this one's builtin
57145544 });
57155545
57165546 if (options.depend_on_aro) {
57175547 const aro_mod = try Package.Module.create(arena, .{
5718 .global_cache_directory = global_cache_directory,
57195548 .paths = .{
5720 .root = .{
5721 .root_dir = zig_lib_directory,
5722 .sub_path = "compiler/aro",
5723 },
5549 .root = try .fromRoot(arena, dirs, .zig_lib, "compiler/aro"),
57245550 .root_src_path = "aro.zig",
57255551 },
57265552 .fully_qualified_name = "aro",
......@@ -5732,16 +5558,12 @@ fn jitCmd(
57325558 },
57335559 .global = config,
57345560 .parent = null,
5735 .builtin_mod = root_mod.getBuiltinDependency(),
5736 .builtin_modules = null, // `builtin_mod` is specified
57375561 });
57385562 try root_mod.deps.put(arena, "aro", aro_mod);
57395563 }
57405564
57415565 const comp = Compilation.create(gpa, arena, .{
5742 .zig_lib_directory = zig_lib_directory,
5743 .local_cache_directory = global_cache_directory,
5744 .global_cache_directory = global_cache_directory,
5566 .dirs = dirs,
57455567 .root_name = options.cmd_name,
57465568 .config = config,
57475569 .root_mod = root_mod,
......@@ -5778,16 +5600,16 @@ fn jitCmd(
57785600 };
57795601 }
57805602
5781 const exe_path = try global_cache_directory.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
5603 const exe_path = try dirs.global_cache.join(arena, &.{comp.cache_use.whole.bin_sub_path.?});
57825604 child_argv.appendAssumeCapacity(exe_path);
57835605 }
57845606
57855607 if (options.prepend_zig_lib_dir_path)
5786 child_argv.appendAssumeCapacity(zig_lib_directory.path.?);
5608 child_argv.appendAssumeCapacity(dirs.zig_lib.path.?);
57875609 if (options.prepend_zig_exe_path)
57885610 child_argv.appendAssumeCapacity(self_exe_path);
57895611 if (options.prepend_global_cache_path)
5790 child_argv.appendAssumeCapacity(global_cache_directory.path.?);
5612 child_argv.appendAssumeCapacity(dirs.global_cache.path.?);
57915613
57925614 child_argv.appendSliceAssumeCapacity(args);
57935615
......@@ -6270,7 +6092,6 @@ const usage_ast_check =
62706092;
62716093
62726094fn cmdAstCheck(
6273 gpa: Allocator,
62746095 arena: Allocator,
62756096 args: []const []const u8,
62766097) !void {
......@@ -6281,7 +6102,7 @@ fn cmdAstCheck(
62816102 var color: Color = .auto;
62826103 var want_output_text = false;
62836104 var force_zon = false;
6284 var zig_source_file: ?[]const u8 = null;
6105 var zig_source_path: ?[]const u8 = null;
62856106
62866107 var i: usize = 0;
62876108 while (i < args.len) : (i += 1) {
......@@ -6306,96 +6127,55 @@ fn cmdAstCheck(
63066127 } else {
63076128 fatal("unrecognized parameter: '{s}'", .{arg});
63086129 }
6309 } else if (zig_source_file == null) {
6310 zig_source_file = arg;
6130 } else if (zig_source_path == null) {
6131 zig_source_path = arg;
63116132 } else {
63126133 fatal("extra positional parameter: '{s}'", .{arg});
63136134 }
63146135 }
63156136
6316 var file: Zcu.File = .{
6317 .status = .never_loaded,
6318 .sub_file_path = undefined,
6319 .stat = undefined,
6320 .source = null,
6321 .tree = null,
6322 .zir = null,
6323 .zoir = null,
6324 .mod = undefined,
6325 };
6326 if (zig_source_file) |file_name| {
6327 var f = fs.cwd().openFile(file_name, .{}) catch |err| {
6328 fatal("unable to open file for ast-check '{s}': {s}", .{ file_name, @errorName(err) });
6329 };
6330 defer f.close();
6331
6332 const stat = try f.stat();
6333
6334 if (stat.size > std.zig.max_src_size)
6335 return error.FileTooBig;
6336
6337 const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
6338 const amt = try f.readAll(source);
6339 if (amt != stat.size)
6340 return error.UnexpectedEndOfFile;
6341
6342 file.sub_file_path = file_name;
6343 file.source = source;
6344 file.stat = .{
6345 .size = stat.size,
6346 .inode = stat.inode,
6347 .mtime = stat.mtime,
6348 };
6349 } else {
6350 const stdin = io.getStdIn();
6351 const source = std.zig.readSourceFileToEndAlloc(arena, stdin, null) catch |err| {
6352 fatal("unable to read stdin: {}", .{err});
6137 const display_path = zig_source_path orelse "<stdin>";
6138 const source: [:0]const u8 = s: {
6139 var f = if (zig_source_path) |p| file: {
6140 break :file fs.cwd().openFile(p, .{}) catch |err| {
6141 fatal("unable to open file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
6142 };
6143 } else io.getStdIn();
6144 defer if (zig_source_path != null) f.close();
6145 break :s std.zig.readSourceFileToEndAlloc(arena, f, null) catch |err| {
6146 fatal("unable to load file '{s}' for ast-check: {s}", .{ display_path, @errorName(err) });
63536147 };
6354 file.sub_file_path = "<stdin>";
6355 file.source = source;
6356 file.stat.size = source.len;
6357 }
6148 };
63586149
63596150 const mode: Ast.Mode = mode: {
63606151 if (force_zon) break :mode .zon;
6361 if (zig_source_file) |name| {
6362 if (mem.endsWith(u8, name, ".zon")) {
6152 if (zig_source_path) |path| {
6153 if (mem.endsWith(u8, path, ".zon")) {
63636154 break :mode .zon;
63646155 }
63656156 }
63666157 break :mode .zig;
63676158 };
63686159
6369 file.mod = try Package.Module.createLimited(arena, .{
6370 .root = Path.cwd(),
6371 .root_src_path = file.sub_file_path,
6372 .fully_qualified_name = "root",
6373 });
6374
6375 file.tree = try Ast.parse(gpa, file.source.?, mode);
6376 defer file.tree.?.deinit(gpa);
6160 const tree = try Ast.parse(arena, source, mode);
63776161
63786162 switch (mode) {
63796163 .zig => {
6380 file.zir = try AstGen.generate(gpa, file.tree.?);
6381 defer file.zir.?.deinit(gpa);
6164 const zir = try AstGen.generate(arena, tree);
63826165
6383 if (file.zir.?.hasCompileErrors()) {
6166 if (zir.hasCompileErrors()) {
63846167 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6385 try wip_errors.init(gpa);
6386 defer wip_errors.deinit();
6387 try Compilation.addZirErrorMessages(&wip_errors, &file);
6168 try wip_errors.init(arena);
6169 try wip_errors.addZirErrorMessages(zir, tree, source, display_path);
63886170 var error_bundle = try wip_errors.toOwnedBundle("");
6389 defer error_bundle.deinit(gpa);
63906171 error_bundle.renderToStdErr(color.renderOptions());
6391
6392 if (file.zir.?.loweringFailed()) {
6172 if (zir.loweringFailed()) {
63936173 process.exit(1);
63946174 }
63956175 }
63966176
63976177 if (!want_output_text) {
6398 if (file.zir.?.hasCompileErrors()) {
6178 if (zir.hasCompileErrors()) {
63996179 process.exit(1);
64006180 } else {
64016181 return cleanExit();
......@@ -6407,20 +6187,20 @@ fn cmdAstCheck(
64076187
64086188 {
64096189 const token_bytes = @sizeOf(Ast.TokenList) +
6410 file.tree.?.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));
6411 const tree_bytes = @sizeOf(Ast) + file.tree.?.nodes.len *
6190 tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset));
6191 const tree_bytes = @sizeOf(Ast) + tree.nodes.len *
64126192 (@sizeOf(Ast.Node.Tag) +
64136193 @sizeOf(Ast.TokenIndex) +
64146194 // Here we don't use @sizeOf(Ast.Node.Data) because it would include
64156195 // the debug safety tag but we want to measure release size.
64166196 8);
6417 const instruction_bytes = file.zir.?.instructions.len *
6197 const instruction_bytes = zir.instructions.len *
64186198 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
64196199 // the debug safety tag but we want to measure release size.
64206200 (@sizeOf(Zir.Inst.Tag) + 8);
6421 const extra_bytes = file.zir.?.extra.len * @sizeOf(u32);
6201 const extra_bytes = zir.extra.len * @sizeOf(u32);
64226202 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
6423 file.zir.?.string_bytes.len * @sizeOf(u8);
6203 zir.string_bytes.len * @sizeOf(u8);
64246204 const stdout = io.getStdOut();
64256205 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
64266206 // zig fmt: off
......@@ -6434,44 +6214,33 @@ fn cmdAstCheck(
64346214 \\# Extra Data Items: {d} ({})
64356215 \\
64366216 , .{
6437 fmtIntSizeBin(file.source.?.len),
6438 file.tree.?.tokens.len, fmtIntSizeBin(token_bytes),
6439 file.tree.?.nodes.len, fmtIntSizeBin(tree_bytes),
6217 fmtIntSizeBin(source.len),
6218 tree.tokens.len, fmtIntSizeBin(token_bytes),
6219 tree.nodes.len, fmtIntSizeBin(tree_bytes),
64406220 fmtIntSizeBin(total_bytes),
6441 file.zir.?.instructions.len, fmtIntSizeBin(instruction_bytes),
6442 fmtIntSizeBin(file.zir.?.string_bytes.len),
6443 file.zir.?.extra.len, fmtIntSizeBin(extra_bytes),
6221 zir.instructions.len, fmtIntSizeBin(instruction_bytes),
6222 fmtIntSizeBin(zir.string_bytes.len),
6223 zir.extra.len, fmtIntSizeBin(extra_bytes),
64446224 });
64456225 // zig fmt: on
64466226 }
64476227
6448 try @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
6228 try @import("print_zir.zig").renderAsTextToFile(arena, tree, zir, io.getStdOut());
64496229
6450 if (file.zir.?.hasCompileErrors()) {
6230 if (zir.hasCompileErrors()) {
64516231 process.exit(1);
64526232 } else {
64536233 return cleanExit();
64546234 }
64556235 },
64566236 .zon => {
6457 const zoir = try ZonGen.generate(gpa, file.tree.?, .{});
6458 defer zoir.deinit(gpa);
6459
6237 const zoir = try ZonGen.generate(arena, tree, .{});
64606238 if (zoir.hasCompileErrors()) {
64616239 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6462 try wip_errors.init(gpa);
6463 defer wip_errors.deinit();
6464
6465 {
6466 const src_path = try file.fullPath(gpa);
6467 defer gpa.free(src_path);
6468 try wip_errors.addZoirErrorMessages(zoir, file.tree.?, file.source.?, src_path);
6469 }
6470
6240 try wip_errors.init(arena);
6241 try wip_errors.addZoirErrorMessages(zoir, tree, source, display_path);
64716242 var error_bundle = try wip_errors.toOwnedBundle("");
6472 defer error_bundle.deinit(gpa);
64736243 error_bundle.renderToStdErr(color.renderOptions());
6474
64756244 process.exit(1);
64766245 }
64776246
......@@ -6489,16 +6258,9 @@ fn cmdAstCheck(
64896258 }
64906259}
64916260
6492fn cmdDetectCpu(
6493 gpa: Allocator,
6494 arena: Allocator,
6495 args: []const []const u8,
6496) !void {
6261fn cmdDetectCpu(args: []const []const u8) !void {
64976262 dev.check(.detect_cpu_command);
64986263
6499 _ = gpa;
6500 _ = arena;
6501
65026264 const detect_cpu_usage =
65036265 \\Usage: zig detect-cpu [--llvm]
65046266 \\
......@@ -6676,13 +6438,11 @@ fn cmdDumpLlvmInts(
66766438
66776439/// This is only enabled for debug builds.
66786440fn cmdDumpZir(
6679 gpa: Allocator,
66806441 arena: Allocator,
66816442 args: []const []const u8,
66826443) !void {
66836444 dev.check(.dump_zir_command);
66846445
6685 _ = arena;
66866446 const Zir = std.zig.Zir;
66876447
66886448 const cache_file = args[0];
......@@ -6692,26 +6452,16 @@ fn cmdDumpZir(
66926452 };
66936453 defer f.close();
66946454
6695 var file: Zcu.File = .{
6696 .status = .never_loaded,
6697 .sub_file_path = undefined,
6698 .stat = undefined,
6699 .source = null,
6700 .tree = null,
6701 .zir = try Zcu.loadZirCache(gpa, f),
6702 .zoir = null,
6703 .mod = undefined,
6704 };
6705 defer file.zir.?.deinit(gpa);
6455 const zir = try Zcu.loadZirCache(arena, f);
67066456
67076457 {
6708 const instruction_bytes = file.zir.?.instructions.len *
6458 const instruction_bytes = zir.instructions.len *
67096459 // Here we don't use @sizeOf(Zir.Inst.Data) because it would include
67106460 // the debug safety tag but we want to measure release size.
67116461 (@sizeOf(Zir.Inst.Tag) + 8);
6712 const extra_bytes = file.zir.?.extra.len * @sizeOf(u32);
6462 const extra_bytes = zir.extra.len * @sizeOf(u32);
67136463 const total_bytes = @sizeOf(Zir) + instruction_bytes + extra_bytes +
6714 file.zir.?.string_bytes.len * @sizeOf(u8);
6464 zir.string_bytes.len * @sizeOf(u8);
67156465 const stdout = io.getStdOut();
67166466 const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
67176467 // zig fmt: off
......@@ -6723,19 +6473,18 @@ fn cmdDumpZir(
67236473 \\
67246474 , .{
67256475 fmtIntSizeBin(total_bytes),
6726 file.zir.?.instructions.len, fmtIntSizeBin(instruction_bytes),
6727 fmtIntSizeBin(file.zir.?.string_bytes.len),
6728 file.zir.?.extra.len, fmtIntSizeBin(extra_bytes),
6476 zir.instructions.len, fmtIntSizeBin(instruction_bytes),
6477 fmtIntSizeBin(zir.string_bytes.len),
6478 zir.extra.len, fmtIntSizeBin(extra_bytes),
67296479 });
67306480 // zig fmt: on
67316481 }
67326482
6733 return @import("print_zir.zig").renderAsTextToFile(gpa, &file, io.getStdOut());
6483 return @import("print_zir.zig").renderAsTextToFile(arena, null, zir, io.getStdOut());
67346484}
67356485
67366486/// This is only enabled for debug builds.
67376487fn cmdChangelist(
6738 gpa: Allocator,
67396488 arena: Allocator,
67406489 args: []const []const u8,
67416490) !void {
......@@ -6744,101 +6493,50 @@ fn cmdChangelist(
67446493 const color: Color = .auto;
67456494 const Zir = std.zig.Zir;
67466495
6747 const old_source_file = args[0];
6748 const new_source_file = args[1];
6496 const old_source_path = args[0];
6497 const new_source_path = args[1];
67496498
6750 var f = fs.cwd().openFile(old_source_file, .{}) catch |err| {
6751 fatal("unable to open old source file for comparison '{s}': {s}", .{ old_source_file, @errorName(err) });
6499 const old_source = source: {
6500 var f = fs.cwd().openFile(old_source_path, .{}) catch |err|
6501 fatal("unable to open old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
6502 defer f.close();
6503 break :source std.zig.readSourceFileToEndAlloc(arena, f, std.zig.max_src_size) catch |err|
6504 fatal("unable to read old source file '{s}': {s}", .{ old_source_path, @errorName(err) });
67526505 };
6753 defer f.close();
6754
6755 const stat = try f.stat();
6756
6757 if (stat.size > std.zig.max_src_size)
6758 return error.FileTooBig;
6759
6760 var file: Zcu.File = .{
6761 .status = .never_loaded,
6762 .sub_file_path = old_source_file,
6763 .stat = .{
6764 .size = stat.size,
6765 .inode = stat.inode,
6766 .mtime = stat.mtime,
6767 },
6768 .source = null,
6769 .tree = null,
6770 .zir = null,
6771 .zoir = null,
6772 .mod = undefined,
6506 const new_source = source: {
6507 var f = fs.cwd().openFile(new_source_path, .{}) catch |err|
6508 fatal("unable to open new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
6509 defer f.close();
6510 break :source std.zig.readSourceFileToEndAlloc(arena, f, std.zig.max_src_size) catch |err|
6511 fatal("unable to read new source file '{s}': {s}", .{ new_source_path, @errorName(err) });
67736512 };
67746513
6775 file.mod = try Package.Module.createLimited(arena, .{
6776 .root = Path.cwd(),
6777 .root_src_path = file.sub_file_path,
6778 .fully_qualified_name = "root",
6779 });
6780
6781 const source = try arena.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
6782 const amt = try f.readAll(source);
6783 if (amt != stat.size)
6784 return error.UnexpectedEndOfFile;
6785 file.source = source;
6786
6787 file.tree = try Ast.parse(gpa, file.source.?, .zig);
6788 defer file.tree.?.deinit(gpa);
6789
6790 file.zir = try AstGen.generate(gpa, file.tree.?);
6791 defer file.zir.?.deinit(gpa);
6514 const old_tree = try Ast.parse(arena, old_source, .zig);
6515 const old_zir = try AstGen.generate(arena, old_tree);
67926516
6793 if (file.zir.?.loweringFailed()) {
6517 if (old_zir.loweringFailed()) {
67946518 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6795 try wip_errors.init(gpa);
6796 defer wip_errors.deinit();
6797 try Compilation.addZirErrorMessages(&wip_errors, &file);
6519 try wip_errors.init(arena);
6520 try wip_errors.addZirErrorMessages(old_zir, old_tree, old_source, old_source_path);
67986521 var error_bundle = try wip_errors.toOwnedBundle("");
6799 defer error_bundle.deinit(gpa);
68006522 error_bundle.renderToStdErr(color.renderOptions());
68016523 process.exit(1);
68026524 }
68036525
6804 var new_f = fs.cwd().openFile(new_source_file, .{}) catch |err| {
6805 fatal("unable to open new source file for comparison '{s}': {s}", .{ new_source_file, @errorName(err) });
6806 };
6807 defer new_f.close();
6808
6809 const new_stat = try new_f.stat();
6810
6811 if (new_stat.size > std.zig.max_src_size)
6812 return error.FileTooBig;
6813
6814 const new_source = try arena.allocSentinel(u8, @as(usize, @intCast(new_stat.size)), 0);
6815 const new_amt = try new_f.readAll(new_source);
6816 if (new_amt != new_stat.size)
6817 return error.UnexpectedEndOfFile;
6526 const new_tree = try Ast.parse(arena, new_source, .zig);
6527 const new_zir = try AstGen.generate(arena, new_tree);
68186528
6819 var new_tree = try Ast.parse(gpa, new_source, .zig);
6820 defer new_tree.deinit(gpa);
6821
6822 var old_zir = file.zir.?;
6823 defer old_zir.deinit(gpa);
6824 file.zir = null;
6825 file.zir = try AstGen.generate(gpa, new_tree);
6826
6827 if (file.zir.?.loweringFailed()) {
6529 if (new_zir.loweringFailed()) {
68286530 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
6829 try wip_errors.init(gpa);
6830 defer wip_errors.deinit();
6831 try Compilation.addZirErrorMessages(&wip_errors, &file);
6531 try wip_errors.init(arena);
6532 try wip_errors.addZirErrorMessages(new_zir, new_tree, new_source, new_source_path);
68326533 var error_bundle = try wip_errors.toOwnedBundle("");
6833 defer error_bundle.deinit(gpa);
68346534 error_bundle.renderToStdErr(color.renderOptions());
68356535 process.exit(1);
68366536 }
68376537
68386538 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .empty;
6839 defer inst_map.deinit(gpa);
6840
6841 try Zcu.mapOldZirToNew(gpa, old_zir, file.zir.?, &inst_map);
6539 try Zcu.mapOldZirToNew(arena, old_zir, new_zir, &inst_map);
68426540
68436541 var bw = io.bufferedWriter(io.getStdOut().writer());
68446542 const stdout = bw.writer();
......@@ -7315,7 +7013,7 @@ fn cmdFetch(
73157013 },
73167014 };
73177015
7318 const cwd_path = try process.getCwdAlloc(arena);
7016 const cwd_path = try introspect.getResolvedCwd(arena);
73197017
73207018 var build_root = try findBuildRoot(arena, .{
73217019 .cwd_path = cwd_path,
......@@ -7447,9 +7145,7 @@ fn cmdFetch(
74477145fn createEmptyDependenciesModule(
74487146 arena: Allocator,
74497147 main_mod: *Package.Module,
7450 global_cache_directory: Cache.Directory,
7451 local_cache_directory: Cache.Directory,
7452 builtin_mod: *Package.Module,
7148 dirs: Compilation.Directories,
74537149 global_options: Compilation.Config,
74547150) !void {
74557151 var source = std.ArrayList(u8).init(arena);
......@@ -7458,9 +7154,7 @@ fn createEmptyDependenciesModule(
74587154 arena,
74597155 source.items,
74607156 main_mod,
7461 global_cache_directory,
7462 local_cache_directory,
7463 builtin_mod,
7157 dirs,
74647158 global_options,
74657159 );
74667160}
......@@ -7471,9 +7165,7 @@ fn createDependenciesModule(
74717165 arena: Allocator,
74727166 source: []const u8,
74737167 main_mod: *Package.Module,
7474 global_cache_directory: Cache.Directory,
7475 local_cache_directory: Cache.Directory,
7476 builtin_mod: *Package.Module,
7168 dirs: Compilation.Directories,
74777169 global_options: Compilation.Config,
74787170) !*Package.Module {
74797171 // Atomically create the file in a directory named after the hash of its contents.
......@@ -7481,7 +7173,7 @@ fn createDependenciesModule(
74817173 const rand_int = std.crypto.random.int(u64);
74827174 const tmp_dir_sub_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
74837175 {
7484 var tmp_dir = try local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{});
7176 var tmp_dir = try dirs.local_cache.handle.makeOpenPath(tmp_dir_sub_path, .{});
74857177 defer tmp_dir.close();
74867178 try tmp_dir.writeFile(.{ .sub_path = basename, .data = source });
74877179 }
......@@ -7493,18 +7185,14 @@ fn createDependenciesModule(
74937185
74947186 const o_dir_sub_path = try arena.dupe(u8, "o" ++ fs.path.sep_str ++ hex_digest);
74957187 try Package.Fetch.renameTmpIntoCache(
7496 local_cache_directory.handle,
7188 dirs.local_cache.handle,
74977189 tmp_dir_sub_path,
74987190 o_dir_sub_path,
74997191 );
75007192
75017193 const deps_mod = try Package.Module.create(arena, .{
7502 .global_cache_directory = global_cache_directory,
75037194 .paths = .{
7504 .root = .{
7505 .root_dir = local_cache_directory,
7506 .sub_path = o_dir_sub_path,
7507 },
7195 .root = try .fromRoot(arena, dirs, .local_cache, o_dir_sub_path),
75087196 .root_src_path = basename,
75097197 },
75107198 .fully_qualified_name = "root.@dependencies",
......@@ -7512,8 +7200,6 @@ fn createDependenciesModule(
75127200 .cc_argv = &.{},
75137201 .inherited = .{},
75147202 .global = global_options,
7515 .builtin_mod = builtin_mod,
7516 .builtin_modules = null, // `builtin_mod` is specified
75177203 });
75187204 try main_mod.deps.put(arena, "@dependencies", deps_mod);
75197205 return deps_mod;
......@@ -7536,7 +7222,7 @@ const FindBuildRootOptions = struct {
75367222};
75377223
75387224fn findBuildRoot(arena: Allocator, options: FindBuildRootOptions) !BuildRoot {
7539 const cwd_path = options.cwd_path orelse try process.getCwdAlloc(arena);
7225 const cwd_path = options.cwd_path orelse try introspect.getResolvedCwd(arena);
75407226 const build_zig_basename = if (options.build_file) |bf|
75417227 fs.path.basename(bf)
75427228 else
......@@ -7723,10 +7409,13 @@ const Templates = struct {
77237409};
77247410
77257411fn findTemplates(gpa: Allocator, arena: Allocator) Templates {
7726 const self_exe_path = introspect.findZigExePath(arena) catch |err| {
7412 const cwd_path = introspect.getResolvedCwd(arena) catch |err| {
7413 fatal("unable to get cwd: {s}", .{@errorName(err)});
7414 };
7415 const self_exe_path = fs.selfExePathAlloc(arena) catch |err| {
77277416 fatal("unable to find self exe path: {s}", .{@errorName(err)});
77287417 };
7729 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
7418 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
77307419 fatal("unable to find zig installation directory '{s}': {s}", .{ self_exe_path, @errorName(err) });
77317420 };
77327421
......@@ -7783,8 +7472,8 @@ fn handleModArg(
77837472 const gop = try create_module.modules.getOrPut(arena, mod_name);
77847473
77857474 if (gop.found_existing) {
7786 fatal("unable to add module '{s}': already exists as '{s}'", .{
7787 mod_name, gop.value_ptr.paths.root_src_path,
7475 fatal("unable to add module '{s}': already exists as '{s}{c}{s}'", .{
7476 mod_name, gop.value_ptr.root_path, fs.path.sep, gop.value_ptr.root_src_path,
77887477 });
77897478 }
77907479
......@@ -7811,24 +7500,14 @@ fn handleModArg(
78117500 if (mod_opts.error_tracing == true)
78127501 create_module.opts.any_error_tracing = true;
78137502
7503 const root_path: []const u8, const root_src_path: []const u8 = if (opt_root_src_orig) |path| root: {
7504 create_module.opts.have_zcu = true;
7505 break :root .{ fs.path.dirname(path) orelse ".", fs.path.basename(path) };
7506 } else .{ ".", "" };
7507
78147508 gop.value_ptr.* = .{
7815 .paths = p: {
7816 if (opt_root_src_orig) |root_src_orig| {
7817 create_module.opts.have_zcu = true;
7818 const root_src = try introspect.resolvePath(arena, root_src_orig);
7819 break :p .{
7820 .root = .{
7821 .root_dir = Cache.Directory.cwd(),
7822 .sub_path = fs.path.dirname(root_src) orelse "",
7823 },
7824 .root_src_path = fs.path.basename(root_src),
7825 };
7826 }
7827 break :p .{
7828 .root = .{ .root_dir = Cache.Directory.cwd() },
7829 .root_src_path = "",
7830 };
7831 },
7509 .root_path = root_path,
7510 .root_src_path = root_src_path,
78327511 .cc_argv = try cc_argv.toOwnedSlice(arena),
78337512 .inherited = mod_opts.*,
78347513 .target_arch_os_abi = target_arch_os_abi.*,
src/print_env.zig+4-3
......@@ -2,13 +2,14 @@ const std = @import("std");
22const build_options = @import("build_options");
33const introspect = @import("introspect.zig");
44const Allocator = std.mem.Allocator;
5const fatal = @import("main.zig").fatal;
5const fatal = std.process.fatal;
66
77pub fn cmdEnv(arena: Allocator, args: []const []const u8, stdout: std.fs.File.Writer) !void {
88 _ = args;
9 const self_exe_path = try introspect.findZigExePath(arena);
9 const cwd_path = try introspect.getResolvedCwd(arena);
10 const self_exe_path = try std.fs.selfExePathAlloc(arena);
1011
11 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, self_exe_path) catch |err| {
12 var zig_lib_directory = introspect.findZigLibDirFromSelfExe(arena, cwd_path, self_exe_path) catch |err| {
1213 fatal("unable to find zig installation directory: {s}\n", .{@errorName(err)});
1314 };
1415 defer zig_lib_directory.handle.close();
src/print_targets.zig+1-1
......@@ -3,13 +3,13 @@ const fs = std.fs;
33const io = std.io;
44const mem = std.mem;
55const meta = std.meta;
6const fatal = std.process.fatal;
67const Allocator = std.mem.Allocator;
78const Target = std.Target;
89const target = @import("target.zig");
910const assert = std.debug.assert;
1011const glibc = @import("libs/glibc.zig");
1112const introspect = @import("introspect.zig");
12const fatal = @import("main.zig").fatal;
1313
1414pub fn cmdTargets(
1515 allocator: Allocator,
src/print_zir.zig+14-13
......@@ -12,7 +12,8 @@ const LazySrcLoc = Zcu.LazySrcLoc;
1212/// Write human-readable, debug formatted ZIR code to a file.
1313pub fn renderAsTextToFile(
1414 gpa: Allocator,
15 scope_file: *Zcu.File,
15 tree: ?Ast,
16 zir: Zir,
1617 fs_file: std.fs.File,
1718) !void {
1819 var arena = std.heap.ArenaAllocator.init(gpa);
......@@ -21,8 +22,8 @@ pub fn renderAsTextToFile(
2122 var writer: Writer = .{
2223 .gpa = gpa,
2324 .arena = arena.allocator(),
24 .file = scope_file,
25 .code = scope_file.zir.?,
25 .tree = tree,
26 .code = zir,
2627 .indent = 0,
2728 .parent_decl_node = .root,
2829 .recurse_decls = true,
......@@ -36,18 +37,18 @@ pub fn renderAsTextToFile(
3637 try stream.print("%{d} ", .{@intFromEnum(main_struct_inst)});
3738 try writer.writeInstToStream(stream, main_struct_inst);
3839 try stream.writeAll("\n");
39 const imports_index = scope_file.zir.?.extra[@intFromEnum(Zir.ExtraIndex.imports)];
40 const imports_index = zir.extra[@intFromEnum(Zir.ExtraIndex.imports)];
4041 if (imports_index != 0) {
4142 try stream.writeAll("Imports:\n");
4243
43 const extra = scope_file.zir.?.extraData(Zir.Inst.Imports, imports_index);
44 const extra = zir.extraData(Zir.Inst.Imports, imports_index);
4445 var extra_index = extra.end;
4546
4647 for (0..extra.data.imports_len) |_| {
47 const item = scope_file.zir.?.extraData(Zir.Inst.Imports.Item, extra_index);
48 const item = zir.extraData(Zir.Inst.Imports.Item, extra_index);
4849 extra_index = item.end;
4950
50 const import_path = scope_file.zir.?.nullTerminatedString(item.data.name);
51 const import_path = zir.nullTerminatedString(item.data.name);
5152 try stream.print(" @import(\"{}\") ", .{
5253 std.zig.fmtEscapes(import_path),
5354 });
......@@ -74,7 +75,7 @@ pub fn renderInstructionContext(
7475 var writer: Writer = .{
7576 .gpa = gpa,
7677 .arena = arena.allocator(),
77 .file = scope_file,
78 .tree = scope_file.tree,
7879 .code = scope_file.zir.?,
7980 .indent = if (indent < 2) 2 else indent,
8081 .parent_decl_node = parent_decl_node,
......@@ -106,7 +107,7 @@ pub fn renderSingleInstruction(
106107 var writer: Writer = .{
107108 .gpa = gpa,
108109 .arena = arena.allocator(),
109 .file = scope_file,
110 .tree = scope_file.tree,
110111 .code = scope_file.zir.?,
111112 .indent = indent,
112113 .parent_decl_node = parent_decl_node,
......@@ -121,7 +122,7 @@ pub fn renderSingleInstruction(
121122const Writer = struct {
122123 gpa: Allocator,
123124 arena: Allocator,
124 file: *Zcu.File,
125 tree: ?Ast,
125126 code: Zir,
126127 indent: u32,
127128 parent_decl_node: Ast.Node.Index,
......@@ -2761,7 +2762,7 @@ const Writer = struct {
27612762 }
27622763
27632764 fn writeSrcNode(self: *Writer, stream: anytype, src_node: Ast.Node.Offset) !void {
2764 const tree = self.file.tree orelse return;
2765 const tree = self.tree orelse return;
27652766 const abs_node = src_node.toAbsolute(self.parent_decl_node);
27662767 const src_span = tree.nodeToSpan(abs_node);
27672768 const start = self.line_col_cursor.find(tree.source, src_span.start);
......@@ -2773,7 +2774,7 @@ const Writer = struct {
27732774 }
27742775
27752776 fn writeSrcTok(self: *Writer, stream: anytype, src_tok: Ast.TokenOffset) !void {
2776 const tree = self.file.tree orelse return;
2777 const tree = self.tree orelse return;
27772778 const abs_tok = src_tok.toAbsolute(tree.firstToken(self.parent_decl_node));
27782779 const span_start = tree.tokenStart(abs_tok);
27792780 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(abs_tok).len));
......@@ -2786,7 +2787,7 @@ const Writer = struct {
27862787 }
27872788
27882789 fn writeSrcTokAbs(self: *Writer, stream: anytype, src_tok: Ast.TokenIndex) !void {
2789 const tree = self.file.tree orelse return;
2790 const tree = self.tree orelse return;
27902791 const span_start = tree.tokenStart(src_tok);
27912792 const span_end = span_start + @as(u32, @intCast(tree.tokenSlice(src_tok).len));
27922793 const start = self.line_col_cursor.find(tree.source, span_start);
test/cases/compile_errors/bad_import.zig+2-3
......@@ -3,7 +3,6 @@ const bogus = @import(
33);
44
55// error
6// backend=stage2
7// target=native
86//
9// bogus-does-not-exist.zig': FileNotFound
7// bogus-does-not-exist.zig:1:1: error: unable to load 'bogus-does-not-exist.zig': FileNotFound
8// :2:5: note: file imported here
test/cases/compile_errors/import_of_missing_module.zig created+8
......@@ -0,0 +1,8 @@
1const foo = @import("foo");
2comptime {
3 _ = foo;
4}
5
6// error
7//
8// :1:21: error: no module named 'foo' available within module 'root'
test/cases/compile_errors/import_of_missing_package.zig deleted-10
......@@ -1,10 +0,0 @@
1const foo = @import("foo");
2comptime {
3 _ = foo;
4}
5
6// error
7// backend=stage2
8// target=native
9//
10// :1:21: error: no module named 'foo' available within module root
test/cases/compile_errors/import_outside_module_path.zig created+7
......@@ -0,0 +1,7 @@
1comptime {
2 _ = @import("../a.zig");
3}
4
5// error
6//
7// :2:17: error: import of file outside module path
test/cases/compile_errors/import_outside_package.zig deleted-8
......@@ -1,8 +0,0 @@
1export fn a() usize {
2 return @import("../../above.zig").len;
3}
4
5// error
6// target=native
7//
8// :2:20: error: import of file outside module path: '../../above.zig'
test/cases/compile_errors/import_outside_package_path.zig deleted-9
......@@ -1,9 +0,0 @@
1comptime {
2 _ = @import("../a.zig");
3}
4
5// error
6// backend=stage2
7// target=native
8//
9// :2:17: error: import of file outside module path: '../a.zig'
test/compile_errors.zig+4-3
......@@ -126,9 +126,10 @@ pub fn addCases(ctx: *Cases, b: *std.Build) !void {
126126 \\ _ = @import("foo.zig");
127127 \\}
128128 , &[_][]const u8{
129 ":1:1: error: file exists in multiple modules",
130 ":1:1: note: root of module foo",
131 ":3:17: note: imported from module root",
129 ":1:1: error: file exists in modules 'foo' and 'root'",
130 ":1:1: note: files must belong to only one module",
131 ":1:1: note: file is the root of module 'foo'",
132 ":3:17: note: file is imported here by the root of module 'root'",
132133 });
133134 case.addSourceFile("foo.zig",
134135 \\const dummy = 0;
test/incremental/bad_import created+35
......@@ -0,0 +1,35 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted
5
6#update=initial version
7#file=main.zig
8pub fn main() !void {
9 _ = @import("foo.zig");
10 try std.io.getStdOut().writeAll("success\n");
11}
12const std = @import("std");
13#file=foo.zig
14comptime {
15 _ = @import("bad.zig");
16}
17#expect_error=bad.zig:1:1: error: unable to load 'bad.zig': FileNotFound
18#expect_error=foo.zig:2:17: note: file imported here
19
20#update=change bad import
21#file=foo.zig
22comptime {
23 _ = @import("this_is/not_real.zig");
24}
25#expect_error=this_is/not_real.zig:1:1: error: unable to load 'not_real.zig': FileNotFound
26#expect_error=foo.zig:2:17: note: file imported here
27
28#update=remove import of 'foo.zig'
29#file=main.zig
30pub fn main() !void {
31 //_ = @import("foo.zig");
32 try std.io.getStdOut().writeAll("success\n");
33}
34const std = @import("std");
35#expect_stdout="success\n"
test/incremental/change_module created+65
......@@ -0,0 +1,65 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe
4#target=wasm32-wasi-selfhosted
5#module=foo=foo.zig
6
7#update=initial version
8#file=main.zig
9pub fn main() void {
10 _ = @import("foo");
11 //_ = @import("other.zig");
12}
13#file=foo.zig
14comptime {
15 _ = @import("other.zig");
16}
17#file=other.zig
18fn f() void {
19 @compileLog(@src().module);
20}
21comptime {
22 f();
23}
24#expect_error=other.zig:2:5: error: found compile log statement
25#expect_compile_log=@as([:0]const u8, "foo"[0..3])
26
27#update=change module of other.zig
28#file=main.zig
29pub fn main() void {
30 _ = @import("foo");
31 _ = @import("other.zig");
32}
33#file=foo.zig
34comptime {
35 //_ = @import("other.zig");
36}
37#expect_error=other.zig:2:5: error: found compile log statement
38#expect_compile_log=@as([:0]const u8, "root"[0..4])
39
40#update=put other.zig in both modules
41#file=main.zig
42pub fn main() void {
43 _ = @import("foo");
44 _ = @import("other.zig");
45}
46#file=foo.zig
47comptime {
48 _ = @import("other.zig");
49}
50#expect_error=foo.zig:1:1: error: file exists in modules 'root' and 'foo'
51#expect_error=foo.zig:1:1: note: files must belong to only one module
52#expect_error=main.zig:3:17: note: file is imported here by the root of module 'root'
53#expect_error=foo.zig:2:17: note: file is imported here by the root of module 'foo'
54
55#update=put other.zig in no modules
56#file=main.zig
57pub fn main() void {
58 _ = @import("foo");
59 //_ = @import("other.zig");
60}
61#file=foo.zig
62comptime {
63 //_ = @import("other.zig");
64}
65#expect_stdout=""
test/incremental/change_zon_file+4-2
......@@ -20,7 +20,8 @@ pub fn main() !void {
2020
2121#update=delete file
2222#rm_file=message.zon
23#expect_error=message.zon:1:1: error: unable to load './message.zon': FileNotFound
23#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
24#expect_error=main.zig:2:37: note: file imported here
2425
2526#update=remove reference to ZON file
2627#file=main.zig
......@@ -29,7 +30,8 @@ const message: []const u8 = @import("message.zon");
2930pub fn main() !void {
3031 try std.io.getStdOut().writeAll("a hardcoded string\n");
3132}
32#expect_error=message.zon:1:1: error: unable to load './message.zon': FileNotFound
33#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
34#expect_error=main.zig:2:37: note: file imported here
3335
3436#update=recreate ZON file
3537#file=message.zon
test/standalone/dep_recursive/test.zig-1
......@@ -1,5 +1,4 @@
11const foo = @import("foo");
2const shared = @import("shared");
32const assert = @import("std").debug.assert;
43
54pub fn main() void {
tools/incr-check.zig+37-7
......@@ -106,7 +106,6 @@ pub fn main() !void {
106106 try child_args.appendSlice(arena, &.{
107107 resolved_zig_exe,
108108 "build-exe",
109 case.root_source_file,
110109 "-fincremental",
111110 "-fno-ubsan-rt",
112111 "-target",
......@@ -135,6 +134,13 @@ pub fn main() !void {
135134 if (debug_link) {
136135 try child_args.appendSlice(arena, &.{ "--debug-log", "link", "--debug-log", "link_state", "--debug-log", "link_relocs" });
137136 }
137 for (case.modules) |mod| {
138 try child_args.appendSlice(arena, &.{ "--dep", mod.name });
139 }
140 try child_args.append(arena, try std.fmt.allocPrint(arena, "-Mroot={s}", .{case.root_source_file}));
141 for (case.modules) |mod| {
142 try child_args.append(arena, try std.fmt.allocPrint(arena, "-M{s}={s}", .{ mod.name, mod.file }));
143 }
138144
139145 const zig_prog_node = target_prog_node.start("zig build-exe", 0);
140146 defer zig_prog_node.end();
......@@ -308,9 +314,8 @@ const Eval = struct {
308314 const digest = body[@sizeOf(EbpHdr)..][0..Cache.bin_digest_len];
309315 const result_dir = ".local-cache" ++ std.fs.path.sep_str ++ "o" ++ std.fs.path.sep_str ++ Cache.binToHex(digest.*);
310316
311 const name = std.fs.path.stem(std.fs.path.basename(eval.case.root_source_file));
312317 const bin_name = try std.zig.binNameAlloc(arena, .{
313 .root_name = name,
318 .root_name = "root", // corresponds to the module name "root"
314319 .target = eval.target.resolved,
315320 .output_mode = .Exe,
316321 });
......@@ -359,7 +364,7 @@ const Eval = struct {
359364 error_bundle.renderToStdErr(color.renderOptions());
360365 eval.fatal("update '{s}': more errors than expected", .{update.name});
361366 }
362 eval.checkOneError(update, error_bundle, expected.errors[expected_idx], false, err_idx);
367 try eval.checkOneError(update, error_bundle, expected.errors[expected_idx], false, err_idx);
363368 expected_idx += 1;
364369
365370 for (error_bundle.getNotes(err_idx)) |note_idx| {
......@@ -368,7 +373,7 @@ const Eval = struct {
368373 error_bundle.renderToStdErr(color.renderOptions());
369374 eval.fatal("update '{s}': more error notes than expected", .{update.name});
370375 }
371 eval.checkOneError(update, error_bundle, expected.errors[expected_idx], true, note_idx);
376 try eval.checkOneError(update, error_bundle, expected.errors[expected_idx], true, note_idx);
372377 expected_idx += 1;
373378 }
374379 }
......@@ -387,13 +392,21 @@ const Eval = struct {
387392 expected: Case.ExpectedError,
388393 is_note: bool,
389394 err_idx: std.zig.ErrorBundle.MessageIndex,
390 ) void {
395 ) Allocator.Error!void {
391396 const err = eb.getErrorMessage(err_idx);
392397 if (err.src_loc == .none) @panic("TODO error message with no source location");
393398 if (err.count != 1) @panic("TODO error message with count>1");
394399 const msg = eb.nullTerminatedString(err.msg);
395400 const src = eb.getSourceLocation(err.src_loc);
396 const filename = eb.nullTerminatedString(src.src_path);
401 const raw_filename = eb.nullTerminatedString(src.src_path);
402
403 // We need to replace backslashes for consistency between platforms.
404 const filename = name: {
405 if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename;
406 const copied = try eval.arena.dupe(u8, raw_filename);
407 std.mem.replaceScalar(u8, copied, '\\', '/');
408 break :name copied;
409 };
397410
398411 if (expected.is_note != is_note or
399412 !std.mem.eql(u8, expected.filename, filename) or
......@@ -605,6 +618,7 @@ const Case = struct {
605618 updates: []Update,
606619 root_source_file: []const u8,
607620 targets: []const Target,
621 modules: []const Module,
608622
609623 const Target = struct {
610624 query: []const u8,
......@@ -626,6 +640,11 @@ const Case = struct {
626640 };
627641 };
628642
643 const Module = struct {
644 name: []const u8,
645 file: []const u8,
646 };
647
629648 const Update = struct {
630649 name: []const u8,
631650 outcome: Outcome,
......@@ -660,6 +679,7 @@ const Case = struct {
660679 const fatal = std.process.fatal;
661680
662681 var targets: std.ArrayListUnmanaged(Target) = .empty;
682 var modules: std.ArrayListUnmanaged(Module) = .empty;
663683 var updates: std.ArrayListUnmanaged(Update) = .empty;
664684 var changes: std.ArrayListUnmanaged(FullContents) = .empty;
665685 var deletes: std.ArrayListUnmanaged([]const u8) = .empty;
......@@ -698,6 +718,15 @@ const Case = struct {
698718 .resolved = resolved,
699719 .backend = backend,
700720 });
721 } else if (std.mem.eql(u8, key, "module")) {
722 const split_idx = std.mem.indexOfScalar(u8, val, '=') orelse
723 fatal("line {d}: module does not include file", .{line_n});
724 const name = val[0..split_idx];
725 const file = val[split_idx + 1 ..];
726 try modules.append(arena, .{
727 .name = name,
728 .file = file,
729 });
701730 } else if (std.mem.eql(u8, key, "update")) {
702731 if (updates.items.len > 0) {
703732 const last_update = &updates.items[updates.items.len - 1];
......@@ -811,6 +840,7 @@ const Case = struct {
811840 .updates = updates.items,
812841 .root_source_file = root_source_file orelse fatal("missing root source file", .{}),
813842 .targets = targets.items, // arena so no need for toOwnedSlice
843 .modules = modules.items,
814844 };
815845 }
816846};