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 {...@@ -1399,7 +1399,13 @@ fn configure(graph: *Graph, options: ConfigureOptions) !ScannedConfig {
1399 defer compile_prog_node.end();1399 defer compile_prog_node.end();
14001400
1401 if (config_man) |man| {1401 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) {
1403 const digest = man.hitDigestHex();1409 const digest = man.hitDigestHex();
1404 const path: Path = .{1410 const path: Path = .{
1405 .root_dir = graph.local_cache_root,1411 .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...@@ -726,7 +726,10 @@ pub fn handleChildProcessTerm(s: *Step, maker: *Maker, term: std.process.Child.T
726/// Prefer `cacheHitWatched` unless you already added watch inputs726/// Prefer `cacheHitWatched` unless you already added watch inputs
727/// separately from using the cache system.727/// separately from using the cache system.
728pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {728pub 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
730 s.result_cached = hit;733 s.result_cached = hit;
731 return hit;734 return hit;
732}735}
...@@ -736,7 +739,10 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n...@@ -736,7 +739,10 @@ pub fn cacheHit(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_n
736///739///
737/// Must be accompanied with `finalizeManifestAndWatch`.740/// Must be accompanied with `finalizeManifestAndWatch`.
738pub fn cacheHitWatched(s: *Step, maker: *Maker, man: *Cache.Manifest, parent_progress_node: std.Progress.Node) !bool {741pub 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
740 s.result_cached = hit;746 s.result_cached = hit;
741 // The above call to hit() populates the manifest with files, so in case of747 // The above call to hit() populates the manifest with files, so in case of
742 // a hit, we need to populate watch inputs.748 // a hit, we need to populate watch inputs.
...@@ -748,20 +754,11 @@ fn failWithCacheError(...@@ -748,20 +754,11 @@ fn failWithCacheError(
748 s: *Step,754 s: *Step,
749 maker: *Maker,755 maker: *Maker,
750 man: *const Cache.Manifest,756 man: *const Cache.Manifest,
757 diag: *const Cache.Manifest.CheckDiagnostic,
751 err: Cache.Manifest.CheckError,758 err: Cache.Manifest.CheckError,
752) error{ OutOfMemory, Canceled, MakeFailed } {759) error{ OutOfMemory, Canceled, MakeFailed } {
753 switch (err) {760 switch (err) {
754 error.CacheCheckFailed => switch (man.diagnostic) {761 error.CacheCheckFailed => return s.fail(maker, "checking cache failed: {f}", .{diag.fmt(man)}),
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 },
765 error.OutOfMemory, error.Canceled => |e| return e,762 error.OutOfMemory, error.Canceled => |e| return e,
766 }763 }
767}764}
lib/std/Build/Cache.zig+142-99
...@@ -289,7 +289,6 @@ pub const Manifest = struct {...@@ -289,7 +289,6 @@ pub const Manifest = struct {
289 /// Indexes line up with `files`, but only up until `hit` is called. Uses289 /// Indexes line up with `files`, but only up until `hit` is called. Uses
290 /// `Cache.gpa`.290 /// `Cache.gpa`.
291 input_paths: std.ArrayList(InputPath) = .empty,291 input_paths: std.ArrayList(InputPath) = .empty,
292 diagnostic: Diagnostic = .none,
293 /// Keeps track of the last time we performed a file system write to observe292 /// Keeps track of the last time we performed a file system write to observe
294 /// what time the file system thinks it is, according to its own granularity.293 /// what time the file system thinks it is, according to its own granularity.
295 recent_problematic_timestamp: Io.Timestamp = .zero,294 recent_problematic_timestamp: Io.Timestamp = .zero,
...@@ -591,8 +590,7 @@ pub const Manifest = struct {...@@ -591,8 +590,7 @@ pub const Manifest = struct {
591 }590 }
592 };591 };
593592
594 pub const Diagnostic = union(enum) {593 pub const CheckDiagnostic = union(enum) {
595 none,
596 manifest_create: Io.File.OpenError,594 manifest_create: Io.File.OpenError,
597 manifest_stat: Io.File.StatError,595 manifest_stat: Io.File.StatError,
598 manifest_oversize,596 manifest_oversize,
...@@ -617,6 +615,31 @@ pub const Manifest = struct {...@@ -617,6 +615,31 @@ pub const Manifest = struct {
617 };615 };
618 }616 }
619 };617 };
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 }
620 };643 };
621644
622 pub const Stat = struct {645 pub const Stat = struct {
...@@ -816,6 +839,28 @@ pub const Manifest = struct {...@@ -816,6 +839,28 @@ pub const Manifest = struct {
816 directory_status_changed: File.Offset,839 directory_status_changed: File.Offset,
817 metadata_changed: File.Offset,840 metadata_changed: File.Offset,
818 contents_changed: File.Offset,841 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 }
819 };864 };
820865
821 pub const CheckError = error{866 pub const CheckError = error{
...@@ -836,13 +881,17 @@ pub const Manifest = struct {...@@ -836,13 +881,17 @@ pub const Manifest = struct {
836 /// The lock on the manifest file is released when `deinit` is called. As another881 /// The lock on the manifest file is released when `deinit` is called. As another
837 /// option, one may call `toOwnedLock` to obtain a smaller object which can represent882 /// option, one may call `toOwnedLock` to obtain a smaller object which can represent
838 /// the lock. `deinit` is safe to call whether or not `toOwnedLock` has been called.883 /// 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 {
840 const node = parent_progress_node.start("Reusing Cache Artifacts", 0);889 const node = parent_progress_node.start("Reusing Cache Artifacts", 0);
841 defer node.end();890 defer node.end();
842 return checkProgressless(man);891 return checkProgressless(man, diag);
843 }892 }
844893
845 pub fn checkProgressless(man: *Manifest) CheckError!CheckResult {894 pub fn checkProgressless(man: *Manifest, diag: *CheckDiagnostic) CheckError!CheckResult {
846 assert(man.state == .input);895 assert(man.state == .input);
847 assert(man.manifest_file == null);896 assert(man.manifest_file == null);
848897
...@@ -852,8 +901,6 @@ pub const Manifest = struct {...@@ -852,8 +901,6 @@ pub const Manifest = struct {
852 man.hashFlagsAndPath(file_off, &man.hash.hasher);901 man.hashFlagsAndPath(file_off, &man.hash.hasher);
853 }902 }
854903
855 man.diagnostic = .none;
856
857 var input_digest: BinDigest = undefined;904 var input_digest: BinDigest = undefined;
858 man.hash.hasher.final(&input_digest);905 man.hash.hasher.final(&input_digest);
859 const input_hex_digest = binToHex(input_digest);906 const input_hex_digest = binToHex(input_digest);
...@@ -879,10 +926,7 @@ pub const Manifest = struct {...@@ -879,10 +926,7 @@ pub const Manifest = struct {
879 man.manifest_file = man.cache.manifest_dir.openFile(io, manifest_file_path, .{926 man.manifest_file = man.cache.manifest_dir.openFile(io, manifest_file_path, .{
880 .mode = .read_write,927 .mode = .read_write,
881 .lock = .shared,928 .lock = .shared,
882 }) catch |e| {929 }) catch |e| return fail(diag, .{ .manifest_create = e });
883 man.diagnostic = .{ .manifest_create = e };
884 return error.CacheCheckFailed;
885 };
886 break;930 break;
887 },931 },
888 error.FileNotFound => {932 error.FileNotFound => {
...@@ -895,10 +939,7 @@ pub const Manifest = struct {...@@ -895,10 +939,7 @@ pub const Manifest = struct {
895 // disambiguates by returning EEXIST, indicating original939 // disambiguates by returning EEXIST, indicating original
896 // failure was a race, or ENOENT, indicating deletion of940 // failure was a race, or ENOENT, indicating deletion of
897 // the directory of our open handle.941 // the directory of our open handle.
898 if (!builtin.os.tag.isDarwin()) {942 if (!builtin.os.tag.isDarwin()) return fail(diag, .{ .manifest_create = error.FileNotFound });
899 man.diagnostic = .{ .manifest_create = error.FileNotFound };
900 return error.CacheCheckFailed;
901 }
902943
903 if (man.cache.manifest_dir.createFile(io, manifest_file_path, .{944 if (man.cache.manifest_dir.createFile(io, manifest_file_path, .{
904 .read = true,945 .read = true,
...@@ -912,22 +953,13 @@ pub const Manifest = struct {...@@ -912,22 +953,13 @@ pub const Manifest = struct {
912 break;953 break;
913 } else |excl_err| switch (excl_err) {954 } else |excl_err| switch (excl_err) {
914 error.WouldBlock, error.PathAlreadyExists => continue,955 error.WouldBlock, error.PathAlreadyExists => continue,
915 error.FileNotFound => {956 error.FileNotFound => return fail(diag, .{ .manifest_create = error.FileNotFound }),
916 man.diagnostic = .{ .manifest_create = error.FileNotFound };
917 return error.CacheCheckFailed;
918 },
919 error.Canceled => |e| return e,957 error.Canceled => |e| return e,
920 else => |e| {958 else => |e| return fail(diag, .{ .manifest_create = e }),
921 man.diagnostic = .{ .manifest_create = e };
922 return error.CacheCheckFailed;
923 },
924 }959 }
925 },960 },
926 error.Canceled => |e| return e,961 error.Canceled => |e| return e,
927 else => |e| {962 else => |e| return fail(diag, .{ .manifest_create = e }),
928 man.diagnostic = .{ .manifest_create = e };
929 return error.CacheCheckFailed;
930 },
931 }963 }
932 }964 }
933965
...@@ -949,16 +981,16 @@ pub const Manifest = struct {...@@ -949,16 +981,16 @@ pub const Manifest = struct {
949981
950 hit: {982 hit: {
951 const miss_result = miss: {983 const miss_result = miss: {
952 const result = try man.checkLocked();984 const result = try man.checkLocked(diag);
953 if (result == .hit) {985 if (result == .hit) {
954 break :hit;986 break :hit;
955 } else if (!try man.upgradeToExclusiveLock()) {987 } else if (!try man.upgradeToExclusiveLock(diag)) {
956 break :miss result;988 break :miss result;
957 }989 }
958 // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have990 // Missed with the shared lock, and upgraded to an exclusive lock. However, another process may have
959 // modified the cache directory, so we need to check again before deciding to miss.991 // modified the cache directory, so we need to check again before deciding to miss.
960 man.shrinkFilesToInput();992 man.shrinkFilesToInput();
961 const refreshed_result = try man.checkLocked();993 const refreshed_result = try man.checkLocked(diag);
962 if (refreshed_result == .hit) break :hit;994 if (refreshed_result == .hit) break :hit;
963 break :miss refreshed_result;995 break :miss refreshed_result;
964 };996 };
...@@ -970,10 +1002,7 @@ pub const Manifest = struct {...@@ -970,10 +1002,7 @@ pub const Manifest = struct {
970 }1002 }
9711003
972 if (man.want_shared_lock) {1004 if (man.want_shared_lock) {
973 man.downgradeToSharedLock() catch |err| {1005 man.downgradeToSharedLock() catch |err| return fail(diag, .{ .manifest_lock = err });
974 man.diagnostic = .{ .manifest_lock = err };
975 return error.CacheCheckFailed;
976 };
977 }1006 }
9781007
979 man.state = .hit;1008 man.state = .hit;
...@@ -1006,7 +1035,7 @@ pub const Manifest = struct {...@@ -1006,7 +1035,7 @@ pub const Manifest = struct {
1006 }1035 }
10071036
1008 /// Does not observe or modify `self.hash.hasher`. Asserts `self.files` contains only the original input files.1037 /// 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 {
1010 assert(m.files.count() == m.input_paths.items.len);1039 assert(m.files.count() == m.input_paths.items.len);
1011 const gpa = m.cache.gpa;1040 const gpa = m.cache.gpa;
1012 const io = m.cache.io;1041 const io = m.cache.io;
...@@ -1014,15 +1043,15 @@ pub const Manifest = struct {...@@ -1014,15 +1043,15 @@ pub const Manifest = struct {
10141043
1015 const manifest_stat = manifest_file.stat(io) catch |err| switch (err) {1044 const manifest_stat = manifest_file.stat(io) catch |err| switch (err) {
1016 error.Canceled => |e| return e,1045 error.Canceled => |e| return e,
1017 else => |e| return fail(&m.diagnostic, .{ .manifest_stat = e }),1046 else => |e| return fail(diag, .{ .manifest_stat = e }),
1018 };1047 };
1019 const manifest_size = std.math.cast(u32, manifest_stat.size) orelse1048 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
1022 if (manifest_size == 0 or manifest_size < m.contents.items.len) {1051 if (manifest_size == 0 or manifest_size < m.contents.items.len) {
1023 // Manifest file was never finalized.1052 // Manifest file was never finalized.
1024 try m.contents.ensureUnusedCapacity(gpa, 1);1053 try m.contents.ensureUnusedCapacity(gpa, 1);
1025 return populateMissingInputFileHashes(m, 0, .incomplete_manifest);1054 return populateMissingInputFileHashes(m, diag, 0, .incomplete_manifest);
1026 }1055 }
10271056
1028 // We must not clobber existing `Manifest.contents` because it possibly contains prepopulated stat and digest1057 // We must not clobber existing `Manifest.contents` because it possibly contains prepopulated stat and digest
...@@ -1039,9 +1068,9 @@ pub const Manifest = struct {...@@ -1039,9 +1068,9 @@ pub const Manifest = struct {
1039 {1068 {
1040 const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) {1069 const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) {
1041 error.Canceled => |e| return e,1070 error.Canceled => |e| return e,
1042 else => |e| return fail(&m.diagnostic, .{ .manifest_read = e }),1071 else => |e| return fail(diag, .{ .manifest_read = e }),
1043 };1072 };
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);
1045 }1074 }
1046 const disk_contents = m.contents.items[0..manifest_size];1075 const disk_contents = m.contents.items[0..manifest_size];
1047 const input_contents = m.contents.items[manifest_size..][0..input_contents_len];1076 const input_contents = m.contents.items[manifest_size..][0..input_contents_len];
...@@ -1050,12 +1079,12 @@ pub const Manifest = struct {...@@ -1050,12 +1079,12 @@ pub const Manifest = struct {
1050 var off: usize = 0;1079 var off: usize = 0;
1051 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len], 0..) |*input_path, file_off, i| {1080 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len], 0..) |*input_path, file_off, i| {
1052 if (@backingInt(file_off) + 1 >= disk_contents.len)1081 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);
1054 if (!mem.eql(u8, file_off.flagsAndPath(disk_contents), file_off.flagsAndPath(input_contents)))1083 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);1086 const result = try checkInputPath(m, diag, file_off, input_path, disk_contents, input_contents);
1058 if (result != .hit) return missInput(m, i + 1, input_contents_len, manifest_size, result);1087 if (result != .hit) return missInput(m, diag, i + 1, input_contents_len, manifest_size, result);
1059 off = @backingInt(file_off);1088 off = @backingInt(file_off);
1060 }1089 }
10611090
...@@ -1074,7 +1103,7 @@ pub const Manifest = struct {...@@ -1074,7 +1103,7 @@ pub const Manifest = struct {
1074 if (path.len == 0) return .invalid_manifest;1103 if (path.len == 0) return .invalid_manifest;
10751104
1076 try m.files.putContext(gpa, file_off, {}, .{ .contents = disk_contents });1105 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);
1078 if (result != .hit) return result;1107 if (result != .hit) return result;
10791108
1080 off += File.sizeOf(path.len);1109 off += File.sizeOf(path.len);
...@@ -1098,6 +1127,7 @@ pub const Manifest = struct {...@@ -1098,6 +1127,7 @@ pub const Manifest = struct {
1098 /// missed one.1127 /// missed one.
1099 fn missInput(1128 fn missInput(
1100 m: *Manifest,1129 m: *Manifest,
1130 diag: *CheckDiagnostic,
1101 next_file_index: usize,1131 next_file_index: usize,
1102 input_contents_len: usize,1132 input_contents_len: usize,
1103 manifest_size: usize,1133 manifest_size: usize,
...@@ -1114,18 +1144,19 @@ pub const Manifest = struct {...@@ -1114,18 +1144,19 @@ pub const Manifest = struct {
1114 m.contents.items[manifest_size + off ..][0..copy_len],1144 m.contents.items[manifest_size + off ..][0..copy_len],
1115 );1145 );
1116 m.contents.shrinkRetainingCapacity(input_contents_len);1146 m.contents.shrinkRetainingCapacity(input_contents_len);
1117 return populateMissingInputFileHashes(m, next_file_index, result);1147 return populateMissingInputFileHashes(m, diag, next_file_index, result);
1118 }1148 }
11191149
1120 fn populateMissingInputFileHashes(1150 fn populateMissingInputFileHashes(
1121 m: *Manifest,1151 m: *Manifest,
1152 diag: *CheckDiagnostic,
1122 next_file_index: usize,1153 next_file_index: usize,
1123 result: CheckResult,1154 result: CheckResult,
1124 ) CheckError!CheckResult {1155 ) CheckError!CheckResult {
1125 const file_offs = m.files.keys();1156 const file_offs = m.files.keys();
1126 const contents = m.contents.items;1157 const contents = m.contents.items;
1127 for (file_offs[next_file_index..], m.input_paths.items[next_file_index..]) |input_file_off, *input_path| {1158 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);
1129 }1160 }
1130 return result;1161 return result;
1131 }1162 }
...@@ -1134,6 +1165,7 @@ pub const Manifest = struct {...@@ -1134,6 +1165,7 @@ pub const Manifest = struct {
1134 /// system. Only ensures that metadata and digest are available.1165 /// system. Only ensures that metadata and digest are available.
1135 fn populateInputPath(1166 fn populateInputPath(
1136 m: *Manifest,1167 m: *Manifest,
1168 diag: *CheckDiagnostic,
1137 file_off: File.Offset,1169 file_off: File.Offset,
1138 input_path: *InputPath,1170 input_path: *InputPath,
1139 contents: []u8,1171 contents: []u8,
...@@ -1156,21 +1188,21 @@ pub const Manifest = struct {...@@ -1156,21 +1188,21 @@ pub const Manifest = struct {
1156 const actual_stat = switch (input_path.getHandle(input_file)) {1188 const actual_stat = switch (input_path.getHandle(input_file)) {
1157 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {1189 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
1158 error.Canceled => |e| return e,1190 error.Canceled => |e| return e,
1159 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1191 else => |e| return fail(diag, .{ .file_stat = .{
1160 .file_offset = file_off,1192 .file_offset = file_off,
1161 .err = e,1193 .err = e,
1162 } }),1194 } }),
1163 },1195 },
1164 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {1196 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {
1165 error.Canceled => |e| return e,1197 error.Canceled => |e| return e,
1166 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1198 else => |e| return fail(diag, .{ .file_stat = .{
1167 .file_offset = file_off,1199 .file_offset = file_off,
1168 .err = e,1200 .err = e,
1169 } }),1201 } }),
1170 },1202 },
1171 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {1203 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {
1172 error.Canceled => |e| return e,1204 error.Canceled => |e| return e,
1173 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1205 else => |e| return fail(diag, .{ .file_stat = .{
1174 .file_offset = file_off,1206 .file_offset = file_off,
1175 .err = e,1207 .err = e,
1176 } }),1208 } }),
...@@ -1179,7 +1211,7 @@ pub const Manifest = struct {...@@ -1179,7 +1211,7 @@ pub const Manifest = struct {
1179 const actual_is_directory = actual_stat.kind == .directory;1211 const actual_is_directory = actual_stat.kind == .directory;
1180 if (actual_is_directory != input_file.flags.is_directory) {1212 if (actual_is_directory != input_file.flags.is_directory) {
1181 // Since this is an input file, this is a failure, not a cache miss.1213 // 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 = .{
1183 .file_offset = file_off,1215 .file_offset = file_off,
1184 .err = if (actual_is_directory) error.IsDir else error.NotDir,1216 .err = if (actual_is_directory) error.IsDir else error.NotDir,
1185 } });1217 } });
...@@ -1210,7 +1242,7 @@ pub const Manifest = struct {...@@ -1210,7 +1242,7 @@ pub const Manifest = struct {
1210 .access_sub_paths = false,1242 .access_sub_paths = false,
1211 }) catch |err| switch (err) {1243 }) catch |err| switch (err) {
1212 error.Canceled => |e| return e,1244 error.Canceled => |e| return e,
1213 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1245 else => |e| return fail(diag, .{ .file_open = .{
1214 .file_offset = file_off,1246 .file_offset = file_off,
1215 .err = e,1247 .err = e,
1216 } }),1248 } }),
...@@ -1224,7 +1256,7 @@ pub const Manifest = struct {...@@ -1224,7 +1256,7 @@ pub const Manifest = struct {
1224 assert(!stat_path_ok);1256 assert(!stat_path_ok);
1225 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {1257 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
1226 error.Canceled => |e| return e,1258 error.Canceled => |e| return e,
1227 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1259 else => |e| return fail(diag, .{ .file_stat = .{
1228 .file_offset = file_off,1260 .file_offset = file_off,
1229 .err = e,1261 .err = e,
1230 } }),1262 } }),
...@@ -1235,7 +1267,7 @@ pub const Manifest = struct {...@@ -1235,7 +1267,7 @@ pub const Manifest = struct {
1235 const dir_contents_start = m.all_input_content.items.len;1267 const dir_contents_start = m.all_input_content.items.len;
1236 hashDir(gpa, io, opened_dir, &input_file.digest, &m.all_input_content) catch |err| switch (err) {1268 hashDir(gpa, io, opened_dir, &input_file.digest, &m.all_input_content) catch |err| switch (err) {
1237 error.Canceled, error.OutOfMemory => |e| return e,1269 error.Canceled, error.OutOfMemory => |e| return e,
1238 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1270 else => |e| return fail(diag, .{ .file_read = .{
1239 .file_offset = file_off,1271 .file_offset = file_off,
1240 .err = e,1272 .err = e,
1241 } }),1273 } }),
...@@ -1254,7 +1286,7 @@ pub const Manifest = struct {...@@ -1254,7 +1286,7 @@ pub const Manifest = struct {
1254 else1286 else
1255 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {1287 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {
1256 error.Canceled => |e| return e,1288 error.Canceled => |e| return e,
1257 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1289 else => |e| return fail(diag, .{ .file_open = .{
1258 .file_offset = file_off,1290 .file_offset = file_off,
1259 .err = e,1291 .err = e,
1260 } }),1292 } }),
...@@ -1268,7 +1300,7 @@ pub const Manifest = struct {...@@ -1268,7 +1300,7 @@ pub const Manifest = struct {
1268 assert(!stat_path_ok);1300 assert(!stat_path_ok);
1269 const actual_stat = opened_file.stat(io) catch |err| switch (err) {1301 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
1270 error.Canceled => |e| return e,1302 error.Canceled => |e| return e,
1271 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1303 else => |e| return fail(diag, .{ .file_stat = .{
1272 .file_offset = file_off,1304 .file_offset = file_off,
1273 .err = e,1305 .err = e,
1274 } }),1306 } }),
...@@ -1281,7 +1313,7 @@ pub const Manifest = struct {...@@ -1281,7 +1313,7 @@ pub const Manifest = struct {
1281 const start = m.all_input_content.items.len;1313 const start = m.all_input_content.items.len;
1282 hashFileAppend(io, opened_file, &input_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {1314 hashFileAppend(io, opened_file, &input_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {
1283 error.Canceled, error.OutOfMemory => |e| return e,1315 error.Canceled, error.OutOfMemory => |e| return e,
1284 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1316 else => |e| return fail(diag, .{ .file_read = .{
1285 .file_offset = file_off,1317 .file_offset = file_off,
1286 .err = e,1318 .err = e,
1287 } }),1319 } }),
...@@ -1293,7 +1325,7 @@ pub const Manifest = struct {...@@ -1293,7 +1325,7 @@ pub const Manifest = struct {
1293 },1325 },
1294 .unrequested => hashFile(io, opened_file, &input_file.digest) catch |err| switch (err) {1326 .unrequested => hashFile(io, opened_file, &input_file.digest) catch |err| switch (err) {
1295 error.Canceled => |e| return e,1327 error.Canceled => |e| return e,
1296 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1328 else => |e| return fail(diag, .{ .file_read = .{
1297 .file_offset = file_off,1329 .file_offset = file_off,
1298 .err = e,1330 .err = e,
1299 } }),1331 } }),
...@@ -1306,6 +1338,7 @@ pub const Manifest = struct {...@@ -1306,6 +1338,7 @@ pub const Manifest = struct {
1306 /// Upon return, disk_contents digest and stat will be populated regardless of whether hit or miss occurs.1338 /// Upon return, disk_contents digest and stat will be populated regardless of whether hit or miss occurs.
1307 fn checkInputPath(1339 fn checkInputPath(
1308 m: *Manifest,1340 m: *Manifest,
1341 diag: *CheckDiagnostic,
1309 file_off: File.Offset,1342 file_off: File.Offset,
1310 input_path: *InputPath,1343 input_path: *InputPath,
1311 disk_contents: []u8,1344 disk_contents: []u8,
...@@ -1337,21 +1370,21 @@ pub const Manifest = struct {...@@ -1337,21 +1370,21 @@ pub const Manifest = struct {
1337 const actual_stat = switch (input_path.getHandle(input_file)) {1370 const actual_stat = switch (input_path.getHandle(input_file)) {
1338 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {1371 .none => parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
1339 error.Canceled => |e| return e,1372 error.Canceled => |e| return e,
1340 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1373 else => |e| return fail(diag, .{ .file_stat = .{
1341 .file_offset = file_off,1374 .file_offset = file_off,
1342 .err = e,1375 .err = e,
1343 } }),1376 } }),
1344 },1377 },
1345 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {1378 .file => |opened_file| opened_file.stat(io) catch |err| switch (err) {
1346 error.Canceled => |e| return e,1379 error.Canceled => |e| return e,
1347 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1380 else => |e| return fail(diag, .{ .file_stat = .{
1348 .file_offset = file_off,1381 .file_offset = file_off,
1349 .err = e,1382 .err = e,
1350 } }),1383 } }),
1351 },1384 },
1352 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {1385 .dir => |opened_dir| opened_dir.stat(io) catch |err| switch (err) {
1353 error.Canceled => |e| return e,1386 error.Canceled => |e| return e,
1354 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1387 else => |e| return fail(diag, .{ .file_stat = .{
1355 .file_offset = file_off,1388 .file_offset = file_off,
1356 .err = e,1389 .err = e,
1357 } }),1390 } }),
...@@ -1362,7 +1395,7 @@ pub const Manifest = struct {...@@ -1362,7 +1395,7 @@ pub const Manifest = struct {
1362 const actual_is_directory = actual_stat.kind == .directory;1395 const actual_is_directory = actual_stat.kind == .directory;
1363 if (actual_is_directory != disk_file.flags.is_directory) {1396 if (actual_is_directory != disk_file.flags.is_directory) {
1364 // Since this is an input file, this is a failure, not a cache miss.1397 // 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 = .{
1366 .file_offset = file_off,1399 .file_offset = file_off,
1367 .err = if (actual_is_directory) error.IsDir else error.NotDir,1400 .err = if (actual_is_directory) error.IsDir else error.NotDir,
1368 } });1401 } });
...@@ -1393,7 +1426,7 @@ pub const Manifest = struct {...@@ -1393,7 +1426,7 @@ pub const Manifest = struct {
1393 .access_sub_paths = false,1426 .access_sub_paths = false,
1394 }) catch |err| switch (err) {1427 }) catch |err| switch (err) {
1395 error.Canceled => |e| return e,1428 error.Canceled => |e| return e,
1396 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1429 else => |e| return fail(diag, .{ .file_open = .{
1397 .file_offset = file_off,1430 .file_offset = file_off,
1398 .err = e,1431 .err = e,
1399 } }),1432 } }),
...@@ -1406,7 +1439,7 @@ pub const Manifest = struct {...@@ -1406,7 +1439,7 @@ pub const Manifest = struct {
1406 if (!input_path.have_stat) {1439 if (!input_path.have_stat) {
1407 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {1440 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
1408 error.Canceled => |e| return e,1441 error.Canceled => |e| return e,
1409 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1442 else => |e| return fail(diag, .{ .file_stat = .{
1410 .file_offset = file_off,1443 .file_offset = file_off,
1411 .err = e,1444 .err = e,
1412 } }),1445 } }),
...@@ -1417,7 +1450,7 @@ pub const Manifest = struct {...@@ -1417,7 +1450,7 @@ pub const Manifest = struct {
1417 const dir_contents_start = m.all_input_content.items.len;1450 const dir_contents_start = m.all_input_content.items.len;
1418 hashDir(gpa, io, opened_dir, &disk_file.digest, &m.all_input_content) catch |err| switch (err) {1451 hashDir(gpa, io, opened_dir, &disk_file.digest, &m.all_input_content) catch |err| switch (err) {
1419 error.Canceled, error.OutOfMemory => |e| return e,1452 error.Canceled, error.OutOfMemory => |e| return e,
1420 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1453 else => |e| return fail(diag, .{ .file_read = .{
1421 .file_offset = file_off,1454 .file_offset = file_off,
1422 .err = e,1455 .err = e,
1423 } }),1456 } }),
...@@ -1439,7 +1472,7 @@ pub const Manifest = struct {...@@ -1439,7 +1472,7 @@ pub const Manifest = struct {
1439 else1472 else
1440 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {1473 parent_dir.openFile(io, file_path, .{ .mode = .read_only }) catch |err| switch (err) {
1441 error.Canceled => |e| return e,1474 error.Canceled => |e| return e,
1442 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1475 else => |e| return fail(diag, .{ .file_open = .{
1443 .file_offset = file_off,1476 .file_offset = file_off,
1444 .err = e,1477 .err = e,
1445 } }),1478 } }),
...@@ -1452,7 +1485,7 @@ pub const Manifest = struct {...@@ -1452,7 +1485,7 @@ pub const Manifest = struct {
1452 if (!input_path.have_stat) {1485 if (!input_path.have_stat) {
1453 const actual_stat = opened_file.stat(io) catch |err| switch (err) {1486 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
1454 error.Canceled => |e| return e,1487 error.Canceled => |e| return e,
1455 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1488 else => |e| return fail(diag, .{ .file_stat = .{
1456 .file_offset = file_off,1489 .file_offset = file_off,
1457 .err = e,1490 .err = e,
1458 } }),1491 } }),
...@@ -1465,7 +1498,7 @@ pub const Manifest = struct {...@@ -1465,7 +1498,7 @@ pub const Manifest = struct {
1465 const start = m.all_input_content.items.len;1498 const start = m.all_input_content.items.len;
1466 hashFileAppend(io, opened_file, &disk_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {1499 hashFileAppend(io, opened_file, &disk_file.digest, &m.all_input_content, gpa) catch |err| switch (err) {
1467 error.Canceled, error.OutOfMemory => |e| return e,1500 error.Canceled, error.OutOfMemory => |e| return e,
1468 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1501 else => |e| return fail(diag, .{ .file_read = .{
1469 .file_offset = file_off,1502 .file_offset = file_off,
1470 .err = e,1503 .err = e,
1471 } }),1504 } }),
...@@ -1477,7 +1510,7 @@ pub const Manifest = struct {...@@ -1477,7 +1510,7 @@ pub const Manifest = struct {
1477 },1510 },
1478 .unrequested => hashFile(io, opened_file, &disk_file.digest) catch |err| switch (err) {1511 .unrequested => hashFile(io, opened_file, &disk_file.digest) catch |err| switch (err) {
1479 error.Canceled => |e| return e,1512 error.Canceled => |e| return e,
1480 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1513 else => |e| return fail(diag, .{ .file_read = .{
1481 .file_offset = file_off,1514 .file_offset = file_off,
1482 .err = e,1515 .err = e,
1483 } }),1516 } }),
...@@ -1490,7 +1523,12 @@ pub const Manifest = struct {...@@ -1490,7 +1523,12 @@ pub const Manifest = struct {
1490 }1523 }
1491 }1524 }
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 {
1494 const file = file_off.get(contents);1532 const file = file_off.get(contents);
1495 const cache = m.cache;1533 const cache = m.cache;
1496 const gpa = cache.gpa;1534 const gpa = cache.gpa;
...@@ -1502,7 +1540,7 @@ pub const Manifest = struct {...@@ -1502,7 +1540,7 @@ pub const Manifest = struct {
1502 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {1540 const actual_stat = parent_dir.statFile(io, file_path, .{}) catch |err| switch (err) {
1503 error.FileNotFound => return .{ .path_deleted = file_off },1541 error.FileNotFound => return .{ .path_deleted = file_off },
1504 error.Canceled => |e| return e,1542 error.Canceled => |e| return e,
1505 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1543 else => |e| return fail(diag, .{ .file_stat = .{
1506 .file_offset = file_off,1544 .file_offset = file_off,
1507 .err = e,1545 .err = e,
1508 } }),1546 } }),
...@@ -1525,7 +1563,7 @@ pub const Manifest = struct {...@@ -1525,7 +1563,7 @@ pub const Manifest = struct {
1525 error.FileNotFound => return .{ .path_deleted = file_off },1563 error.FileNotFound => return .{ .path_deleted = file_off },
1526 error.NotDir => return .{ .directory_status_changed = file_off },1564 error.NotDir => return .{ .directory_status_changed = file_off },
1527 error.Canceled => |e| return e,1565 error.Canceled => |e| return e,
1528 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1566 else => |e| return fail(diag, .{ .file_open = .{
1529 .file_offset = file_off,1567 .file_offset = file_off,
1530 .err = e,1568 .err = e,
1531 } }),1569 } }),
...@@ -1534,7 +1572,7 @@ pub const Manifest = struct {...@@ -1534,7 +1572,7 @@ pub const Manifest = struct {
15341572
1535 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {1573 const actual_stat = opened_dir.stat(io) catch |err| switch (err) {
1536 error.Canceled => |e| return e,1574 error.Canceled => |e| return e,
1537 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1575 else => |e| return fail(diag, .{ .file_stat = .{
1538 .file_offset = file_off,1576 .file_offset = file_off,
1539 .err = e,1577 .err = e,
1540 } }),1578 } }),
...@@ -1545,7 +1583,7 @@ pub const Manifest = struct {...@@ -1545,7 +1583,7 @@ pub const Manifest = struct {
1545 defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start);1583 defer m.all_input_content.shrinkRetainingCapacity(dir_contents_start);
1546 hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) {1584 hashDir(gpa, io, opened_dir, &file.digest, &m.all_input_content) catch |err| switch (err) {
1547 error.Canceled, error.OutOfMemory => |e| return e,1585 error.Canceled, error.OutOfMemory => |e| return e,
1548 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1586 else => |e| return fail(diag, .{ .file_read = .{
1549 .file_offset = file_off,1587 .file_offset = file_off,
1550 .err = e,1588 .err = e,
1551 } }),1589 } }),
...@@ -1560,7 +1598,7 @@ pub const Manifest = struct {...@@ -1560,7 +1598,7 @@ pub const Manifest = struct {
1560 error.FileNotFound => return .{ .path_deleted = file_off },1598 error.FileNotFound => return .{ .path_deleted = file_off },
1561 error.IsDir => return .{ .directory_status_changed = file_off },1599 error.IsDir => return .{ .directory_status_changed = file_off },
1562 error.Canceled => |e| return e,1600 error.Canceled => |e| return e,
1563 else => |e| return fail(&m.diagnostic, .{ .file_open = .{1601 else => |e| return fail(diag, .{ .file_open = .{
1564 .file_offset = file_off,1602 .file_offset = file_off,
1565 .err = e,1603 .err = e,
1566 } }),1604 } }),
...@@ -1569,7 +1607,7 @@ pub const Manifest = struct {...@@ -1569,7 +1607,7 @@ pub const Manifest = struct {
15691607
1570 const actual_stat = opened_file.stat(io) catch |err| switch (err) {1608 const actual_stat = opened_file.stat(io) catch |err| switch (err) {
1571 error.Canceled => |e| return e,1609 error.Canceled => |e| return e,
1572 else => |e| return fail(&m.diagnostic, .{ .file_stat = .{1610 else => |e| return fail(diag, .{ .file_stat = .{
1573 .file_offset = file_off,1611 .file_offset = file_off,
1574 .err = e,1612 .err = e,
1575 } }),1613 } }),
...@@ -1579,7 +1617,7 @@ pub const Manifest = struct {...@@ -1579,7 +1617,7 @@ pub const Manifest = struct {
1579 const prev_digest: BinDigest = file.digest;1617 const prev_digest: BinDigest = file.digest;
1580 hashFile(io, opened_file, &file.digest) catch |err| switch (err) {1618 hashFile(io, opened_file, &file.digest) catch |err| switch (err) {
1581 error.Canceled => |e| return e,1619 error.Canceled => |e| return e,
1582 else => |e| return fail(&m.diagnostic, .{ .file_read = .{1620 else => |e| return fail(diag, .{ .file_read = .{
1583 .file_offset = file_off,1621 .file_offset = file_off,
1584 .err = e,1622 .err = e,
1585 } }),1623 } }),
...@@ -1591,8 +1629,7 @@ pub const Manifest = struct {...@@ -1591,8 +1629,7 @@ pub const Manifest = struct {
1591 return .hit;1629 return .hit;
1592 }1630 }
15931631
1594 fn fail(ptr: *Diagnostic, d: Diagnostic) error{CacheCheckFailed} {1632 fn fail(ptr: *CheckDiagnostic, d: CheckDiagnostic) error{CacheCheckFailed} {
1595 assert(ptr.* == .none);
1596 ptr.* = d;1633 ptr.* = d;
1597 return error.CacheCheckFailed;1634 return error.CacheCheckFailed;
1598 }1635 }
...@@ -2002,22 +2039,19 @@ pub const Manifest = struct {...@@ -2002,22 +2039,19 @@ pub const Manifest = struct {
2002 self.have_exclusive_lock = false;2039 self.have_exclusive_lock = false;
2003 }2040 }
20042041
2005 fn upgradeToExclusiveLock(self: *Manifest) error{CacheCheckFailed}!bool {2042 fn upgradeToExclusiveLock(m: *Manifest, diag: *CheckDiagnostic) error{CacheCheckFailed}!bool {
2006 if (self.have_exclusive_lock) return false;2043 if (m.have_exclusive_lock) return false;
2007 assert(self.manifest_file != null);2044 assert(m.manifest_file != null);
2008 const io = self.cache.io;2045 const io = m.cache.io;
20092046
2010 if (std.process.can_spawn or !builtin.single_threaded) {2047 if (std.process.can_spawn or !builtin.single_threaded) {
2011 const manifest_file = self.manifest_file.?;2048 const manifest_file = m.manifest_file.?;
2012 // Here we intentionally have a period where the lock is released, in case there are2049 // Here we intentionally have a period where the lock is released, in case there are
2013 // other processes holding a shared lock.2050 // other processes holding a shared lock.
2014 manifest_file.unlock(io);2051 manifest_file.unlock(io);
2015 manifest_file.lock(io, .exclusive) catch |err| {2052 manifest_file.lock(io, .exclusive) catch |err| return fail(diag, .{ .manifest_lock = err });
2016 self.diagnostic = .{ .manifest_lock = err };
2017 return error.CacheCheckFailed;
2018 };
2019 }2053 }
2020 self.have_exclusive_lock = true;2054 m.have_exclusive_lock = true;
2021 return true;2055 return true;
2022 }2056 }
20232057
...@@ -2327,7 +2361,8 @@ test "cache file and then recall it" {...@@ -2327,7 +2361,8 @@ test "cache file and then recall it" {
2327 .sub_path = temp_file,2361 .sub_path = temp_file,
2328 }, .{});2362 }, .{});
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
2332 digest1 = man.missDigestHex();2367 digest1 = man.missDigestHex();
2333 try man.finalize();2368 try man.finalize();
...@@ -2345,7 +2380,8 @@ test "cache file and then recall it" {...@@ -2345,7 +2380,8 @@ test "cache file and then recall it" {
2345 }, .{});2380 }, .{});
23462381
2347 // Cache hit! We just "built" the same file2382 // 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));
2349 digest2 = man.hitDigestHex();2385 digest2 = man.hitDigestHex();
23502386
2351 try testing.expectEqual(false, man.have_exclusive_lock);2387 try testing.expectEqual(false, man.have_exclusive_lock);
...@@ -2406,7 +2442,8 @@ test "check that changing a file causes cache miss" {...@@ -2406,7 +2442,8 @@ test "check that changing a file causes cache miss" {
2406 .sub_path = temp_file,2442 .sub_path = temp_file,
2407 }, .{ .request_contents = true });2443 }, .{ .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
2411 try testing.expectEqualStrings(original_temp_file_contents, temp_file_idx.contents(&man));2448 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" {...@@ -2428,9 +2465,10 @@ test "check that changing a file causes cache miss" {
2428 }, .{ .request_contents = true });2465 }, .{ .request_contents = true });
24292466
2430 // The one input file changed.2467 // The one input file changed.
2468 var diag: Manifest.CheckDiagnostic = undefined;
2431 try testing.expectEqual(2469 try testing.expectEqual(
2432 @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }),2470 @as(Manifest.CheckResult, .{ .contents_changed = temp_file_idx.offset(&man) }),
2433 try man.check(.none),2471 try man.check(&diag, .none),
2434 );2472 );
24352473
2436 try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man));2474 try testing.expectEqualStrings(updated_temp_file_contents, temp_file_idx.contents(&man));
...@@ -2473,7 +2511,8 @@ test "no file inputs" {...@@ -2473,7 +2511,8 @@ test "no file inputs" {
24732511
2474 man.hash.addBytes("1234");2512 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
2478 digest1 = man.missDigestHex();2517 digest1 = man.missDigestHex();
24792518
...@@ -2485,7 +2524,8 @@ test "no file inputs" {...@@ -2485,7 +2524,8 @@ test "no file inputs" {
24852524
2486 man.hash.addBytes("1234");2525 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));
2489 digest2 = man.hitDigestHex();2529 digest2 = man.hitDigestHex();
2490 try testing.expectEqual(false, man.have_exclusive_lock);2530 try testing.expectEqual(false, man.have_exclusive_lock);
2491 }2531 }
...@@ -2545,7 +2585,8 @@ test "Manifest with files added after initial hash" {...@@ -2545,7 +2585,8 @@ test "Manifest with files added after initial hash" {
2545 .sub_path = temp_file1,2585 .sub_path = temp_file1,
2546 }, .{});2586 }, .{});
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
2550 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .{2591 try man.addDiscoveredPath(.{ .discovered_path = .{ .unresolved = .{
2551 .root_dir = tmp_directory,2592 .root_dir = tmp_directory,
...@@ -2565,7 +2606,8 @@ test "Manifest with files added after initial hash" {...@@ -2565,7 +2606,8 @@ test "Manifest with files added after initial hash" {
2565 .sub_path = temp_file1,2606 .sub_path = temp_file1,
2566 }, .{});2607 }, .{});
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));
2569 digest2 = man.hitDigestHex();2611 digest2 = man.hitDigestHex();
25702612
2571 try testing.expectEqual(false, man.have_exclusive_lock);2613 try testing.expectEqual(false, man.have_exclusive_lock);
...@@ -2591,7 +2633,8 @@ test "Manifest with files added after initial hash" {...@@ -2591,7 +2633,8 @@ test "Manifest with files added after initial hash" {
2591 .sub_path = temp_file1,2633 .sub_path = temp_file1,
2592 }, .{});2634 }, .{});
25932635
2594 switch (try man.check(.none)) {2636 var diag: Manifest.CheckDiagnostic = undefined;
2637 switch (try man.check(&diag, .none)) {
2595 .contents_changed => |off| {2638 .contents_changed => |off| {
2596 try testing.expectEqualStrings(temp_file2, off.path(man.contents.items));2639 try testing.expectEqualStrings(temp_file2, off.path(man.contents.items));
2597 },2640 },
src/Compilation.zig+52-28
...@@ -2813,27 +2813,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2813,27 +2813,14 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2813 man.want_shared_lock = false;2813 man.want_shared_lock = false;
2814 }2814 }
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) {
2817 error.Canceled, error.OutOfMemory => |e| return e,2818 error.Canceled, error.OutOfMemory => |e| return e,
2818 error.CacheCheckFailed => switch (man.diagnostic) {2819 error.CacheCheckFailed => {
2819 .none => unreachable,2820 return comp.setMiscFailure(.check_whole_cache, "checking cache failed: {f}", .{diag.fmt(&man)});
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 },
2835 },2821 },
2836 };2822 };
2823 log.debug("{s} whole cache {f} ignore_hit={}", .{ comp.root_name, status.fmt(&man), ignore_hit });
2837 if (status == .hit and !ignore_hit) {2824 if (status == .hit and !ignore_hit) {
2838 // In this case the cache hit contains the full set of file system inputs. Nice!2825 // In this case the cache hit contains the full set of file system inputs. Nice!
2839 if (comp.file_system_inputs) |buf| try man.populateFileSystemInputs(buf);2826 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...@@ -2844,7 +2831,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2844 }2831 }
28452832
2846 comp.last_update_was_cache_hit = true;2833 comp.last_update_was_cache_hit = true;
2847 log.debug("CacheMode.whole cache hit for {s}", .{comp.root_name});
2848 const bin_digest = man.hitDigest();2834 const bin_digest = man.hitDigest();
28492835
2850 comp.digest = bin_digest;2836 comp.digest = bin_digest;
...@@ -2853,7 +2839,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE...@@ -2853,7 +2839,6 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) UpdateE
2853 whole.lock = man.toOwnedLock();2839 whole.lock = man.toOwnedLock();
2854 return;2840 return;
2855 }2841 }
2856 log.debug("CacheMode.whole cache miss for {s}", .{comp.root_name});
28572842
2858 if (ignore_hit) {2843 if (ignore_hit) {
2859 // Okay, now set this back so that `Manifest.finalize` will downgrade our lock later.2844 // 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...@@ -5536,7 +5521,18 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
5536 const target = comp.getTarget();5521 const target = comp.getTarget();
5537 assert(target.ofmt != .c);5522 assert(target.ofmt != .c);
5538 const o_ext = target.ofmt.fileExt(target.cpu.arch);5523 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 }
5540 var argv: std.array_list.Managed([]const u8) = .init(gpa);5536 var argv: std.array_list.Managed([]const u8) = .init(gpa);
5541 defer argv.deinit();5537 defer argv.deinit();
55425538
...@@ -5811,16 +5807,28 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -5811,16 +5807,28 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
5811 }5807 }
58125808
5813 // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.5809 // 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
5816 // Rename into place.5825 // Rename into place.
5817 const digest = man.missDigestHex();
5818 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });5826 const o_sub_path = try fs.path.join(arena, &.{ "o", &digest });
5819 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{});5827 var o_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, o_sub_path, .{});
5820 defer o_dir.close(io);5828 defer o_dir.close(io);
5821 const tmp_basename = fs.path.basename(out_obj_path);5829 const tmp_basename = fs.path.basename(out_obj_path);
5822 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io);5830 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, o_basename, io);
5823 break :miss digest;5831 break :d digest;
5824 };5832 };
58255833
5826 if (man.have_exclusive_lock) {5834 if (man.have_exclusive_lock) {
...@@ -5896,7 +5904,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -5896,7 +5904,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
5896 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});5904 const rc_basename = try std.fmt.allocPrint(arena, "{s}.rc", .{src_basename});
5897 const res_basename = try std.fmt.allocPrint(arena, "{s}.res", .{src_basename});5905 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: {
5900 // The digest only depends on the .manifest file, so we can5916 // The digest only depends on the .manifest file, so we can
5901 // get the digest now and write the .res directly to the cache5917 // get the digest now and write the .res directly to the cache
5902 const digest = man.missDigestHex();5918 const digest = man.missDigestHex();
...@@ -5961,7 +5977,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -5961,7 +5977,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59615977
5962 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node);5978 try spawnZigRc(comp, win32_resource, arena, argv.items, child_progress_node);
59635979
5964 break :blk digest;5980 break :miss digest;
5965 };5981 };
59665982
5967 if (man.have_exclusive_lock) {5983 if (man.have_exclusive_lock) {
...@@ -5988,7 +6004,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -5988,7 +6004,15 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
59886004
5989 const rc_basename_noext = src_basename[0 .. src_basename.len - fs.path.extension(src_basename).len];6005 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: {
5992 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{});6016 var zig_cache_tmp_dir = try comp.dirs.local_cache.handle.createDirPathOpen(io, "tmp", .{});
5993 defer zig_cache_tmp_dir.close(io);6017 defer zig_cache_tmp_dir.close(io);
59946018
...@@ -6066,7 +6090,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32...@@ -6066,7 +6090,7 @@ fn updateWin32Resource(comp: *Compilation, win32_resource: *Win32Resource, win32
6066 defer o_dir.close(io);6090 defer o_dir.close(io);
6067 const tmp_basename = fs.path.basename(out_res_path);6091 const tmp_basename = fs.path.basename(out_res_path);
6068 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io);6092 try Io.Dir.rename(zig_cache_tmp_dir, tmp_basename, o_dir, res_filename, io);
6069 break :blk digest;6093 break :miss digest;
6070 };6094 };
60716095
6072 if (man.have_exclusive_lock) {6096 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...@@ -12974,7 +12974,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1297412974
12975 const result = ef_idx.get(zcu);12975 const result = ef_idx.get(zcu);
12976 if (result.val == .none) {12976 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.? });
12978 }12978 }
1297912979
12980 return Air.internedToRef(result.val);12980 return Air.internedToRef(result.val);
...@@ -15911,9 +15911,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -15911,9 +15911,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
15911 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;15911 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
15912 const tree = file.getTree(zcu) catch |err| {15912 const tree = file.getTree(zcu) catch |err| {
15913 // In this case we emit a warning + a less precise source location.15913 // In this case we emit a warning + a less precise source location.
15914 log.warn("unable to load {f}: {s}", .{15914 log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err });
15915 file.path.fmt(zcu.comp), @errorName(err),
15916 });
15917 break :name null;15915 break :name null;
15918 };15916 };
15919 const node = src_node.toAbsolute(src_base_node);15917 const node = src_node.toAbsolute(src_base_node);
...@@ -15939,9 +15937,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -15939,9 +15937,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
15939 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;15937 const file, const src_base_node = Zcu.LazySrcLoc.resolveBaseNode(block.src_base_inst, zcu).?;
15940 const tree = file.getTree(zcu) catch |err| {15938 const tree = file.getTree(zcu) catch |err| {
15941 // In this case we emit a warning + a less precise source location.15939 // In this case we emit a warning + a less precise source location.
15942 log.warn("unable to load {f}: {s}", .{15940 log.warn("failed loading {qf}: {t}", .{ file.path.fmt(zcu.comp), err });
15943 file.path.fmt(zcu.comp), @errorName(err),
15944 });
15945 break :name null;15941 break :name null;
15946 };15942 };
15947 const node = src_node.toAbsolute(src_base_node);15943 const node = src_node.toAbsolute(src_base_node);
...@@ -15950,7 +15946,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat...@@ -15950,7 +15946,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
15950 };15946 };
1595115947
15952 const msg = if (name) |some|15948 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})
15954 else15950 else
15955 try sema.errMsg(src, "variable not accessible from inner function", .{});15951 try sema.errMsg(src, "variable not accessible from inner function", .{});
15956 errdefer msg.destroy(sema.gpa);15952 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...@@ -465,7 +465,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
465 .request_contents = true,465 .request_contents = true,
466 });466 });
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) {
469 const digest = man.hitDigestHex();482 const digest = man.hitDigestHex();
470 return queueSharedObjects(comp, .{483 return queueSharedObjects(comp, .{
471 .lock = man.toOwnedLock(),484 .lock = man.toOwnedLock(),
src/libs/glibc.zig+14-1
...@@ -705,7 +705,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -705,7 +705,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
705 .request_contents = true,705 .request_contents = true,
706 });706 });
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) {
709 const digest = man.hitDigestHex();722 const digest = man.hitDigestHex();
710 return queueSharedObjects(comp, .{723 return queueSharedObjects(comp, .{
711 .lock = man.toOwnedLock(),724 .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...@@ -251,26 +251,17 @@ pub fn buildImportLib(comp: *Compilation, lib_name: []const u8, prog_node: std.P
251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});251 const final_lib_basename = try std.fmt.allocPrint(gpa, "{s}.lib", .{lib_name});
252 errdefer gpa.free(final_lib_basename);252 errdefer gpa.free(final_lib_basename);
253253
254 const status = man.check(prog_node) catch |err| switch (err) {254 var diag: Cache.Manifest.CheckDiagnostic = undefined;
255 error.CacheCheckFailed => switch (man.diagnostic) {255 const status = man.check(&diag, prog_node) catch |err| switch (err) {
256 .none => unreachable,256 error.CacheCheckFailed => {
257 .manifest_oversize => {257 comp.setMiscFailure(.windows_import_lib, "{s} cache check failed: {f}", .{
258 comp.setMiscFailure(.windows_import_lib, "checking cache failed: {t}", .{man.diagnostic});258 final_lib_basename, diag.fmt(&man),
259 return error.AlreadyReported;259 });
260 },260 return error.AlreadyReported;
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 },
271 },261 },
272 error.OutOfMemory, error.Canceled => |e| return e,262 error.OutOfMemory, error.Canceled => |e| return e,
273 };263 };
264 log.debug("{s} cache {f}", .{ final_lib_basename, status.fmt(&man) });
274 if (status == .hit) {265 if (status == .hit) {
275 const digest = man.hitDigestHex();266 const digest = man.hitDigestHex();
276 const sub_path = try std.fs.path.join(gpa, &.{ "o", &digest, final_lib_basename });267 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...@@ -413,7 +413,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
413 .request_contents = true,413 .request_contents = true,
414 });414 });
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) {
417 const digest = man.hitDigestHex();430 const digest = man.hitDigestHex();
418 return queueSharedObjects(comp, .{431 return queueSharedObjects(comp, .{
419 .lock = man.toOwnedLock(),432 .lock = man.toOwnedLock(),
src/libs/openbsd.zig+14-1
...@@ -334,7 +334,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye...@@ -334,7 +334,20 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) anye
334 .request_contents = true,334 .request_contents = true,
335 });335 });
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) {
338 const digest = man.hitDigestHex();351 const digest = man.hitDigestHex();
339 return queueSharedObjects(comp, .{352 return queueSharedObjects(comp, .{
340 .lock = man.toOwnedLock(),353 .lock = man.toOwnedLock(),
src/main.zig+7-1
...@@ -4878,7 +4878,13 @@ fn cmdTranslateC(...@@ -4878,7 +4878,13 @@ fn cmdTranslateC(
4878 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|4878 Compilation.cache_helpers.hashCSource(&man, c_source_file) catch |err|
4879 fatal("unable to process {q}: {t}", .{ c_source_file.src_path, err });4879 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) .{
4882 .digest = man.hitDigest(),4888 .digest = man.hitDigest(),
4883 .cache_hit = true,4889 .cache_hit = true,
4884 .errors = std.zig.ErrorBundle.empty,4890 .errors = std.zig.ErrorBundle.empty,
test/incremental/bad_import+2-2
...@@ -10,7 +10,7 @@ const io = std.Io.Threaded.global_single_threaded.io();...@@ -10,7 +10,7 @@ const io = std.Io.Threaded.global_single_threaded.io();
10comptime {10comptime {
11 _ = @import("bad.zig");11 _ = @import("bad.zig");
12}12}
13#expect_error=bad.zig:1:1: error: unable to load 'bad.zig': FileNotFound13#expect_error=bad.zig:1:1: error: unable to load "bad.zig": FileNotFound
14#expect_error=foo.zig:2:17: note: file imported here14#expect_error=foo.zig:2:17: note: file imported here
1515
16#update=change bad import16#update=change bad import
...@@ -18,7 +18,7 @@ comptime {...@@ -18,7 +18,7 @@ comptime {
18comptime {18comptime {
19 _ = @import("this_is/not_real.zig");19 _ = @import("this_is/not_real.zig");
20}20}
21#expect_error=this_is/not_real.zig:1:1: error: unable to load 'not_real.zig': FileNotFound21#expect_error=this_is/not_real.zig:1:1: error: unable to load "not_real.zig": FileNotFound
22#expect_error=foo.zig:2:17: note: file imported here22#expect_error=foo.zig:2:17: note: file imported here
2323
24#update=remove import of 'foo.zig'24#update=remove import of 'foo.zig'
test/incremental/change_embed_file+2-2
...@@ -17,7 +17,7 @@ Hello again, World!...@@ -17,7 +17,7 @@ Hello again, World!
1717
18#update=delete file18#update=delete file
19#rm_file=string.txt19#rm_file=string.txt
20#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound20#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound
2121
22#update=remove reference to file22#update=remove reference to file
23#file=main.zig23#file=main.zig
...@@ -37,7 +37,7 @@ pub fn main() !void {...@@ -37,7 +37,7 @@ pub fn main() !void {
37 try std.Io.File.stdout().writeStreamingAll(io, string);37 try std.Io.File.stdout().writeStreamingAll(io, string);
38}38}
39const io = std.Io.Threaded.global_single_threaded.io();39const io = std.Io.Threaded.global_single_threaded.io();
40#expect_error=main.zig:2:27: error: unable to open 'string.txt': FileNotFound40#expect_error=main.zig:2:27: error: failed opening "string.txt": FileNotFound
4141
42#update=recreate file42#update=recreate file
43#file=string.txt43#file=string.txt
test/incremental/change_zon_file+2-2
...@@ -17,7 +17,7 @@ const io = std.Io.Threaded.global_single_threaded.io();...@@ -17,7 +17,7 @@ const io = std.Io.Threaded.global_single_threaded.io();
1717
18#update=delete file18#update=delete file
19#rm_file=message.zon19#rm_file=message.zon
20#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound20#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound
21#expect_error=main.zig:2:37: note: file imported here21#expect_error=main.zig:2:37: note: file imported here
2222
23#update=remove reference to ZON file23#update=remove reference to ZON file
...@@ -28,7 +28,7 @@ pub fn main() !void {...@@ -28,7 +28,7 @@ pub fn main() !void {
28 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");28 try std.Io.File.stdout().writeStreamingAll(io, "a hardcoded string\n");
29}29}
30const io = std.Io.Threaded.global_single_threaded.io();30const io = std.Io.Threaded.global_single_threaded.io();
31#expect_error=message.zon:1:1: error: unable to load 'message.zon': FileNotFound31#expect_error=message.zon:1:1: error: unable to load "message.zon": FileNotFound
32#expect_error=main.zig:2:37: note: file imported here32#expect_error=main.zig:2:37: note: file imported here
3333
34#update=recreate ZON file34#update=recreate ZON file