authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-15 17:00:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 13:12:47-07:00
log597306838dcc4802c17e94ba156ccf3912e9934c
tree2eba931f1c697dbb4e5cd0cae27f4ece04c41a8b
parente8882ffcf0d97cabfc974bdbc1c592f911832623

frontend: better error reporting for cache check failures


14 files changed, 292 insertions(+), 177 deletions(-)

lib/compiler/Maker.zig+7-1
......@@ -1399,7 +1399,13 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
13991399 defer compile_prog_node.end();
14001400
14011401 if (config_man) |man| {
1402 if (.hit == try man.check(compile_prog_node)) {
1402 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined;
1403 const status = man.check(&diagnostic, compile_prog_node) catch |err| switch (err) {
1404 error.Canceled, error.OutOfMemory => |e| return e,
1405 error.CacheCheckFailed => fatal("checking cache failed: {f}", .{diagnostic.fmt(man)}),
1406 };
1407 log.debug("configuration cache {f}", .{status.fmt(man)});
1408 if (status == .hit) {
14031409 const digest = man.hitDigestHex();
14041410 const path: Path = .{
14051411 .root_dir = graph.local_cache_root,
lib/compiler/Maker/Step.zig+10-13
......@@ -726,7 +726,10 @@ pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.T
726726/// Prefer `cacheHitWatched` unless you already added watch inputs
727727/// separately from using the cache system.
728728pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {
729 const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err));
729 var diag: Cache.Manifest.CheckDiagnostic = undefined;
730 const status = man.check(&diag, parent_progress_node) catch |err|
731 return failWithCacheError(s, maker, man, &diag, err);
732 const hit = .hit == status; // TODO cache miss reason in the build summary
730733 s.result_cached = hit;
731734 return hit;
732735}
......@@ -736,7 +739,10 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n
736739///
737740/// Must be accompanied with `finalizeManifestAndWatch`.
738741pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {
739 const hit = .hit == (man.check(parent_progress_node) catch |err| return failWithCacheError(s, maker, man, err));
742 var diag: Cache.Manifest.CheckDiagnostic = undefined;
743 const status = man.check(&diag, parent_progress_node) catch |err|
744 return failWithCacheError(s, maker, man, &diag, err);
745 const hit = .hit == status; // TODO cache miss reason in the build summary
740746 s.result_cached = hit;
741747 // The above call to hit() populates the manifest with files, so in case of
742748 // a hit, we need to populate watch inputs.
......@@ -748,20 +754,11 @@ fn failWithCacheError(
748754 s: *Step,
749755 maker: *Maker,
750756 man: *const Cache.Manifest,
757 diag: *const Cache.Manifest.CheckDiagnostic,
751758 err: Cache.Manifest.CheckError,
752759) error{ OutOfMemory, Canceled, MakeFailed } {
753760 switch (err) {
754 error.CacheCheckFailed => switch (man.diagnostic) {
755 .none => unreachable,
756 .manifest_oversize => return s.fail(maker, "checking cache failed: {t}", .{man.diagnostic}),
757 .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| {
758 return s.fail(maker, "checking cache failed: {t} {t}", .{ man.diagnostic, e });
759 },
760 .file_open, .file_stat, .file_read, .file_hash => |op| {
761 const path = op.path(man);
762 return s.fail(maker, "checking cache failed: {f} {t} {t}", .{ path, man.diagnostic, op.err });
763 },
764 },
761 error.CacheCheckFailed => return s.fail(maker, "checking cache failed: {f}", .{diag.fmt(man)}),
765762 error.OutOfMemory, error.Canceled => |e| return e,
766763 }
767764}
lib/std/Build/Cache.zig+142-99
......@@ -289,7 +289,6 @@ pub const Manifest = struct {
289289 /// Indexes line up with `files`, but only up until `hit` is called. Uses
290290 /// `Cache.gpa`.
291291 input_paths: std.ArrayList(InputPath) = .empty,
292 diagnostic: Diagnostic = .none,
293292 /// Keeps track of the last time we performed a file system write to observe
294293 /// what time the file system thinks it is, according to its own granularity.
295294 recent_problematic_timestamp: Io.Timestamp = .zero,
......@@ -591,8 +590,7 @@ pub const Manifest = struct {
591590 }
592591 };
593592
594 pub const Diagnostic = union(enum) {
595 none,
593 pub const CheckDiagnostic = union(enum) {
596594 manifest_create: Io.File.OpenError,
597595 manifest_stat: Io.File.StatError,
598596 manifest_oversize,
......@@ -617,6 +615,31 @@ pub const Manifest = struct {
617615 };
618616 }
619617 };
618
619 pub const Format = struct {
620 diagnostic: CheckDiagnostic,
621 manifest: *const Manifest,
622
623 pub fn format(this: @This(), w: *Io.Writer) Io.Writer.Error!void {
624 switch (this.diagnostic) {
625 .manifest_oversize => return w.writeAll(@tagName(this.diagnostic)),
626 .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| {
627 return w.print("{t} {t}", .{ this.diagnostic, e });
628 },
629 .file_open, .file_stat, .file_read, .file_hash => |op| {
630 const path = op.path(this.manifest);
631 return w.print("{t} {t} {f}", .{ this.diagnostic, op.err, path });
632 },
633 }
634 }
635 };
636
637 pub fn fmt(diagnostic: CheckDiagnostic, manifest: *const Manifest) Format {
638 return .{
639 .diagnostic = diagnostic,
640 .manifest = manifest,
641 };
642 }
620643 };
621644
622645 pub const Stat = struct {
......@@ -816,6 +839,28 @@ pub const Manifest = struct {
816839 directory_status_changed: File.Offset,
817840 metadata_changed: File.Offset,
818841 contents_changed: File.Offset,
842
843 pub const Format = struct {
844 check_result: CheckResult,
845 manifest: *const Manifest,
846
847 pub fn format(this: @This(), w: *Io.Writer) Io.Writer.Error!void {
848 switch (this.check_result) {
849 .hit, .incomplete_manifest, .invalid_manifest => return w.writeAll(@tagName(this.check_result)),
850 .path_deleted, .directory_status_changed, .metadata_changed, .contents_changed => |off| {
851 const path = off.path(this.manifest.contents.items);
852 return w.print("{t} {s}", .{ this.check_result, path });
853 },
854 }
855 }
856 };
857
858 pub fn fmt(check_result: CheckResult, manifest: *const Manifest) Format {
859 return .{
860 .check_result = check_result,
861 .manifest = manifest,
862 };
863 }
819864 };
820865
821866 pub const CheckError = error{
......@@ -836,13 +881,17 @@ pub const Manifest = struct {
836881 /// The lock on the manifest file is released when `deinit` is called. As another
837882 /// option, one may call `toOwnedLock` to obtain a smaller object which can represent
838883 /// the lock. `deinit` is safe to call whether or not `toOwnedLock` has been called.
839 pub fn check(man: *Manifest, parent_progress_node: std.Progress.Node) CheckError!CheckResult {
884 pub fn check(
885 man: *Manifest,
886 diag: *CheckDiagnostic,
887 parent_progress_node: std.Progress.Node,
888 ) CheckError!CheckResult {
840889 const node = parent_progress_node.start("Reusing Cache Artifacts", 0);
841890 defer node.end();
842 return checkProgressless(man);
891 return checkProgressless(man, diag);
843892 }
844893
845 pub fn checkProgressless(man: *Manifest) CheckError!CheckResult {
894 pub fn checkProgressless(man: *Manifest, diag: *CheckDiagnostic) CheckError!CheckResult {
846895 assert(man.state == .input);
847896 assert(man.manifest_file == null);
848897
......@@ -852,8 +901,6 @@ pub const Manifest = struct {
852901 man.hashFlagsAndPath(file_off, &man.hash.hasher);
853902 }
854903
855 man.diagnostic = .none;
856
857904 var input_digest: BinDigest = undefined;
858905 man.hash.hasher.final(&input_digest);
859906 const input_hex_digest = binToHex(input_digest);
......@@ -879,10 +926,7 @@ pub const Manifest = struct {
879926 man.manifest_file = man.cache.manifest_dir.openFile(io, manifest_file_path, .{
880927 .mode = .read_write,
881928 .lock = .shared,
882 }) catch |e| {
883 man.diagnostic = .{ .manifest_create = e };
884 return error.CacheCheckFailed;
885 };
929 }) catch |e| return fail(diag, .{ .manifest_create = e });
886930 break;
887931 },
888932 error.FileNotFound => {
......@@ -895,10 +939,7 @@ pub const Manifest = struct {
895939 // disambiguates by returning EEXIST, indicating original
896940 // failure was a race, or ENOENT, indicating deletion of
897941 // the directory of our open handle.
898 if (!builtin.os.tag.isDarwin()) {
899 man.diagnostic = .{ .manifest_create = error.FileNotFound };
900 return error.CacheCheckFailed;
901 }
942 if (!builtin.os.tag.isDarwin()) return fail(diag, .{ .manifest_create = error.FileNotFound });
902943
903944 if (man.cache.manifest_dir.createFile(io, manifest_file_path, .{
904945 .read = true,
......@@ -912,22 +953,13 @@ pub const Manifest = struct {
912953 break;
913954 } else |excl_err| switch (excl_err) {
914955 error.WouldBlock, error.PathAlreadyExists => continue,
915 error.FileNotFound => {
916 man.diagnostic = .{ .manifest_create = error.FileNotFound };
917 return error.CacheCheckFailed;
918 },
956 error.FileNotFound => return fail(diag, .{ .manifest_create = error.FileNotFound }),
919957 error.Canceled => |e| return e,
920 else => |e| {
921 man.diagnostic = .{ .manifest_create = e };
922 return error.CacheCheckFailed;
923 },
958 else => |e| return fail(diag, .{ .manifest_create = e }),
924959 }
925960 },
926961 error.Canceled => |e| return e,
927 else => |e| {
928 man.diagnostic = .{ .manifest_create = e };
929 return error.CacheCheckFailed;
930 },
962 else => |e| return fail(diag, .{ .manifest_create = e }),
931963 }
932964 }
933965
......@@ -949,16 +981,16 @@ pub const Manifest = struct {
949981
950982 hit: {
951983 const miss_result = miss: {
952 const result = try man.checkLocked();
984 const result = try man.checkLocked(diag);
953985 if (result == .hit) {
954986 break :hit;
955 } else if (!try man.upgradeToExclusiveLock()) {
987 } else if (!try man.upgradeToExclusiveLock(diag)) {
956988 break :miss result;
957989 }
958990 // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have
959991 // modified the cache directory, so we need to check again before deciding to miss.
960992 man.shrinkFilesToInput();
961 const refreshed_result = try man.checkLocked();
993 const refreshed_result = try man.checkLocked(diag);
962994 if (refreshed_result == .hit) break :hit;
963995 break :miss refreshed_result;
964996 };
......@@ -970,10 +1002,7 @@ pub const Manifest = struct {
9701002 }
9711003
9721004 if (man.want_shared_lock) {
973 man.downgradeToSharedLock() catch |err| {
974 man.diagnostic = .{ .manifest_lock = err };
975 return error.CacheCheckFailed;
976 };
1005 man.downgradeToSharedLock() catch |err| return fail(diag, .{ .manifest_lock = err });
9771006 }
9781007
9791008 man.state = .hit;
......@@ -1006,7 +1035,7 @@ pub const Manifest = struct {
10061035 }
10071036
10081037 /// Does not observe or modify `self.hash.hasher`. Asserts `self.files` contains only the original input files.
1009 fn checkLocked(m: *Manifest) CheckError!CheckResult {
1038 fn checkLocked(m: *Manifest, diag: *CheckDiagnostic) CheckError!CheckResult {
10101039 assert(m.files.count() == m.input_paths.items.len);
10111040 const gpa = m.cache.gpa;
10121041 const io = m.cache.io;
......@@ -1014,15 +1043,15 @@ pub const Manifest = struct {
10141043
10151044 const manifest_stat = manifest_file.stat(io) catch |err| switch (err) {
10161045 error.Canceled => |e| return e,
1017 else => |e| return fail(&m.diagnostic, .{ .manifest_stat = e }),
1046 else => |e| return fail(diag, .{ .manifest_stat = e }),
10181047 };
10191048 const manifest_size = std.math.cast(u32, manifest_stat.size) orelse
1020 return fail(&m.diagnostic, .manifest_oversize);
1049 return fail(diag, .manifest_oversize);
10211050
10221051 if (manifest_size == 0 or manifest_size < m.contents.items.len) {
10231052 // Manifest file was never finalized.
10241053 try m.contents.ensureUnusedCapacity(gpa, 1);
1025 return populateMissingInputFileHashes(m, 0, .incomplete_manifest);
1054 return populateMissingInputFileHashes(m, diag, 0, .incomplete_manifest);
10261055 }
10271056
10281057 // We must not clobber existing `Manifest.contents` because it possibly contains prepopulated stat and digest
......@@ -1039,9 +1068,9 @@ pub const Manifest = struct {
10391068 {
10401069 const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) {
10411070 error.Canceled => |e| return e,
1042 else => |e| return fail(&m.diagnostic, .{ .manifest_read = e }),
1071 else => |e| return fail(diag, .{ .manifest_read = e }),
10431072 };
1044 if (n != manifest_size) return missInput(m, 0, input_contents_len, manifest_size, .incomplete_manifest);
1073 if (n != manifest_size) return missInput(m, diag, 0, input_contents_len, manifest_size, .incomplete_manifest);
10451074 }
10461075 const disk_contents = m.contents.items[0..manifest_size];
10471076 const input_contents = m.contents.items[manifest_size..][0..input_contents_len];
......@@ -1050,12 +1079,12 @@ pub const Manifest = struct {
10501079 var off: usize = 0;
10511080 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len], 0..) |*input_path, file_off, i| {
10521081 if (@backingInt(file_off) + 1 >= disk_contents.len)
1053 return missInput(m, i, input_contents_len, manifest_size, .incomplete_manifest);
1082 return missInput(m, diag, i, input_contents_len, manifest_size, .incomplete_manifest);
10541083 if (!mem.eql(u8, file_off.flagsAndPath(disk_contents), file_off.flagsAndPath(input_contents)))
1055 return missInput(m, i, input_contents_len, manifest_size, .invalid_manifest);
1084 return missInput(m, diag, i, input_contents_len, manifest_size, .invalid_manifest);
10561085
1057 const result = try checkInputPath(m, file_off, input_path, disk_contents, input_contents);
1058 if (result != .hit) return missInput(m, i + 1, input_contents_len, manifest_size, result);
1086 const result = try checkInputPath(m, diag, file_off, input_path, disk_contents, input_contents);
1087 if (result != .hit) return missInput(m, diag, i + 1, input_contents_len, manifest_size, result);
10591088 off = @backingInt(file_off);
10601089 }
10611090
......@@ -1074,7 +1103,7 @@ pub const Manifest = struct {
10741103 if (path.len == 0) return .invalid_manifest;
10751104
10761105 try m.files.putContext(gpa, file_off, {}, .{ .contents = disk_contents });
1077 const result = try checkDiscoveredPath(m, file_off, disk_contents);
1106 const result = try checkDiscoveredPath(m, diag, file_off, disk_contents);
10781107 if (result != .hit) return result;
10791108
10801109 off += File.sizeOf(path.len);
......@@ -1098,6 +1127,7 @@ pub const Manifest = struct {
10981127 /// missed one.
10991128 fn missInput(
11001129 m: *Manifest,
1130 diag: *CheckDiagnostic,
11011131 next_file_index: usize,
11021132 input_contents_len: usize,
11031133 manifest_size: usize,
......@@ -1114,18 +1144,19 @@ pub const Manifest = struct {
11141144 m.contents.items[manifest_size + off ..][0..copy_len],
11151145 );
11161146 m.contents.shrinkRetainingCapacity(input_contents_len);
1117 return populateMissingInputFileHashes(m, next_file_index, result);
1147 return populateMissingInputFileHashes(m, diag, next_file_index, result);
11181148 }
11191149
11201150 fn populateMissingInputFileHashes(
11211151 m: *Manifest,
1152 diag: *CheckDiagnostic,
11221153 next_file_index: usize,
11231154 result: CheckResult,
11241155 ) CheckError!CheckResult {
11251156 const file_offs = m.files.keys();
11261157 const contents = m.contents.items;
11271158 for (file_offs[next_file_index..], m.input_paths.items[next_file_index..]) |input_file_off, *input_path| {
1128 try populateInputPath(m, input_file_off, input_path, contents);
1159 try populateInputPath(m, diag, input_file_off, input_path, contents);
11291160 }
11301161 return result;
11311162 }
......@@ -1134,6 +1165,7 @@ pub const Manifest = struct {
11341165 /// system. Only ensures that metadata and digest are available.
11351166 fn populateInputPath(
11361167 m: *Manifest,
1168 diag: *CheckDiagnostic,
11371169 file_off: File.Offset,
11381170 input_path: *InputPath,
11391171 contents: []u8,
......@@ -1156,21 +1188,21 @@ pub const Manifest = struct {
11561188 const actual_stat = switch (input_path.getHandle(input_file)) {
11571189 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
11581190 error.Canceled => |e| return e,
1159 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1191 else => |e| return fail(diag, .{ .file_stat = .{
11601192 .file_offset = file_off,
11611193 .err = e,
11621194 } }),
11631195 },
11641196 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {
11651197 error.Canceled => |e| return e,
1166 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1198 else => |e| return fail(diag, .{ .file_stat = .{
11671199 .file_offset = file_off,
11681200 .err = e,
11691201 } }),
11701202 },
11711203 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {
11721204 error.Canceled => |e| return e,
1173 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1205 else => |e| return fail(diag, .{ .file_stat = .{
11741206 .file_offset = file_off,
11751207 .err = e,
11761208 } }),
......@@ -1179,7 +1211,7 @@ pub const Manifest = struct {
11791211 const actual_is_directory = actual_stat.kind == .directory;
11801212 if (actual_is_directory != input_file.flags.is_directory) {
11811213 // Since this is an input file, this is a failure, not a cache miss.
1182 return fail(&m.diagnostic, .{ .file_stat = .{
1214 return fail(diag, .{ .file_stat = .{
11831215 .file_offset = file_off,
11841216 .err = if (actual_is_directory) error.IsDir else error.NotDir,
11851217 } });
......@@ -1210,7 +1242,7 @@ pub const Manifest = struct {
12101242 .access_sub_paths = false,
12111243 }) catch |err| switch (err) {
12121244 error.Canceled => |e| return e,
1213 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1245 else => |e| return fail(diag, .{ .file_open = .{
12141246 .file_offset = file_off,
12151247 .err = e,
12161248 } }),
......@@ -1224,7 +1256,7 @@ pub const Manifest = struct {
12241256 assert(!stat_path_ok);
12251257 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
12261258 error.Canceled => |e| return e,
1227 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1259 else => |e| return fail(diag, .{ .file_stat = .{
12281260 .file_offset = file_off,
12291261 .err = e,
12301262 } }),
......@@ -1235,7 +1267,7 @@ pub const Manifest = struct {
12351267 const dir_contents_start = m.all_input_content.items.len;
12361268 hashDir(gpa, io, opened_dir, &input_file.digest, &m.all_input_content) catch |err| switch (err) {
12371269 error.Canceled, error.OutOfMemory => |e| return e,
1238 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1270 else => |e| return fail(diag, .{ .file_read = .{
12391271 .file_offset = file_off,
12401272 .err = e,
12411273 } }),
......@@ -1254,7 +1286,7 @@ pub const Manifest = struct {
12541286 else
12551287 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {
12561288 error.Canceled => |e| return e,
1257 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1289 else => |e| return fail(diag, .{ .file_open = .{
12581290 .file_offset = file_off,
12591291 .err = e,
12601292 } }),
......@@ -1268,7 +1300,7 @@ pub const Manifest = struct {
12681300 assert(!stat_path_ok);
12691301 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
12701302 error.Canceled => |e| return e,
1271 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1303 else => |e| return fail(diag, .{ .file_stat = .{
12721304 .file_offset = file_off,
12731305 .err = e,
12741306 } }),
......@@ -1281,7 +1313,7 @@ pub const Manifest = struct {
12811313 const start = m.all_input_content.items.len;
12821314 hashFileAppend(io, opened_file, &input_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {
12831315 error.Canceled, error.OutOfMemory => |e| return e,
1284 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1316 else => |e| return fail(diag, .{ .file_read = .{
12851317 .file_offset = file_off,
12861318 .err = e,
12871319 } }),
......@@ -1293,7 +1325,7 @@ pub const Manifest = struct {
12931325 },
12941326 .unrequested => hashFile(io, opened_file, &input_file.digest) catch |err| switch (err) {
12951327 error.Canceled => |e| return e,
1296 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1328 else => |e| return fail(diag, .{ .file_read = .{
12971329 .file_offset = file_off,
12981330 .err = e,
12991331 } }),
......@@ -1306,6 +1338,7 @@ pub const Manifest = struct {
13061338 /// Upon return, disk_contents digest and stat will be populated regardless of whether hit or miss occurs.
13071339 fn checkInputPath(
13081340 m: *Manifest,
1341 diag: *CheckDiagnostic,
13091342 file_off: File.Offset,
13101343 input_path: *InputPath,
13111344 disk_contents: []u8,
......@@ -1337,21 +1370,21 @@ pub const Manifest = struct {
13371370 const actual_stat = switch (input_path.getHandle(input_file)) {
13381371 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
13391372 error.Canceled => |e| return e,
1340 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1373 else => |e| return fail(diag, .{ .file_stat = .{
13411374 .file_offset = file_off,
13421375 .err = e,
13431376 } }),
13441377 },
13451378 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {
13461379 error.Canceled => |e| return e,
1347 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1380 else => |e| return fail(diag, .{ .file_stat = .{
13481381 .file_offset = file_off,
13491382 .err = e,
13501383 } }),
13511384 },
13521385 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {
13531386 error.Canceled => |e| return e,
1354 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1387 else => |e| return fail(diag, .{ .file_stat = .{
13551388 .file_offset = file_off,
13561389 .err = e,
13571390 } }),
......@@ -1362,7 +1395,7 @@ pub const Manifest = struct {
13621395 const actual_is_directory = actual_stat.kind == .directory;
13631396 if (actual_is_directory != disk_file.flags.is_directory) {
13641397 // Since this is an input file, this is a failure, not a cache miss.
1365 return fail(&m.diagnostic, .{ .file_stat = .{
1398 return fail(diag, .{ .file_stat = .{
13661399 .file_offset = file_off,
13671400 .err = if (actual_is_directory) error.IsDir else error.NotDir,
13681401 } });
......@@ -1393,7 +1426,7 @@ pub const Manifest = struct {
13931426 .access_sub_paths = false,
13941427 }) catch |err| switch (err) {
13951428 error.Canceled => |e| return e,
1396 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1429 else => |e| return fail(diag, .{ .file_open = .{
13971430 .file_offset = file_off,
13981431 .err = e,
13991432 } }),
......@@ -1406,7 +1439,7 @@ pub const Manifest = struct {
14061439 if (!input_path.have_stat) {
14071440 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
14081441 error.Canceled => |e| return e,
1409 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1442 else => |e| return fail(diag, .{ .file_stat = .{
14101443 .file_offset = file_off,
14111444 .err = e,
14121445 } }),
......@@ -1417,7 +1450,7 @@ pub const Manifest = struct {
14171450 const dir_contents_start = m.all_input_content.items.len;
14181451 hashDir(gpa, io, opened_dir, &disk_file.digest, &m.all_input_content) catch |err| switch (err) {
14191452 error.Canceled, error.OutOfMemory => |e| return e,
1420 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1453 else => |e| return fail(diag, .{ .file_read = .{
14211454 .file_offset = file_off,
14221455 .err = e,
14231456 } }),
......@@ -1439,7 +1472,7 @@ pub const Manifest = struct {
14391472 else
14401473 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {
14411474 error.Canceled => |e| return e,
1442 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1475 else => |e| return fail(diag, .{ .file_open = .{
14431476 .file_offset = file_off,
14441477 .err = e,
14451478 } }),
......@@ -1452,7 +1485,7 @@ pub const Manifest = struct {
14521485 if (!input_path.have_stat) {
14531486 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
14541487 error.Canceled => |e| return e,
1455 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1488 else => |e| return fail(diag, .{ .file_stat = .{
14561489 .file_offset = file_off,
14571490 .err = e,
14581491 } }),
......@@ -1465,7 +1498,7 @@ pub const Manifest = struct {
14651498 const start = m.all_input_content.items.len;
14661499 hashFileAppend(io, opened_file, &disk_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {
14671500 error.Canceled, error.OutOfMemory => |e| return e,
1468 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1501 else => |e| return fail(diag, .{ .file_read = .{
14691502 .file_offset = file_off,
14701503 .err = e,
14711504 } }),
......@@ -1477,7 +1510,7 @@ pub const Manifest = struct {
14771510 },
14781511 .unrequested => hashFile(io, opened_file, &disk_file.digest) catch |err| switch (err) {
14791512 error.Canceled => |e| return e,
1480 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1513 else => |e| return fail(diag, .{ .file_read = .{
14811514 .file_offset = file_off,
14821515 .err = e,
14831516 } }),
......@@ -1490,7 +1523,12 @@ pub const Manifest = struct {
14901523 }
14911524 }
14921525
1493 fn checkDiscoveredPath(m: *Manifest, file_off: File.Offset, contents: []u8) CheckError!CheckResult {
1526 fn checkDiscoveredPath(
1527 m: *Manifest,
1528 diag: *CheckDiagnostic,
1529 file_off: File.Offset,
1530 contents: []u8,
1531 ) CheckError!CheckResult {
14941532 const file = file_off.get(contents);
14951533 const cache = m.cache;
14961534 const gpa = cache.gpa;
......@@ -1502,7 +1540,7 @@ pub const Manifest = struct {
15021540 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
15031541 error.FileNotFound => return .{ .path_deleted = file_off },
15041542 error.Canceled => |e| return e,
1505 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1543 else => |e| return fail(diag, .{ .file_stat = .{
15061544 .file_offset = file_off,
15071545 .err = e,
15081546 } }),
......@@ -1525,7 +1563,7 @@ pub const Manifest = struct {
15251563 error.FileNotFound => return .{ .path_deleted = file_off },
15261564 error.NotDir => return .{ .directory_status_changed = file_off },
15271565 error.Canceled => |e| return e,
1528 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1566 else => |e| return fail(diag, .{ .file_open = .{
15291567 .file_offset = file_off,
15301568 .err = e,
15311569 } }),
......@@ -1534,7 +1572,7 @@ pub const Manifest = struct {
15341572
15351573 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
15361574 error.Canceled => |e| return e,
1537 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1575 else => |e| return fail(diag, .{ .file_stat = .{
15381576 .file_offset = file_off,
15391577 .err = e,
15401578 } }),
......@@ -1545,7 +1583,7 @@ pub const Manifest = struct {
15451583 defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start);
15461584 hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) {
15471585 error.Canceled, error.OutOfMemory => |e| return e,
1548 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1586 else => |e| return fail(diag, .{ .file_read = .{
15491587 .file_offset = file_off,
15501588 .err = e,
15511589 } }),
......@@ -1560,7 +1598,7 @@ pub const Manifest = struct {
15601598 error.FileNotFound => return .{ .path_deleted = file_off },
15611599 error.IsDir => return .{ .directory_status_changed = file_off },
15621600 error.Canceled => |e| return e,
1563 else => |e| return fail(&m.diagnostic, .{ .file_open = .{
1601 else => |e| return fail(diag, .{ .file_open = .{
15641602 .file_offset = file_off,
15651603 .err = e,
15661604 } }),
......@@ -1569,7 +1607,7 @@ pub const Manifest = struct {
15691607
15701608 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
15711609 error.Canceled => |e| return e,
1572 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{
1610 else => |e| return fail(diag, .{ .file_stat = .{
15731611 .file_offset = file_off,
15741612 .err = e,
15751613 } }),
......@@ -1579,7 +1617,7 @@ pub const Manifest = struct {
15791617 const prev_digest: BinDigest = file.digest;
15801618 hashFile(io, opened_file, &file.digest) catch |err| switch (err) {
15811619 error.Canceled => |e| return e,
1582 else => |e| return fail(&m.diagnostic, .{ .file_read = .{
1620 else => |e| return fail(diag, .{ .file_read = .{
15831621 .file_offset = file_off,
15841622 .err = e,
15851623 } }),
......@@ -1591,8 +1629,7 @@ pub const Manifest = struct {
15911629 return .hit;
15921630 }
15931631
1594 fn fail(ptr: *Diagnostic, d: Diagnostic) error{CacheCheckFailed} {
1595 assert(ptr.* == .none);
1632 fn fail(ptr: *CheckDiagnostic, d: CheckDiagnostic) error{CacheCheckFailed} {
15961633 ptr.* = d;
15971634 return error.CacheCheckFailed;
15981635 }
......@@ -2002,22 +2039,19 @@ pub const Manifest = struct {
20022039 self.have_exclusive_lock = false;
20032040 }
20042041
2005 fn upgradeToExclusiveLock(self: *Manifest) error{CacheCheckFailed}!bool {
2006 if (self.have_exclusive_lock) return false;
2007 assert(self.manifest_file != null);
2008 const io = self.cache.io;
2042 fn upgradeToExclusiveLock(m: *Manifest, diag: *CheckDiagnostic) error{CacheCheckFailed}!bool {
2043 if (m.have_exclusive_lock) return false;
2044 assert(m.manifest_file != null);
2045 const io = m.cache.io;
20092046
20102047 if (std.process.can_spawn or !builtin.single_threaded) {
2011 const manifest_file = self.manifest_file.?;
2048 const manifest_file = m.manifest_file.?;
20122049 // Here we intentionally have a period where the lock is released, in case there are
20132050 // other processes holding a shared lock.
20142051 manifest_file.unlock(io);
2015 manifest_file.lock(io, .exclusive) catch |err| {
2016 self.diagnostic = .{ .manifest_lock = err };
2017 return error.CacheCheckFailed;
2018 };
2052 manifest_file.lock(io, .exclusive) catch |err| return fail(diag, .{ .manifest_lock = err });
20192053 }
2020 self.have_exclusive_lock = true;
2054 m.have_exclusive_lock = true;
20212055 return true;
20222056 }
20232057
......@@ -2327,7 +2361,8 @@ test "cache file and then recall it" {
23272361 .sub_path = temp_file,
23282362 }, .{});
23292363
2330 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
2364 var diag: Manifest.CheckDiagnostic = undefined;
2365 try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none));
23312366
23322367 digest1 = man.missDigestHex();
23332368 try man.finalize();
......@@ -2345,7 +2380,8 @@ test "cache file and then recall it" {
23452380 }, .{});
23462381
23472382 // Cache hit! We just "built" the same file
2348 try testing.expectEqual(.hit, try man.check(.none));
2383 var diag: Manifest.CheckDiagnostic = undefined;
2384 try testing.expectEqual(.hit, try man.check(&diag, .none));
23492385 digest2 = man.hitDigestHex();
23502386
23512387 try testing.expectEqual(false, man.have_exclusive_lock);
......@@ -2406,7 +2442,8 @@ test "check that changing a file causes cache miss" {
24062442 .sub_path = temp_file,
24072443 }, .{ .request_contents = true });
24082444
2409 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
2445 var diag: Manifest.CheckDiagnostic = undefined;
2446 try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none));
24102447
24112448 try testing.expectEqualStrings(original_temp_file_contents, temp_file_idx.contents(&man));
24122449
......@@ -2428,9 +2465,10 @@ test "check that changing a file causes cache miss" {
24282465 }, .{ .request_contents = true });
24292466
24302467 // The one input file changed.
2468 var diag: Manifest.CheckDiagnostic = undefined;
24312469 try testing.expectEqual(
24322470 @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }),
2433 try man.check(.none),
2471 try man.check(&diag, .none),
24342472 );
24352473
24362474 try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man));
......@@ -2473,7 +2511,8 @@ test "no file inputs" {
24732511
24742512 man.hash.addBytes("1234");
24752513
2476 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
2514 var diag: Manifest.CheckDiagnostic = undefined;
2515 try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none));
24772516
24782517 digest1 = man.missDigestHex();
24792518
......@@ -2485,7 +2524,8 @@ test "no file inputs" {
24852524
24862525 man.hash.addBytes("1234");
24872526
2488 try testing.expectEqual(.hit, try man.check(.none));
2527 var diag: Manifest.CheckDiagnostic = undefined;
2528 try testing.expectEqual(.hit, try man.check(&diag, .none));
24892529 digest2 = man.hitDigestHex();
24902530 try testing.expectEqual(false, man.have_exclusive_lock);
24912531 }
......@@ -2545,7 +2585,8 @@ test "Manifest with files added after initial hash" {
25452585 .sub_path = temp_file1,
25462586 }, .{});
25472587
2548 try testing.expectEqual(.incomplete_manifest, try man.check(.none));
2588 var diag: Manifest.CheckDiagnostic = undefined;
2589 try testing.expectEqual(.incomplete_manifest, try man.check(&diag, .none));
25492590
25502591 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .{
25512592 .root_dir = tmp_directory,
......@@ -2565,7 +2606,8 @@ test "Manifest with files added after initial hash" {
25652606 .sub_path = temp_file1,
25662607 }, .{});
25672608
2568 try testing.expect(.hit == try man.check(.none));
2609 var diag: Manifest.CheckDiagnostic = undefined;
2610 try testing.expect(.hit == try man.check(&diag, .none));
25692611 digest2 = man.hitDigestHex();
25702612
25712613 try testing.expectEqual(false, man.have_exclusive_lock);
......@@ -2591,7 +2633,8 @@ test "Manifest with files added after initial hash" {
25912633 .sub_path = temp_file1,
25922634 }, .{});
25932635
2594 switch (try man.check(.none)) {
2636 var diag: Manifest.CheckDiagnostic = undefined;
2637 switch (try man.check(&diag, .none)) {
25952638 .contents_changed => |off| {
25962639 try testing.expectEqualStrings(temp_file2, off.path(man.contents.items));
25972640 },
src/Compilation.zig+52-28
......@@ -2813,27 +2813,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28132813 man.want_shared_lock = false;
28142814 }
28152815
2816 const status = man.check(main_progress_node) catch |err| switch (err) {
2816 var diag: Cache.Manifest.CheckDiagnostic = undefined;
2817 const status = man.check(&diag, main_progress_node) catch |err| switch (err) {
28172818 error.Canceled, error.OutOfMemory => |e| return e,
2818 error.CacheCheckFailed => switch (man.diagnostic) {
2819 .none => unreachable,
2820 .manifest_oversize => {
2821 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {t}", .{
2822 man.diagnostic,
2823 });
2824 },
2825 .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| {
2826 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {t} {t}", .{
2827 man.diagnostic, e,
2828 });
2829 },
2830 .file_open, .file_stat, .file_read, .file_hash => |op| {
2831 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f} {t} {t}", .{
2832 op.path(&man), man.diagnostic, op.err,
2833 });
2834 },
2819 error.CacheCheckFailed => {
2820 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f}", .{diag.fmt(&man)});
28352821 },
28362822 };
2823 log.debug("{s} whole cache {f} ignore_hit={}", .{ comp.root_name, status.fmt(&man), ignore_hit });
28372824 if (status == .hit and !ignore_hit) {
28382825 // In this case the cache hit contains the full set of file system inputs. Nice!
28392826 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
28442831 }
28452832
28462833 comp.last_update_was_cache_hit = true;
2847 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
28482834 const bin_digest = man.hitDigest();
28492835
28502836 comp.digest = bin_digest;
......@@ -2853,7 +2839,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
28532839 whole.lock = man.toOwnedLock();
28542840 return;
28552841 }
2856 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
28572842
28582843 if (ignore_hit) {
28592844 // 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
55365521 const target = comp.getTarget();
55375522 assert(target.ofmt != .c);
55385523 const o_ext = target.ofmt.fileExt(target.cpu.arch);
5539 const digest = if (!comp.disable_c_depfile and .hit == try man.check(child_progress_node)) man.hitDigestHex() else miss: {
5524 const digest = d: {
5525 if (!comp.disable_c_depfile) {
5526 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined;
5527 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) {
5528 error.Canceled, error.OutOfMemory => |e| return e,
5529 error.CacheCheckFailed => {
5530 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)});
5531 },
5532 };
5533 log.debug("C object cache {f}", .{status.fmt(&man)});
5534 if (status == .hit) break :d man.hitDigestHex();
5535 }
55405536 var argv: std.array_list.Managed([]const u8) = .init(gpa);
55415537 defer argv.deinit();
55425538
......@@ -5811,16 +5807,28 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
58115807 }
58125808
58135809 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
5814 if (comp.disable_c_depfile) _ = try man.check(child_progress_node);
5810 const digest = inner: {
5811 if (comp.disable_c_depfile) {
5812 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined;
5813 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) {
5814 error.OutOfMemory, error.Canceled => |e| return e,
5815 error.CacheCheckFailed => {
5816 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)});
5817 },
5818 };
5819 log.debug("ignored C object cache {f}", .{status.fmt(&man)});
5820 if (status == .hit) break :inner man.hitDigestHex();
5821 }
5822 break :inner man.missDigestHex();
5823 };
58155824
58165825 // Rename into place.
5817 const digest = man.missDigestHex();
58185826 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });
58195827 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{});
58205828 defer o_dir.close(io);
58215829 const tmp_basename = fs.path.basename(out_obj_path);
58225830 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io);
5823 break :miss digest;
5831 break :d digest;
58245832 };
58255833
58265834 if (man.have_exclusive_lock) {
......@@ -5896,7 +5904,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
58965904 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});
58975905 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});
58985906
5899 const digest = if (.hit == try man.check(child_progress_node)) man.hitDigestHex() else blk: {
5907 var diag: Cache.Manifest.CheckDiagnostic = undefined;
5908 const status = man.check(&diag, child_progress_node) catch |err| switch (err) {
5909 error.OutOfMemory, error.Canceled => |e| return e,
5910 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{
5911 diag.fmt(&man),
5912 }),
5913 };
5914 log.debug("win32 resource cache {f}", .{status.fmt(&man)});
5915 const digest = if (status == .hit) man.hitDigestHex() else miss: {
59005916 // The digest only depends on the .manifest file, so we can
59015917 // get the digest now and write the .res directly to the cache
59025918 const digest = man.missDigestHex();
......@@ -5961,7 +5977,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59615977
59625978 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node);
59635979
5964 break :blk digest;
5980 break :miss digest;
59655981 };
59665982
59675983 if (man.have_exclusive_lock) {
......@@ -5988,7 +6004,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59886004
59896005 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];
59906006
5991 const digest = if (.hit == try man.check(child_progress_node)) man.hitDigestHex() else blk: {
6007 var diagnostic: Cache.Manifest.CheckDiagnostic = undefined;
6008 const status = man.check(&diagnostic, child_progress_node) catch |err| switch (err) {
6009 error.OutOfMemory, error.Canceled => |e| return e,
6010 error.CacheCheckFailed => return comp.failWin32Resource(win32_resource, "checking cache failed: {f}", .{
6011 diagnostic.fmt(&man),
6012 }),
6013 };
6014 log.debug("win32 resource cache {f}", .{status.fmt(&man)});
6015 const digest = if (status == .hit) man.hitDigestHex() else miss: {
59926016 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{});
59936017 defer zig_cache_tmp_dir.close(io);
59946018
......@@ -6066,7 +6090,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
60666090 defer o_dir.close(io);
60676091 const tmp_basename = fs.path.basename(out_res_path);
60686092 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io);
6069 break :blk digest;
6093 break :miss digest;
60706094 };
60716095
60726096 if (man.have_exclusive_lock) {
src/Sema.zig+4-8
......@@ -12974,7 +12974,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1297412974
1297512975 const result = ef_idx.get(zcu);
1297612976 if (result.val == .none) {
12977 return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ name, @errorName(result.err.?) });
12977 return sema.fail(block, operand_src, "failed opening {q}: {t}", .{ name, result.err.? });
1297812978 }
1297912979
1298012980 return Air.internedToRef(result.val);
......@@ -15911,9 +15911,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1591115911 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
1591215912 const tree = file.getTree(zcu) catch |err| {
1591315913 // In this case we emit a warning + a less precise source location.
15914 log.warn("unable to load {f}: {s}", .{
15915 file.path.fmt(zcu.comp), @errorName(err),
15916 });
15914 log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err });
1591715915 break :name null;
1591815916 };
1591915917 const node = src_node.toAbsolute(src_base_node);
......@@ -15939,9 +15937,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1593915937 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
1594015938 const tree = file.getTree(zcu) catch |err| {
1594115939 // In this case we emit a warning + a less precise source location.
15942 log.warn("unable to load {f}: {s}", .{
15943 file.path.fmt(zcu.comp), @errorName(err),
15944 });
15940 log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err });
1594515941 break :name null;
1594615942 };
1594715943 const node = src_node.toAbsolute(src_base_node);
......@@ -15950,7 +15946,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1595015946 };
1595115947
1595215948 const msg = if (name) |some|
15953 try sema.errMsg(src, "'{s}' not accessible from inner function", .{some})
15949 try sema.errMsg(src, "{q} not accessible from inner function", .{some})
1595415950 else
1595515951 try sema.errMsg(src, "variable not accessible from inner function", .{});
1595615952 errdefer msg.destroy(sema.gpa);
src/libs/freebsd.zig+14-1
......@@ -465,7 +465,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
465465 .request_contents = true,
466466 });
467467
468 if (.hit == try man.check(prog_node)) {
468 var diag: Cache.Manifest.CheckDiagnostic = undefined;
469 const status = man.check(&diag, prog_node) catch |err| switch (err) {
470 error.OutOfMemory, error.Canceled => |e| return e,
471 error.CacheCheckFailed => {
472 comp.lockAndSetMiscFailure(
473 .freebsd_shared_objects,
474 "compiling FreeBSD libc shared objects: checking cache failed: {f}",
475 .{diag.fmt(&man)},
476 );
477 return error.AlreadyReported;
478 },
479 };
480 log.debug("freebsd_shared_objects cache {f}", .{status.fmt(&man)});
481 if (status == .hit) {
469482 const digest = man.hitDigestHex();
470483 return queueSharedObjects(comp, .{
471484 .lock = man.toOwnedLock(),
src/libs/glibc.zig+14-1
......@@ -705,7 +705,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
705705 .request_contents = true,
706706 });
707707
708 if (.hit == try man.check(prog_node)) {
708 var diag: Cache.Manifest.CheckDiagnostic = undefined;
709 const status = man.check(&diag, prog_node) catch |err| switch (err) {
710 error.OutOfMemory, error.Canceled => |e| return e,
711 error.CacheCheckFailed => {
712 comp.lockAndSetMiscFailure(
713 .glibc_shared_objects,
714 "compiling glibc shared objects: checking cache failed: {f}",
715 .{diag.fmt(&man)},
716 );
717 return error.AlreadyReported;
718 },
719 };
720 log.debug("glibc_shared_objects cache {f}", .{status.fmt(&man)});
721 if (status == .hit) {
709722 const digest = man.hitDigestHex();
710723 return queueSharedObjects(comp, .{
711724 .lock = man.toOwnedLock(),
src/libs/mingw.zig+8-17
......@@ -251,26 +251,17 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
251251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
252252 errdefer gpa.free(final_lib_basename);
253253
254 const status = man.check(prog_node) catch |err| switch (err) {
255 error.CacheCheckFailed => switch (man.diagnostic) {
256 .none => unreachable,
257 .manifest_oversize => {
258 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t}", .{man.diagnostic});
259 return error.AlreadyReported;
260 },
261 .manifest_create, .manifest_stat, .manifest_read, .manifest_lock => |e| {
262 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t} {t}", .{ man.diagnostic, e });
263 return error.AlreadyReported;
264 },
265 .file_open, .file_stat, .file_read, .file_hash => |op| {
266 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {f} {t} {t}", .{
267 op.path(&man), man.diagnostic, op.err,
268 });
269 return error.AlreadyReported;
270 },
254 var diag: Cache.Manifest.CheckDiagnostic = undefined;
255 const status = man.check(&diag, prog_node) catch |err| switch (err) {
256 error.CacheCheckFailed => {
257 comp.setMiscFailure(.windows_import_lib, "{s} cache check failed: {f}", .{
258 final_lib_basename, diag.fmt(&man),
259 });
260 return error.AlreadyReported;
271261 },
272262 error.OutOfMemory, error.Canceled => |e| return e,
273263 };
264 log.debug("{s} cache {f}", .{ final_lib_basename, status.fmt(&man) });
274265 if (status == .hit) {
275266 const digest = man.hitDigestHex();
276267 const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });
src/libs/netbsd.zig+14-1
......@@ -413,7 +413,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
413413 .request_contents = true,
414414 });
415415
416 if (.hit == try man.check(prog_node)) {
416 var diag: Cache.Manifest.CheckDiagnostic = undefined;
417 const status = man.check(&diag, prog_node) catch |err| switch (err) {
418 error.CacheCheckFailed => {
419 comp.lockAndSetMiscFailure(
420 .netbsd_shared_objects,
421 "compiling NetBSD libc shared objects: checking cache failed: {f}",
422 .{diag.fmt(&man)},
423 );
424 return error.AlreadyReported;
425 },
426 error.OutOfMemory, error.Canceled => |e| return e,
427 };
428 log.debug("netbsd_shared_objects cache {f}", .{status.fmt(&man)});
429 if (status == .hit) {
417430 const digest = man.hitDigestHex();
418431 return queueSharedObjects(comp, .{
419432 .lock = man.toOwnedLock(),
src/libs/openbsd.zig+14-1
......@@ -334,7 +334,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
334334 .request_contents = true,
335335 });
336336
337 if (.hit == try man.check(prog_node)) {
337 var diag: Cache.Manifest.CheckDiagnostic = undefined;
338 const status = man.check(&diag, prog_node) catch |err| switch (err) {
339 error.OutOfMemory, error.Canceled => |e| return e,
340 error.CacheCheckFailed => {
341 comp.lockAndSetMiscFailure(
342 .openbsd_shared_objects,
343 "compiling OpenBSD libc shared objects: checking cache failed: {f}",
344 .{diag.fmt(&man)},
345 );
346 return error.AlreadyReported;
347 },
348 };
349 log.debug("openbsd_shared_objects cache {f}", .{status.fmt(&man)});
350 if (status == .hit) {
338351 const digest = man.hitDigestHex();
339352 return queueSharedObjects(comp, .{
340353 .lock = man.toOwnedLock(),
src/main.zig+7-1
......@@ -4878,7 +4878,13 @@ fn cmdTranslateC(
48784878 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|
48794879 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err });
48804880
4881 const result: Compilation.TranslateCResult = if (.hit == try man.check(prog_node)) .{
4881 var diag: Cache.Manifest.CheckDiagnostic = undefined;
4882 const status = man.check(&diag, prog_node) catch |err| switch (err) {
4883 error.OutOfMemory, error.Canceled => |e| return e,
4884 error.CacheCheckFailed => fatal("translate-c checking cache failed: {f}", .{diag.fmt(&man)}),
4885 };
4886 std.log.debug("translate-c cache {f}", .{status.fmt(&man)});
4887 const result: Compilation.TranslateCResult = if (status == .hit) .{
48824888 .digest = man.hitDigest(),
48834889 .cache_hit = true,
48844890 .errors = std.zig.ErrorBundle.empty,
test/incremental/bad_import+2-2
......@@ -10,7 +10,7 @@ const io = std.Io.Threaded.global_single_threaded.io();
1010comptime {
1111 _ = @import("bad.zig");
1212}
13#expect_error=bad.zig:1:1: error: unable to load 'bad.zig': FileNotFound
13#expect_error=bad.zig:1:1: error: unable to load "bad.zig": FileNotFound
1414#expect_error=foo.zig:2:17: note: file imported here
1515
1616#update=change bad import
......@@ -18,7 +18,7 @@ comptime {
1818comptime {
1919 _ = @import("this_is/not_real.zig");
2020}
21#expect_error=this_is/not_real.zig:1:1: error: unable to load 'not_real.zig': FileNotFound
21#expect_error=this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
2222#expect_error=foo.zig:2:17: note: file imported here
2323
2424#update=remove import of 'foo.zig'
test/incremental/change_embed_file+2-2
......@@ -17,7 +17,7 @@ Hello again, World!
1717
1818#update=delete file
1919#rm_file=string.txt
20#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound
20#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound
2121
2222#update=remove reference to file
2323#file=main.zig
......@@ -37,7 +37,7 @@ pub fn main() !void {
3737 try std.Io.File.stdout().writeStreamingAll(io, string);
3838}
3939const io = std.Io.Threaded.global_single_threaded.io();
40#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound
40#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound
4141
4242#update=recreate file
4343#file=string.txt
test/incremental/change_zon_file+2-2
......@@ -17,7 +17,7 @@ const io = std.Io.Threaded.global_single_threaded.io();
1717
1818#update=delete file
1919#rm_file=message.zon
20#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
20#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound
2121#expect_error=main.zig:2:37: note: file imported here
2222
2323#update=remove reference to ZON file
......@@ -28,7 +28,7 @@ pub fn main() !void {
2828 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
2929}
3030const io = std.Io.Threaded.global_single_threaded.io();
31#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound
31#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound
3232#expect_error=main.zig:2:37: note: file imported here
3333
3434#update=recreate ZON file