authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-04 17:02:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-18 17:37:02+01:00
log37a9a4e0f16c1df8de3a4add3a9566b24f024a95
tree0fc8f1fc15193e8e3c3ccd5e97408cef7372f394
parentd32829e053af2a0f382d4d692ede85c176c9f803
signaturelock-open Commit is signed but in an unrecognized format.

compiler: refactor `Zcu.File` and path representation

This commit makes some big changes to how we track state for Zig source files. In particular, it changes: * How `File` tracks its path on-disk * How AstGen discovers files * How file-level errors are tracked * How `builtin.zig` files and modules are created The original motivation here was to address incremental compilation bugs with the handling of files, such as #22696. To fix this, a few changes are necessary. Just like declarations may become unreferenced on an incremental update, meaning we suppress analysis errors associated with them, it is also possible for all imports of a file to be removed on an incremental update, in which case file-level errors for that file should be suppressed. As such, after AstGen, the compiler must traverse files (starting from analysis roots) and discover the set of "live files" for this update. Additionally, the compiler's previous handling of retryable file errors was not very good; the source location the error was reported as was based only on the first discovered import of that file. This source location also disappeared on future incremental updates. So, as a part of the file traversal above, we also need to figure out the source locations of imports which errors should be reported against. Another observation I made is that the "file exists in multiple modules" error was not implemented in a particularly good way (I get to say that because I wrote it!). It was subject to races, where the order in which different imports of a file were discovered affects both how errors are printed, and which module the file is arbitrarily assigned, with the latter in turn affecting which other files are considered for import. The thing I realised here is that while the AstGen worker pool is running, we cannot know for sure which module(s) a file is in; we could always discover an import later which changes the answer. So, here's how the AstGen workers have changed. We initially ensure that `zcu.import_table` contains the root files for all modules in this Zcu, even if we don't know any imports for them yet. Then, the AstGen workers do not need to be aware of modules. Instead, they simply ignore module imports, and only spin off more workers when they see a by-path import. During AstGen, we can't use module-root-relative paths, since we don't know which modules files are in; but we don't want to unnecessarily use absolute files either, because those are non-portable and can make `error.NameTooLong` more likely. As such, I have introduced a new abstraction, `Compilation.Path`. This type is a way of representing a filesystem path which has a *canonical form*. The path is represented relative to one of a few special directories: the lib directory, the global cache directory, or the local cache directory. As a fallback, we use absolute (or cwd-relative on WASI) paths. This is kind of similar to `std.Build.Cache.Path` with a pre-defined list of possible `std.Build.Cache.Directory`, but has stricter canonicalization rules based on path resolution to make sure deduplicating files works properly. A `Compilation.Path` can be trivially converted to a `std.Build.Cache.Path` from a `Compilation`, but is smaller, has a canonical form, and has a digest which will be consistent across different compiler processes with the same lib and cache directories (important when we serialize incremental compilation state in the future). `Zcu.File` and `Zcu.EmbedFile` both contain a `Compilation.Path`, which is used to access the file on-disk; module-relative sub paths are used quite rarely (`EmbedFile` doesn't even have one now for simplicity). After the AstGen workers all complete, we know that any file which might be imported is definitely in `import_table` and up-to-date. So, we perform a single-threaded graph traversal; similar to what `resolveReferences` plays for `AnalUnit`s, but for files instead. We figure out which files are alive, and which module each file is in. If a file turns out to be in multiple modules, we set a field on `Zcu` to indicate this error. If a file is in a different module to a prior update, we set a flag instructing `updateZirRefs` to invalidate all dependencies on the file. This traversal also discovers "import errors"; these are errors associated with a specific `@import`. With Zig's current design, there is only one possible error here: "import outside of module root". This must be identified during this traversal instead of during AstGen, because it depends on which module the file is in. I tried also representing "module not found" errors in this same way, but it turns out to be much more useful to report those in Sema, because of use cases like optional dependencies where a module import is behind a comptime-known build option. For simplicity, `failed_files` now just maps to `?[]u8`, since the source location is always the whole file. In fact, this allows removing `LazySrcLoc.Offset.entire_file` completely, slightly simplifying some error reporting logic. File-level errors are now directly built in the `std.zig.ErrorBundle.Wip`. If the payload is not `null`, it is the message for a retryable error (i.e. an error loading the source file), and will be reported with a "file imported here" note pointing to the import site discovered during the single-threaded file traversal. The last piece of fallout here is how `Builtin` works. Rather than constructing "builtin" modules when creating `Package.Module`s, they are now constructed on-the-fly by `Zcu`. The map `Zcu.builtin_modules` maps from digests to `*Package.Module`s. These digests are abstract hashes of the `Builtin` value; i.e. all of the options which are placed into "builtin.zig". During the file traversal, we populate `builtin_modules` as needed, so that when we see this imports in Sema, we just grab the relevant entry from this map. This eliminates a bunch of awkward state tracking during construction of the module graph. It's also now clearer exactly what options the builtin module has, since previously it inherited some options arbitrarily from the first-created module with that "builtin" module! The user-visible effects of this commit are: * retryable file errors are now consistently reported against the whole file, with a note pointing to a live import of that file * some theoretical bugs where imports are wrongly considered distinct (when the import path moves out of the cwd and then back in) are fixed * some consistency issues with how file-level errors are reported are fixed; these errors will now always be printed in the same order regardless of how the AstGen pass assigns file indices * incremental updates do not print retryable file errors differently between updates or depending on file structure/contents * incremental updates support files changing modules * incremental updates support files becoming unreferenced Resolves: #22696

49 files changed, 2746 insertions(+), 2377 deletions(-)

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,
......@@ -17290,10 +17301,10 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1729017301 const name = name: {
1729117302 // TODO: we should probably store this name in the ZIR to avoid this complexity.
1729217303 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
17293 const tree = file.getTree(sema.gpa) catch |err| {
17304 const tree = file.getTree(zcu) catch |err| {
1729417305 // In this case we emit a warning + a less precise source location.
17295 log.warn("unable to load {s}: {s}", .{
17296 file.sub_file_path, @errorName(err),
17306 log.warn("unable to load {}: {s}", .{
17307 file.path.fmt(zcu.comp), @errorName(err),
1729717308 });
1729817309 break :name null;
1729917310 };
......@@ -17318,10 +17329,10 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1731817329 const msg = msg: {
1731917330 const name = name: {
1732017331 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
17321 const tree = file.getTree(sema.gpa) catch |err| {
17332 const tree = file.getTree(zcu) catch |err| {
1732217333 // In this case we emit a warning + a less precise source location.
17323 log.warn("unable to load {s}: {s}", .{
17324 file.sub_file_path, @errorName(err),
17334 log.warn("unable to load {}: {s}", .{
17335 file.path.fmt(zcu.comp), @errorName(err),
1732517336 });
1732617337 break :name null;
1732717338 };
......@@ -17415,7 +17426,7 @@ fn zirBuiltinSrc(
1741517426 };
1741617427
1741717428 const module_name_val = v: {
17418 const module_name = file_scope.mod.fully_qualified_name;
17429 const module_name = file_scope.mod.?.fully_qualified_name;
1741917430 const array_ty = try pt.intern(.{ .array_type = .{
1742017431 .len = module_name.len,
1742117432 .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);
......@@ -3404,27 +3490,21 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void
34043490 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
34053491}
34063492
3407pub const ImportFileResult = struct {
3408 file: *File,
3409 file_index: File.Index,
3493pub const ImportResult = struct {
3494 /// Whether `file` has been newly created; in other words, whether this is the first import of
3495 /// this file. This should only be `true` when importing files during AstGen. After that, all
3496 /// files should have already been discovered.
34103497 is_new: bool,
3411 is_pkg: bool,
3412};
34133498
3414pub fn computePathDigest(zcu: *Zcu, mod: *Package.Module, sub_file_path: []const u8) Cache.BinDigest {
3415 const want_local_cache = mod == zcu.main_mod;
3416 var path_hash: Cache.HashHelper = .{};
3417 path_hash.addBytes(build_options.version);
3418 path_hash.add(builtin.zig_backend);
3419 if (!want_local_cache) {
3420 path_hash.addOptionalBytes(mod.root.root_dir.path);
3421 path_hash.addBytes(mod.root.sub_path);
3422 }
3423 path_hash.addBytes(sub_file_path);
3424 var bin: Cache.BinDigest = undefined;
3425 path_hash.hasher.final(&bin);
3426 return bin;
3427}
3499 /// `file.mod` is not populated by this function, so if `is_new`, then it is `undefined`.
3500 file: *Zcu.File,
3501 file_index: File.Index,
3502
3503 /// If this import was a simple file path, this is `null`; the imported file should exist within
3504 /// the importer's module. Otherwise, it's the module which the import resolved to. This module
3505 /// could match the module of `cur_file`, since a module can depend on itself.
3506 module: ?*Package.Module,
3507};
34283508
34293509/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
34303510/// this `AnalUnit` will cause them to be re-created (or not).
......@@ -3938,15 +4018,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
39384018
39394019 try type_queue.ensureTotalCapacity(gpa, zcu.analysis_roots.len);
39404020 for (zcu.analysis_roots.slice()) |mod| {
3941 // Logic ripped from `Zcu.PerThread.importPkg`.
3942 // TODO: this is silly, `Module` should just store a reference to its root `File`.
3943 const resolved_path = try std.fs.path.resolve(gpa, &.{
3944 mod.root.root_dir.path orelse ".",
3945 mod.root.sub_path,
3946 mod.root_src_path,
3947 });
3948 defer gpa.free(resolved_path);
3949 const file = zcu.import_table.get(resolved_path).?;
4021 const file = zcu.module_roots.get(mod).?.unwrap() orelse continue;
39504022 const root_ty = zcu.fileRootType(file);
39514023 if (root_ty == .none) continue;
39524024 type_queue.putAssumeCapacityNoClobber(root_ty, null);
......@@ -4226,8 +4298,8 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
42264298 .@"comptime" => |cu_id| {
42274299 const cu = ip.getComptimeUnit(cu_id);
42284300 if (cu.zir_index.resolveFull(ip)) |resolved| {
4229 const file_path = zcu.fileByIndex(resolved.file).sub_file_path;
4230 return writer.print("comptime(inst=('{s}', %{}) [{}])", .{ file_path, @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
4301 const file_path = zcu.fileByIndex(resolved.file).path;
4302 return writer.print("comptime(inst=('{}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @intFromEnum(resolved.inst), @intFromEnum(cu_id) });
42314303 } else {
42324304 return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)});
42334305 }
......@@ -4251,8 +4323,8 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
42514323 const info = ti.resolveFull(ip) orelse {
42524324 return writer.writeAll("inst(<lost>)");
42534325 };
4254 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4255 return writer.print("inst('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) });
4326 const file_path = zcu.fileByIndex(info.file).path;
4327 return writer.print("inst('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
42564328 },
42574329 .nav_val => |nav| {
42584330 const fqn = ip.getNav(nav).fqn;
......@@ -4268,30 +4340,26 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
42684340 else => unreachable,
42694341 },
42704342 .zon_file => |file| {
4271 const file_path = zcu.fileByIndex(file).sub_file_path;
4272 return writer.print("zon_file('{s}')", .{file_path});
4343 const file_path = zcu.fileByIndex(file).path;
4344 return writer.print("zon_file('{}')", .{file_path.fmt(zcu.comp)});
42734345 },
42744346 .embed_file => |ef_idx| {
42754347 const ef = ef_idx.get(zcu);
4276 return writer.print("embed_file('{s}')", .{std.fs.path.fmtJoin(&.{
4277 ef.owner.root.root_dir.path orelse "",
4278 ef.owner.root.sub_path,
4279 ef.sub_file_path.toSlice(ip),
4280 })});
4348 return writer.print("embed_file('{}')", .{ef.path.fmt(zcu.comp)});
42814349 },
42824350 .namespace => |ti| {
42834351 const info = ti.resolveFull(ip) orelse {
42844352 return writer.writeAll("namespace(<lost>)");
42854353 };
4286 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4287 return writer.print("namespace('{s}', %{d})", .{ file_path, @intFromEnum(info.inst) });
4354 const file_path = zcu.fileByIndex(info.file).path;
4355 return writer.print("namespace('{}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
42884356 },
42894357 .namespace_name => |k| {
42904358 const info = k.namespace.resolveFull(ip) orelse {
42914359 return writer.print("namespace(<lost>, '{}')", .{k.name.fmt(ip)});
42924360 };
4293 const file_path = zcu.fileByIndex(info.file).sub_file_path;
4294 return writer.print("namespace('{s}', %{d}, '{}')", .{ file_path, @intFromEnum(info.inst), k.name.fmt(ip) });
4361 const file_path = zcu.fileByIndex(info.file).path;
4362 return writer.print("namespace('{}', %{d}, '{}')", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst), k.name.fmt(ip) });
42954363 },
42964364 .memoized_state => return writer.writeAll("memoized_state"),
42974365 }
......@@ -4508,3 +4576,114 @@ pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg)
45084576 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg);
45094577 return error.CodegenFail;
45104578}
4579
4580/// Asserts that `zcu.multi_module_err != null`.
4581pub fn addFileInMultipleModulesError(
4582 zcu: *Zcu,
4583 eb: *std.zig.ErrorBundle.Wip,
4584) !void {
4585 const gpa = zcu.gpa;
4586
4587 const info = zcu.multi_module_err.?;
4588 const file = info.file;
4589
4590 // error: file exists in modules 'root.foo' and 'root.bar'
4591 // note: files must belong to only one module
4592 // note: file is imported here
4593 // note: which is imported here
4594 // note: which is the root of module 'root.foo' imported here
4595 // note: file is the root of module 'root.bar' imported here
4596
4597 const file_src = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb);
4598 const root_msg = try eb.printString("file exists in modules '{s}' and '{s}'", .{
4599 info.modules[0].fully_qualified_name,
4600 info.modules[1].fully_qualified_name,
4601 });
4602
4603 var notes: std.ArrayListUnmanaged(std.zig.ErrorBundle.MessageIndex) = .empty;
4604 defer notes.deinit(gpa);
4605
4606 try notes.append(gpa, try eb.addErrorMessage(.{
4607 .msg = try eb.addString("files must belong to only one module"),
4608 .src_loc = file_src,
4609 }));
4610
4611 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[0], info.refs[0]);
4612 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[1], info.refs[1]);
4613
4614 try eb.addRootErrorMessage(.{
4615 .msg = root_msg,
4616 .src_loc = file_src,
4617 .notes_len = @intCast(notes.items.len),
4618 });
4619 const notes_start = try eb.reserveNotes(@intCast(notes.items.len));
4620 const notes_slice: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]);
4621 @memcpy(notes_slice, notes.items);
4622}
4623
4624fn explainWhyFileIsInModule(
4625 zcu: *Zcu,
4626 eb: *std.zig.ErrorBundle.Wip,
4627 notes_out: *std.ArrayListUnmanaged(std.zig.ErrorBundle.MessageIndex),
4628 file: File.Index,
4629 in_module: *Package.Module,
4630 ref: File.Reference,
4631) !void {
4632 const gpa = zcu.gpa;
4633
4634 // error: file is the root of module 'foo'
4635 //
4636 // error: file is imported here by the root of module 'foo'
4637 //
4638 // error: file is imported here
4639 // note: which is imported here
4640 // note: which is imported here by the root of module 'foo'
4641
4642 var import = switch (ref) {
4643 .analysis_root => |mod| {
4644 assert(mod == in_module);
4645 try notes_out.append(gpa, try eb.addErrorMessage(.{
4646 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}),
4647 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb),
4648 }));
4649 return;
4650 },
4651 .import => |import| if (import.module) |mod| {
4652 assert(mod == in_module);
4653 try notes_out.append(gpa, try eb.addErrorMessage(.{
4654 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}),
4655 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb),
4656 }));
4657 return;
4658 } else import,
4659 };
4660
4661 var is_first = true;
4662 while (true) {
4663 const thing: []const u8 = if (is_first) "file" else "which";
4664 is_first = false;
4665
4666 const import_src = try zcu.fileByIndex(import.importer).errorBundleTokenSrc(import.tok, zcu, eb);
4667
4668 const importer_ref = zcu.alive_files.get(import.importer).?;
4669 const importer_root: ?*Package.Module = switch (importer_ref) {
4670 .analysis_root => |mod| mod,
4671 .import => |i| i.module,
4672 };
4673
4674 if (importer_root) |m| {
4675 try notes_out.append(gpa, try eb.addErrorMessage(.{
4676 .msg = try eb.printString("{s} is imported here by the root of module '{s}'", .{ thing, m.fully_qualified_name }),
4677 .src_loc = import_src,
4678 }));
4679 return;
4680 }
4681
4682 try notes_out.append(gpa, try eb.addErrorMessage(.{
4683 .msg = try eb.printString("{s} is imported here", .{thing}),
4684 .src_loc = import_src,
4685 }));
4686
4687 import = importer_ref.import;
4688 }
4689}
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
......@@ -892,7 +892,7 @@ pub fn generate(
892892 const ip = &zcu.intern_pool;
893893 const func = zcu.funcInfo(func_index);
894894 const fn_type: Type = .fromInterned(func.ty);
895 const mod = zcu.navFileScope(func.owner_nav).mod;
895 const mod = zcu.navFileScope(func.owner_nav).mod.?;
896896
897897 var function: CodeGen = .{
898898 .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