diff --git a/lib/compiler/Maker.zig b/lib/compiler/Maker.zig index d0bea06e27c69d07ac220e41c1add40e3b38c2ff..b372f8999270f53a0ba15e916f7ecb8200ec662a 100644 --- a/lib/compiler/Maker.zig +++ b/lib/compiler/Maker.zig @@ -1399,7 +1399,13 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig { defer compile_prog_node.end(); if (config_man) |man| { - if (.hit == try man.check(compile_prog_node)) { + var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diagnostic, compile_prog_node) catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, + error.CacheCheckFailed => fatal("checking cache failed: {f}", .{diagnostic.fmt(man)}), + }; + log.debug("configuration cache {f}", .{status.fmt(man)}); + if (status == .hit) { const digest = man.hitDigestHex(); const path: Path = .{ .root_dir = graph.local_cache_root, diff --git a/lib/compiler/Maker/Step.zig b/lib/compiler/Maker/Step.zig index 117e9c9df53e3626f0c4cfd259cd41bb41878779..4e9eb614efcea395d8f763e1210de56070fb2743 100644 --- a/lib/compiler/Maker/Step.zig +++ b/lib/compiler/Maker/Step.zig @@ -726,7 +726,10 @@ pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.T /// Prefer `cacheHitWatched` unless you already added watch inputs /// separately from using the cache system. pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool { - const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err)); + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, parent_progress_node) catch |err| + return failWithCacheError(s, maker, man, &diag, err); + const hit = .hit == status; // TODO cache miss reason in the build summary s.result_cached = hit; return hit; } @@ -736,7 +739,10 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n /// /// Must be accompanied with `finalizeManifestAndWatch`. pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool { - const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err)); + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, parent_progress_node) catch |err| + return failWithCacheError(s, maker, man, &diag, err); + const hit = .hit == status; // TODO cache miss reason in the build summary s.result_cached = hit; // The above call to hit() populates the manifest with files, so in case of // a hit, we need to populate watch inputs. @@ -748,20 +754,11 @@ fn failWithCacheError( s: *Step, maker: *Maker, man: *const Cache.Manifest, + diag: *const Cache.Manifest.CheckDiagnostic, err: Cache.Manifest.CheckError, ) error{ OutOfMemory, Canceled, MakeFailed } { switch (err) { - error.CacheCheckFailed => switch (man.diagnostic) { - .none => unreachable, - .manifest_oversize => return s.fail(maker, "checking cache failed: {t}", .{man.diagnostic}), - .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| { - return s.fail(maker, "checking cache failed: {t} {t}", .{ man.diagnostic, e }); - }, - .file_open, .file_stat, .file_read, .file_hash => |op| { - const path = op.path(man); - return s.fail(maker, "checking cache failed: {f} {t} {t}", .{ path, man.diagnostic, op.err }); - }, - }, + error.CacheCheckFailed => return s.fail(maker, "checking cache failed: {f}", .{diag.fmt(man)}), error.OutOfMemory, error.Canceled => |e| return e, } } diff --git a/lib/std/Build/Cache.zig b/lib/std/Build/Cache.zig index 973488702c729c2e246b18db00db4daea831e8df..3eaeef3ab92ab88f11c4da1418aa84fb51c960ef 100644 --- a/lib/std/Build/Cache.zig +++ b/lib/std/Build/Cache.zig @@ -289,7 +289,6 @@ pub const Manifest = struct { /// Indexes line up with `files`, but only up until `hit` is called. Uses /// `Cache.gpa`. input_paths: std.ArrayList(InputPath) = .empty, - diagnostic: Diagnostic = .none, /// Keeps track of the last time we performed a file system write to observe /// what time the file system thinks it is, according to its own granularity. recent_problematic_timestamp: Io.Timestamp = .zero, @@ -591,8 +590,7 @@ pub const Manifest = struct { } }; - pub const Diagnostic = union(enum) { - none, + pub const CheckDiagnostic = union(enum) { manifest_create: Io.File.OpenError, manifest_stat: Io.File.StatError, manifest_oversize, @@ -617,6 +615,31 @@ pub const Manifest = struct { }; } }; + + pub const Format = struct { + diagnostic: CheckDiagnostic, + manifest: *const Manifest, + + pub fn format(this: @This(), w: *Io.Writer) Io.Writer.Error!void { + switch (this.diagnostic) { + .manifest_oversize => return w.writeAll(@tagName(this.diagnostic)), + .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| { + return w.print("{t} {t}", .{ this.diagnostic, e }); + }, + .file_open, .file_stat, .file_read, .file_hash => |op| { + const path = op.path(this.manifest); + return w.print("{t} {t} {f}", .{ this.diagnostic, op.err, path }); + }, + } + } + }; + + pub fn fmt(diagnostic: CheckDiagnostic, manifest: *const Manifest) Format { + return .{ + .diagnostic = diagnostic, + .manifest = manifest, + }; + } }; pub const Stat = struct { @@ -816,6 +839,28 @@ pub const Manifest = struct { directory_status_changed: File.Offset, metadata_changed: File.Offset, contents_changed: File.Offset, + + pub const Format = struct { + check_result: CheckResult, + manifest: *const Manifest, + + pub fn format(this: @This(), w: *Io.Writer) Io.Writer.Error!void { + switch (this.check_result) { + .hit, .incomplete_manifest, .invalid_manifest => return w.writeAll(@tagName(this.check_result)), + .path_deleted, .directory_status_changed, .metadata_changed, .contents_changed => |off| { + const path = off.path(this.manifest.contents.items); + return w.print("{t} {s}", .{ this.check_result, path }); + }, + } + } + }; + + pub fn fmt(check_result: CheckResult, manifest: *const Manifest) Format { + return .{ + .check_result = check_result, + .manifest = manifest, + }; + } }; pub const CheckError = error{ @@ -836,13 +881,17 @@ pub const Manifest = struct { /// The lock on the manifest file is released when `deinit` is called. As another /// option, one may call `toOwnedLock` to obtain a smaller object which can represent /// the lock. `deinit` is safe to call whether or not `toOwnedLock` has been called. - pub fn check(man: *Manifest, parent_progress_node: std.Progress.Node) CheckError!CheckResult { + pub fn check( + man: *Manifest, + diag: *CheckDiagnostic, + parent_progress_node: std.Progress.Node, + ) CheckError!CheckResult { const node = parent_progress_node.start("Reusing Cache Artifacts", 0); defer node.end(); - return checkProgressless(man); + return checkProgressless(man, diag); } - pub fn checkProgressless(man: *Manifest) CheckError!CheckResult { + pub fn checkProgressless(man: *Manifest, diag: *CheckDiagnostic) CheckError!CheckResult { assert(man.state == .input); assert(man.manifest_file == null); @@ -852,8 +901,6 @@ pub const Manifest = struct { man.hashFlagsAndPath(file_off, &man.hash.hasher); } - man.diagnostic = .none; - var input_digest: BinDigest = undefined; man.hash.hasher.final(&input_digest); const input_hex_digest = binToHex(input_digest); @@ -879,10 +926,7 @@ pub const Manifest = struct { man.manifest_file = man.cache.manifest_dir.openFile(io, manifest_file_path, .{ .mode = .read_write, .lock = .shared, - }) catch |e| { - man.diagnostic = .{ .manifest_create = e }; - return error.CacheCheckFailed; - }; + }) catch |e| return fail(diag, .{ .manifest_create = e }); break; }, error.FileNotFound => { @@ -895,10 +939,7 @@ pub const Manifest = struct { // disambiguates by returning EEXIST, indicating original // failure was a race, or ENOENT, indicating deletion of // the directory of our open handle. - if (!builtin.os.tag.isDarwin()) { - man.diagnostic = .{ .manifest_create = error.FileNotFound }; - return error.CacheCheckFailed; - } + if (!builtin.os.tag.isDarwin()) return fail(diag, .{ .manifest_create = error.FileNotFound }); if (man.cache.manifest_dir.createFile(io, manifest_file_path, .{ .read = true, @@ -912,22 +953,13 @@ pub const Manifest = struct { break; } else |excl_err| switch (excl_err) { error.WouldBlock, error.PathAlreadyExists => continue, - error.FileNotFound => { - man.diagnostic = .{ .manifest_create = error.FileNotFound }; - return error.CacheCheckFailed; - }, + error.FileNotFound => return fail(diag, .{ .manifest_create = error.FileNotFound }), error.Canceled => |e| return e, - else => |e| { - man.diagnostic = .{ .manifest_create = e }; - return error.CacheCheckFailed; - }, + else => |e| return fail(diag, .{ .manifest_create = e }), } }, error.Canceled => |e| return e, - else => |e| { - man.diagnostic = .{ .manifest_create = e }; - return error.CacheCheckFailed; - }, + else => |e| return fail(diag, .{ .manifest_create = e }), } } @@ -949,16 +981,16 @@ pub const Manifest = struct { hit: { const miss_result = miss: { - const result = try man.checkLocked(); + const result = try man.checkLocked(diag); if (result == .hit) { break :hit; - } else if (!try man.upgradeToExclusiveLock()) { + } else if (!try man.upgradeToExclusiveLock(diag)) { break :miss result; } // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have // modified the cache directory, so we need to check again before deciding to miss. man.shrinkFilesToInput(); - const refreshed_result = try man.checkLocked(); + const refreshed_result = try man.checkLocked(diag); if (refreshed_result == .hit) break :hit; break :miss refreshed_result; }; @@ -970,10 +1002,7 @@ pub const Manifest = struct { } if (man.want_shared_lock) { - man.downgradeToSharedLock() catch |err| { - man.diagnostic = .{ .manifest_lock = err }; - return error.CacheCheckFailed; - }; + man.downgradeToSharedLock() catch |err| return fail(diag, .{ .manifest_lock = err }); } man.state = .hit; @@ -1006,7 +1035,7 @@ pub const Manifest = struct { } /// Does not observe or modify `self.hash.hasher`. Asserts `self.files` contains only the original input files. - fn checkLocked(m: *Manifest) CheckError!CheckResult { + fn checkLocked(m: *Manifest, diag: *CheckDiagnostic) CheckError!CheckResult { assert(m.files.count() == m.input_paths.items.len); const gpa = m.cache.gpa; const io = m.cache.io; @@ -1014,15 +1043,15 @@ pub const Manifest = struct { const manifest_stat = manifest_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .manifest_stat = e }), + else => |e| return fail(diag, .{ .manifest_stat = e }), }; const manifest_size = std.math.cast(u32, manifest_stat.size) orelse - return fail(&m.diagnostic, .manifest_oversize); + return fail(diag, .manifest_oversize); if (manifest_size == 0 or manifest_size < m.contents.items.len) { // Manifest file was never finalized. try m.contents.ensureUnusedCapacity(gpa, 1); - return populateMissingInputFileHashes(m, 0, .incomplete_manifest); + return populateMissingInputFileHashes(m, diag, 0, .incomplete_manifest); } // We must not clobber existing `Manifest.contents` because it possibly contains prepopulated stat and digest @@ -1039,9 +1068,9 @@ pub const Manifest = struct { { const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .manifest_read = e }), + else => |e| return fail(diag, .{ .manifest_read = e }), }; - if (n != manifest_size) return missInput(m, 0, input_contents_len, manifest_size, .incomplete_manifest); + if (n != manifest_size) return missInput(m, diag, 0, input_contents_len, manifest_size, .incomplete_manifest); } const disk_contents = m.contents.items[0..manifest_size]; const input_contents = m.contents.items[manifest_size..][0..input_contents_len]; @@ -1050,12 +1079,12 @@ pub const Manifest = struct { var off: usize = 0; for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len], 0..) |*input_path, file_off, i| { if (@backingInt(file_off) + 1 >= disk_contents.len) - return missInput(m, i, input_contents_len, manifest_size, .incomplete_manifest); + return missInput(m, diag, i, input_contents_len, manifest_size, .incomplete_manifest); if (!mem.eql(u8, file_off.flagsAndPath(disk_contents), file_off.flagsAndPath(input_contents))) - return missInput(m, i, input_contents_len, manifest_size, .invalid_manifest); + return missInput(m, diag, i, input_contents_len, manifest_size, .invalid_manifest); - const result = try checkInputPath(m, file_off, input_path, disk_contents, input_contents); - if (result != .hit) return missInput(m, i + 1, input_contents_len, manifest_size, result); + const result = try checkInputPath(m, diag, file_off, input_path, disk_contents, input_contents); + if (result != .hit) return missInput(m, diag, i + 1, input_contents_len, manifest_size, result); off = @backingInt(file_off); } @@ -1074,7 +1103,7 @@ pub const Manifest = struct { if (path.len == 0) return .invalid_manifest; try m.files.putContext(gpa, file_off, {}, .{ .contents = disk_contents }); - const result = try checkDiscoveredPath(m, file_off, disk_contents); + const result = try checkDiscoveredPath(m, diag, file_off, disk_contents); if (result != .hit) return result; off += File.sizeOf(path.len); @@ -1098,6 +1127,7 @@ pub const Manifest = struct { /// missed one. fn missInput( m: *Manifest, + diag: *CheckDiagnostic, next_file_index: usize, input_contents_len: usize, manifest_size: usize, @@ -1114,18 +1144,19 @@ pub const Manifest = struct { m.contents.items[manifest_size + off ..][0..copy_len], ); m.contents.shrinkRetainingCapacity(input_contents_len); - return populateMissingInputFileHashes(m, next_file_index, result); + return populateMissingInputFileHashes(m, diag, next_file_index, result); } fn populateMissingInputFileHashes( m: *Manifest, + diag: *CheckDiagnostic, next_file_index: usize, result: CheckResult, ) CheckError!CheckResult { const file_offs = m.files.keys(); const contents = m.contents.items; for (file_offs[next_file_index..], m.input_paths.items[next_file_index..]) |input_file_off, *input_path| { - try populateInputPath(m, input_file_off, input_path, contents); + try populateInputPath(m, diag, input_file_off, input_path, contents); } return result; } @@ -1134,6 +1165,7 @@ pub const Manifest = struct { /// system. Only ensures that metadata and digest are available. fn populateInputPath( m: *Manifest, + diag: *CheckDiagnostic, file_off: File.Offset, input_path: *InputPath, contents: []u8, @@ -1156,21 +1188,21 @@ pub const Manifest = struct { const actual_stat = switch (input_path.getHandle(input_file)) { .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), }, .file => |opened_file| opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), }, .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1179,7 +1211,7 @@ pub const Manifest = struct { const actual_is_directory = actual_stat.kind == .directory; if (actual_is_directory != input_file.flags.is_directory) { // Since this is an input file, this is a failure, not a cache miss. - return fail(&m.diagnostic, .{ .file_stat = .{ + return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = if (actual_is_directory) error.IsDir else error.NotDir, } }); @@ -1210,7 +1242,7 @@ pub const Manifest = struct { .access_sub_paths = false, }) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1224,7 +1256,7 @@ pub const Manifest = struct { assert(!stat_path_ok); const actual_stat = opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1235,7 +1267,7 @@ pub const Manifest = struct { const dir_contents_start = m.all_input_content.items.len; hashDir(gpa, io, opened_dir, &input_file.digest, &m.all_input_content) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1254,7 +1286,7 @@ pub const Manifest = struct { else parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1268,7 +1300,7 @@ pub const Manifest = struct { assert(!stat_path_ok); const actual_stat = opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1281,7 +1313,7 @@ pub const Manifest = struct { const start = m.all_input_content.items.len; hashFileAppend(io, opened_file, &input_file.digest, &m.all_input_content, gpa) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1293,7 +1325,7 @@ pub const Manifest = struct { }, .unrequested => hashFile(io, opened_file, &input_file.digest) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1306,6 +1338,7 @@ pub const Manifest = struct { /// Upon return, disk_contents digest and stat will be populated regardless of whether hit or miss occurs. fn checkInputPath( m: *Manifest, + diag: *CheckDiagnostic, file_off: File.Offset, input_path: *InputPath, disk_contents: []u8, @@ -1337,21 +1370,21 @@ pub const Manifest = struct { const actual_stat = switch (input_path.getHandle(input_file)) { .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), }, .file => |opened_file| opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), }, .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1362,7 +1395,7 @@ pub const Manifest = struct { const actual_is_directory = actual_stat.kind == .directory; if (actual_is_directory != disk_file.flags.is_directory) { // Since this is an input file, this is a failure, not a cache miss. - return fail(&m.diagnostic, .{ .file_stat = .{ + return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = if (actual_is_directory) error.IsDir else error.NotDir, } }); @@ -1393,7 +1426,7 @@ pub const Manifest = struct { .access_sub_paths = false, }) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1406,7 +1439,7 @@ pub const Manifest = struct { if (!input_path.have_stat) { const actual_stat = opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1417,7 +1450,7 @@ pub const Manifest = struct { const dir_contents_start = m.all_input_content.items.len; hashDir(gpa, io, opened_dir, &disk_file.digest, &m.all_input_content) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1439,7 +1472,7 @@ pub const Manifest = struct { else parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1452,7 +1485,7 @@ pub const Manifest = struct { if (!input_path.have_stat) { const actual_stat = opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1465,7 +1498,7 @@ pub const Manifest = struct { const start = m.all_input_content.items.len; hashFileAppend(io, opened_file, &disk_file.digest, &m.all_input_content, gpa) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1477,7 +1510,7 @@ pub const Manifest = struct { }, .unrequested => hashFile(io, opened_file, &disk_file.digest) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1490,7 +1523,12 @@ pub const Manifest = struct { } } - fn checkDiscoveredPath(m: *Manifest, file_off: File.Offset, contents: []u8) CheckError!CheckResult { + fn checkDiscoveredPath( + m: *Manifest, + diag: *CheckDiagnostic, + file_off: File.Offset, + contents: []u8, + ) CheckError!CheckResult { const file = file_off.get(contents); const cache = m.cache; const gpa = cache.gpa; @@ -1502,7 +1540,7 @@ pub const Manifest = struct { const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) { error.FileNotFound => return .{ .path_deleted = file_off }, error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1525,7 +1563,7 @@ pub const Manifest = struct { error.FileNotFound => return .{ .path_deleted = file_off }, error.NotDir => return .{ .directory_status_changed = file_off }, error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1534,7 +1572,7 @@ pub const Manifest = struct { const actual_stat = opened_dir.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1545,7 +1583,7 @@ pub const Manifest = struct { defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start); hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1560,7 +1598,7 @@ pub const Manifest = struct { error.FileNotFound => return .{ .path_deleted = file_off }, error.IsDir => return .{ .directory_status_changed = file_off }, error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_open = .{ + else => |e| return fail(diag, .{ .file_open = .{ .file_offset = file_off, .err = e, } }), @@ -1569,7 +1607,7 @@ pub const Manifest = struct { const actual_stat = opened_file.stat(io) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_stat = .{ + else => |e| return fail(diag, .{ .file_stat = .{ .file_offset = file_off, .err = e, } }), @@ -1579,7 +1617,7 @@ pub const Manifest = struct { const prev_digest: BinDigest = file.digest; hashFile(io, opened_file, &file.digest) catch |err| switch (err) { error.Canceled => |e| return e, - else => |e| return fail(&m.diagnostic, .{ .file_read = .{ + else => |e| return fail(diag, .{ .file_read = .{ .file_offset = file_off, .err = e, } }), @@ -1591,8 +1629,7 @@ pub const Manifest = struct { return .hit; } - fn fail(ptr: *Diagnostic, d: Diagnostic) error{CacheCheckFailed} { - assert(ptr.* == .none); + fn fail(ptr: *CheckDiagnostic, d: CheckDiagnostic) error{CacheCheckFailed} { ptr.* = d; return error.CacheCheckFailed; } @@ -2002,22 +2039,19 @@ pub const Manifest = struct { self.have_exclusive_lock = false; } - fn upgradeToExclusiveLock(self: *Manifest) error{CacheCheckFailed}!bool { - if (self.have_exclusive_lock) return false; - assert(self.manifest_file != null); - const io = self.cache.io; + fn upgradeToExclusiveLock(m: *Manifest, diag: *CheckDiagnostic) error{CacheCheckFailed}!bool { + if (m.have_exclusive_lock) return false; + assert(m.manifest_file != null); + const io = m.cache.io; if (std.process.can_spawn or !builtin.single_threaded) { - const manifest_file = self.manifest_file.?; + const manifest_file = m.manifest_file.?; // Here we intentionally have a period where the lock is released, in case there are // other processes holding a shared lock. manifest_file.unlock(io); - manifest_file.lock(io, .exclusive) catch |err| { - self.diagnostic = .{ .manifest_lock = err }; - return error.CacheCheckFailed; - }; + manifest_file.lock(io, .exclusive) catch |err| return fail(diag, .{ .manifest_lock = err }); } - self.have_exclusive_lock = true; + m.have_exclusive_lock = true; return true; } @@ -2327,7 +2361,8 @@ test "cache file and then recall it" { .sub_path = temp_file, }, .{}); - try testing.expectEqual(.incomplete_manifest, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none)); digest1 = man.missDigestHex(); try man.finalize(); @@ -2345,7 +2380,8 @@ test "cache file and then recall it" { }, .{}); // Cache hit! We just "built" the same file - try testing.expectEqual(.hit, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.hit, try man.check(&diag, .none)); digest2 = man.hitDigestHex(); try testing.expectEqual(false, man.have_exclusive_lock); @@ -2406,7 +2442,8 @@ test "check that changing a file causes cache miss" { .sub_path = temp_file, }, .{ .request_contents = true }); - try testing.expectEqual(.incomplete_manifest, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none)); try testing.expectEqualStrings(original_temp_file_contents, temp_file_idx.contents(&man)); @@ -2428,9 +2465,10 @@ test "check that changing a file causes cache miss" { }, .{ .request_contents = true }); // The one input file changed. + var diag: Manifest.CheckDiagnostic = undefined; try testing.expectEqual( @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }), - try man.check(.none), + try man.check(&diag, .none), ); try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man)); @@ -2473,7 +2511,8 @@ test "no file inputs" { man.hash.addBytes("1234"); - try testing.expectEqual(.incomplete_manifest, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none)); digest1 = man.missDigestHex(); @@ -2485,7 +2524,8 @@ test "no file inputs" { man.hash.addBytes("1234"); - try testing.expectEqual(.hit, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.hit, try man.check(&diag, .none)); digest2 = man.hitDigestHex(); try testing.expectEqual(false, man.have_exclusive_lock); } @@ -2545,7 +2585,8 @@ test "Manifest with files added after initial hash" { .sub_path = temp_file1, }, .{}); - try testing.expectEqual(.incomplete_manifest, try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none)); try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .{ .root_dir = tmp_directory, @@ -2565,7 +2606,8 @@ test "Manifest with files added after initial hash" { .sub_path = temp_file1, }, .{}); - try testing.expect(.hit == try man.check(.none)); + var diag: Manifest.CheckDiagnostic = undefined; + try testing.expect(.hit == try man.check(&diag, .none)); digest2 = man.hitDigestHex(); try testing.expectEqual(false, man.have_exclusive_lock); @@ -2591,7 +2633,8 @@ test "Manifest with files added after initial hash" { .sub_path = temp_file1, }, .{}); - switch (try man.check(.none)) { + var diag: Manifest.CheckDiagnostic = undefined; + switch (try man.check(&diag, .none)) { .contents_changed => |off| { try testing.expectEqualStrings(temp_file2, off.path(man.contents.items)); }, diff --git a/src/Compilation.zig b/src/Compilation.zig index 68c76dfd83bce307a45af5d0ed0c35f126316c64..5b3131bf8734ffec53c0bfed5fc04d119716b313 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2813,27 +2813,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE man.want_shared_lock = false; } - const status = man.check(main_progress_node) catch |err| switch (err) { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, main_progress_node) catch |err| switch (err) { error.Canceled, error.OutOfMemory => |e| return e, - error.CacheCheckFailed => switch (man.diagnostic) { - .none => unreachable, - .manifest_oversize => { - return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {t}", .{ - man.diagnostic, - }); - }, - .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| { - return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {t} {t}", .{ - man.diagnostic, e, - }); - }, - .file_open, .file_stat, .file_read, .file_hash => |op| { - return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f} {t} {t}", .{ - op.path(&man), man.diagnostic, op.err, - }); - }, + error.CacheCheckFailed => { + return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f}", .{diag.fmt(&man)}); }, }; + log.debug("{s} whole cache {f} ignore_hit={}", .{ comp.root_name, status.fmt(&man), ignore_hit }); if (status == .hit and !ignore_hit) { // In this case the cache hit contains the full set of file system inputs. Nice! if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf); @@ -2844,7 +2831,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE } comp.last_update_was_cache_hit = true; - log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name}); const bin_digest = man.hitDigest(); comp.digest = bin_digest; @@ -2853,7 +2839,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE whole.lock = man.toOwnedLock(); return; } - log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name}); if (ignore_hit) { // Okay, now set this back so that `Manifest.finalize` will downgrade our lock later. @@ -5536,7 +5521,18 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr const target = comp.getTarget(); assert(target.ofmt != .c); const o_ext = target.ofmt.fileExt(target.cpu.arch); - const digest = if (!comp.disable_c_depfile and .hit == try man.check(child_progress_node)) man.hitDigestHex() else miss: { + const digest = d: { + if (!comp.disable_c_depfile) { + var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { + error.Canceled, error.OutOfMemory => |e| return e, + error.CacheCheckFailed => { + return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); + }, + }; + log.debug("C object cache {f}", .{status.fmt(&man)}); + if (status == .hit) break :d man.hitDigestHex(); + } var argv: std.array_list.Managed([]const u8) = .init(gpa); defer argv.deinit(); @@ -5811,16 +5807,28 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr } // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock. - if (comp.disable_c_depfile) _ = try man.check(child_progress_node); + const digest = inner: { + if (comp.disable_c_depfile) { + var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => { + return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)}); + }, + }; + log.debug("ignored C object cache {f}", .{status.fmt(&man)}); + if (status == .hit) break :inner man.hitDigestHex(); + } + break :inner man.missDigestHex(); + }; // Rename into place. - const digest = man.missDigestHex(); const o_sub_path = try fs.path.join(arena, &.{ "o", &digest }); var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{}); defer o_dir.close(io); const tmp_basename = fs.path.basename(out_obj_path); try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io); - break :miss digest; + break :d digest; }; if (man.have_exclusive_lock) { @@ -5896,7 +5904,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename}); const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename}); - const digest = if (.hit == try man.check(child_progress_node)) man.hitDigestHex() else blk: { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, child_progress_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ + diag.fmt(&man), + }), + }; + log.debug("win32 resource cache {f}", .{status.fmt(&man)}); + const digest = if (status == .hit) man.hitDigestHex() else miss: { // The digest only depends on the .manifest file, so we can // get the digest now and write the .res directly to the cache const digest = man.missDigestHex(); @@ -5961,7 +5977,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node); - break :blk digest; + break :miss digest; }; if (man.have_exclusive_lock) { @@ -5988,7 +6004,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len]; - const digest = if (.hit == try man.check(child_progress_node)) man.hitDigestHex() else blk: { + var diagnostic: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{ + diagnostic.fmt(&man), + }), + }; + log.debug("win32 resource cache {f}", .{status.fmt(&man)}); + const digest = if (status == .hit) man.hitDigestHex() else miss: { var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{}); defer zig_cache_tmp_dir.close(io); @@ -6066,7 +6090,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32 defer o_dir.close(io); const tmp_basename = fs.path.basename(out_res_path); try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io); - break :blk digest; + break :miss digest; }; if (man.have_exclusive_lock) { diff --git a/src/Sema.zig b/src/Sema.zig index 1090ecd135c01218c2020d740b8eada0bc5fef26..a3533e99233d4e8f8e0d61184d65733906d1ad86 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -12974,7 +12974,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const result = ef_idx.get(zcu); if (result.val == .none) { - return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(result.err.?) }); + return sema.fail(block, operand_src, "failed opening {q}: {t}", .{ name, result.err.? }); } return Air.internedToRef(result.val); @@ -15911,9 +15911,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?; const tree = file.getTree(zcu) catch |err| { // In this case we emit a warning + a less precise source location. - log.warn("unable to load {f}: {s}", .{ - file.path.fmt(zcu.comp), @errorName(err), - }); + log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err }); break :name null; }; const node = src_node.toAbsolute(src_base_node); @@ -15939,9 +15937,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?; const tree = file.getTree(zcu) catch |err| { // In this case we emit a warning + a less precise source location. - log.warn("unable to load {f}: {s}", .{ - file.path.fmt(zcu.comp), @errorName(err), - }); + log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err }); break :name null; }; const node = src_node.toAbsolute(src_base_node); @@ -15950,7 +15946,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat }; const msg = if (name) |some| - try sema.errMsg(src, "'{s}' not accessible from inner function", .{some}) + try sema.errMsg(src, "{q} not accessible from inner function", .{some}) else try sema.errMsg(src, "variable not accessible from inner function", .{}); errdefer msg.destroy(sema.gpa); diff --git a/src/libs/freebsd.zig b/src/libs/freebsd.zig index 36062854757ac0b1369c0712031f80e806f453f4..584a6b63b69adae9e3427334567bd41357056543 100644 --- a/src/libs/freebsd.zig +++ b/src/libs/freebsd.zig @@ -465,7 +465,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye .request_contents = true, }); - if (.hit == try man.check(prog_node)) { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => { + comp.lockAndSetMiscFailure( + .freebsd_shared_objects, + "compiling FreeBSD libc shared objects: checking cache failed: {f}", + .{diag.fmt(&man)}, + ); + return error.AlreadyReported; + }, + }; + log.debug("freebsd_shared_objects cache {f}", .{status.fmt(&man)}); + if (status == .hit) { const digest = man.hitDigestHex(); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/glibc.zig b/src/libs/glibc.zig index 691da1bd0f047f527c37c4b850cdceea7dd036a8..86c5360cc17cce248afeac8ddcfb5bb4b2f9ceca 100644 --- a/src/libs/glibc.zig +++ b/src/libs/glibc.zig @@ -705,7 +705,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye .request_contents = true, }); - if (.hit == try man.check(prog_node)) { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => { + comp.lockAndSetMiscFailure( + .glibc_shared_objects, + "compiling glibc shared objects: checking cache failed: {f}", + .{diag.fmt(&man)}, + ); + return error.AlreadyReported; + }, + }; + log.debug("glibc_shared_objects cache {f}", .{status.fmt(&man)}); + if (status == .hit) { const digest = man.hitDigestHex(); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/mingw.zig b/src/libs/mingw.zig index 59d99a783af2af8053dcfb629ce1c48ee672f262..61dbd5dfb064aa52631efd77837b23013a8214dc 100644 --- a/src/libs/mingw.zig +++ b/src/libs/mingw.zig @@ -251,26 +251,17 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name}); errdefer gpa.free(final_lib_basename); - const status = man.check(prog_node) catch |err| switch (err) { - error.CacheCheckFailed => switch (man.diagnostic) { - .none => unreachable, - .manifest_oversize => { - comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t}", .{man.diagnostic}); - return error.AlreadyReported; - }, - .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| { - comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t} {t}", .{ man.diagnostic, e }); - return error.AlreadyReported; - }, - .file_open, .file_stat, .file_read, .file_hash => |op| { - comp.setMiscFailure(.windows_import_lib, "checking cache failed: {f} {t} {t}", .{ - op.path(&man), man.diagnostic, op.err, - }); - return error.AlreadyReported; - }, + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.CacheCheckFailed => { + comp.setMiscFailure(.windows_import_lib, "{s} cache check failed: {f}", .{ + final_lib_basename, diag.fmt(&man), + }); + return error.AlreadyReported; }, error.OutOfMemory, error.Canceled => |e| return e, }; + log.debug("{s} cache {f}", .{ final_lib_basename, status.fmt(&man) }); if (status == .hit) { const digest = man.hitDigestHex(); const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename }); diff --git a/src/libs/netbsd.zig b/src/libs/netbsd.zig index 5445f5fcaab4906ada5cc8950ef403fb4fc825f6..46a34b96a55943f84a92914521a730c27d0d19a7 100644 --- a/src/libs/netbsd.zig +++ b/src/libs/netbsd.zig @@ -413,7 +413,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye .request_contents = true, }); - if (.hit == try man.check(prog_node)) { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.CacheCheckFailed => { + comp.lockAndSetMiscFailure( + .netbsd_shared_objects, + "compiling NetBSD libc shared objects: checking cache failed: {f}", + .{diag.fmt(&man)}, + ); + return error.AlreadyReported; + }, + error.OutOfMemory, error.Canceled => |e| return e, + }; + log.debug("netbsd_shared_objects cache {f}", .{status.fmt(&man)}); + if (status == .hit) { const digest = man.hitDigestHex(); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/libs/openbsd.zig b/src/libs/openbsd.zig index ab126f2a96aa9dce467620052d07a5af8f965e49..4bea660a65eed944eb93d48f27c5cc70a0369a8d 100644 --- a/src/libs/openbsd.zig +++ b/src/libs/openbsd.zig @@ -334,7 +334,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye .request_contents = true, }); - if (.hit == try man.check(prog_node)) { + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => { + comp.lockAndSetMiscFailure( + .openbsd_shared_objects, + "compiling OpenBSD libc shared objects: checking cache failed: {f}", + .{diag.fmt(&man)}, + ); + return error.AlreadyReported; + }, + }; + log.debug("openbsd_shared_objects cache {f}", .{status.fmt(&man)}); + if (status == .hit) { const digest = man.hitDigestHex(); return queueSharedObjects(comp, .{ .lock = man.toOwnedLock(), diff --git a/src/main.zig b/src/main.zig index 6bcb22f26e15180f6526022a4da12ea7393cbed8..a4299f4f896ba5f1118a1e8d81dfa5a9522cff1c 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4878,7 +4878,13 @@ fn cmdTranslateC( Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err| fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err }); - const result: Compilation.TranslateCResult = if (.hit == try man.check(prog_node)) .{ + var diag: Cache.Manifest.CheckDiagnostic = undefined; + const status = man.check(&diag, prog_node) catch |err| switch (err) { + error.OutOfMemory, error.Canceled => |e| return e, + error.CacheCheckFailed => fatal("translate-c checking cache failed: {f}", .{diag.fmt(&man)}), + }; + std.log.debug("translate-c cache {f}", .{status.fmt(&man)}); + const result: Compilation.TranslateCResult = if (status == .hit) .{ .digest = man.hitDigest(), .cache_hit = true, .errors = std.zig.ErrorBundle.empty, diff --git a/test/incremental/bad_import b/test/incremental/bad_import index ab6369bee38a0d8c0c3e01b42458cc52051e4f5f..fd91fa66050e2ae3cb1407382d5f173bdb2fe884 100644 --- a/test/incremental/bad_import +++ b/test/incremental/bad_import @@ -10,7 +10,7 @@ const io = std.Io.Threaded.global_single_threaded.io(); comptime { _ = @import("bad.zig"); } -#expect_error=bad.zig:1:1: error: unable to load 'bad.zig': FileNotFound +#expect_error=bad.zig:1:1: error: unable to load "bad.zig": FileNotFound #expect_error=foo.zig:2:17: note: file imported here #update=change bad import @@ -18,7 +18,7 @@ comptime { comptime { _ = @import("this_is/not_real.zig"); } -#expect_error=this_is/not_real.zig:1:1: error: unable to load 'not_real.zig': FileNotFound +#expect_error=this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound #expect_error=foo.zig:2:17: note: file imported here #update=remove import of 'foo.zig' diff --git a/test/incremental/change_embed_file b/test/incremental/change_embed_file index 34efcdcc5a4fb112e35c862173e85afd96a15ddd..8b515d2d980c9ee68da186c8fa149b5b19c2ed20 100644 --- a/test/incremental/change_embed_file +++ b/test/incremental/change_embed_file @@ -17,7 +17,7 @@ Hello again, World! #update=delete file #rm_file=string.txt -#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound +#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound #update=remove reference to file #file=main.zig @@ -37,7 +37,7 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, string); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound +#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound #update=recreate file #file=string.txt diff --git a/test/incremental/change_zon_file b/test/incremental/change_zon_file index 080dc235199d21b5dded5136bd6baf04b72142a0..7616c53ea80094d746102df13d51e387a3d1bc40 100644 --- a/test/incremental/change_zon_file +++ b/test/incremental/change_zon_file @@ -17,7 +17,7 @@ const io = std.Io.Threaded.global_single_threaded.io(); #update=delete file #rm_file=message.zon -#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound +#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound #expect_error=main.zig:2:37: note: file imported here #update=remove reference to ZON file @@ -28,7 +28,7 @@ pub fn main() !void { try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n"); } const io = std.Io.Threaded.global_single_threaded.io(); -#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound +#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound #expect_error=main.zig:2:37: note: file imported here #update=recreate ZON file