@@ -97,6 +97,20 @@ getBufferOfDependency(llvm::vfs::FileSystem &FS,
97
97
return std::move (DepBuf.get ());
98
98
}
99
99
100
+ static Optional<clang::vfs::Status>
101
+ getStatusOfDependency (clang::vfs::FileSystem &FS,
102
+ StringRef ModulePath, StringRef DepPath,
103
+ DiagnosticEngine &Diags, SourceLoc DiagLoc) {
104
+ auto Status = FS.status (DepPath);
105
+ if (!Status) {
106
+ Diags.diagnose (DiagLoc,
107
+ diag::missing_dependency_of_parseable_module_interface,
108
+ DepPath, ModulePath, Status.getError ().message ());
109
+ return None;
110
+ }
111
+ return Status.get ();
112
+ }
113
+
100
114
// / Construct a cache key for the .swiftmodule being generated. There is a
101
115
// / balance to be struck here between things that go in the cache key and
102
116
// / things that go in the "up to date" check of the cache entry. We want to
@@ -111,20 +125,23 @@ static std::string getCacheHash(ASTContext &Ctx,
111
125
const CompilerInvocation &SubInvocation,
112
126
StringRef InPath) {
113
127
// Start with the compiler version (which will be either tag names or revs).
114
- std::string vers = swift::version::getSwiftFullVersion (
115
- Ctx.LangOpts .EffectiveLanguageVersion );
116
- llvm::hash_code H = llvm::hash_value (vers);
128
+ // Explicitly don't pass in the "effective" language version -- this would
129
+ // mean modules built in different -swift-version modes would rebuild their
130
+ // dependencies.
131
+ llvm::hash_code H = hash_value (swift::version::getSwiftFullVersion ());
117
132
118
133
// Simplest representation of input "identity" (not content) is just a
119
134
// pathname, and probably all we can get from the VFS in this regard anyways.
120
- H = llvm::hash_combine (H, InPath);
135
+ H = hash_combine (H, InPath);
136
+
137
+ // Include the target CPU. In practice, .swiftinterface files will be in
138
+ // architecture-specific subdirectories and would have target-specific pieces
139
+ // #if'd out. However, it doesn't hurt to include it, and it guards against
140
+ // mistakenly reusing cached modules across targets.
141
+ H = hash_combine (H, SubInvocation.getTargetTriple ());
121
142
122
- // ClangImporterOpts does include the target CPU, which is redundant: we
123
- // already have separate .swiftinterface files per target due to expanding
124
- // preprocessing directives, but further specializing the cache key to that
125
- // target is harmless and will not make any extra cache entries, so allow it.
126
- H = llvm::hash_combine (
127
- H, SubInvocation.getClangImporterOptions ().getPCHHashComponents ());
143
+ // The SDK path is going to affect how this module is imported, so include it.
144
+ H = hash_combine (H, SubInvocation.getSDKPath ());
128
145
129
146
return llvm::APInt (64 , H).toString (36 , /* Signed=*/ false );
130
147
}
@@ -195,6 +212,17 @@ void ParseableInterfaceModuleLoader::configureSubInvocationInputsAndOutputs(
195
212
SubFEOpts.InputsAndOutputs .setMainAndSupplementaryOutputs ({MainOut}, {SOPs});
196
213
}
197
214
215
+ // Checks that a dependency read from the cached module is up to date compared
216
+ // to the interface file it represents.
217
+ static bool dependencyIsUpToDate (clang::vfs::FileSystem &FS, FileDependency In,
218
+ StringRef ModulePath, DiagnosticEngine &Diags,
219
+ SourceLoc DiagLoc) {
220
+ auto Status = getStatusOfDependency (FS, ModulePath, In.Path , Diags, DiagLoc);
221
+ if (!Status) return false ;
222
+ uint64_t mtime = Status->getLastModificationTime ().time_since_epoch ().count ();
223
+ return Status->getSize () == In.Size && mtime == In.ModificationTime ;
224
+ }
225
+
198
226
// Check that the output .swiftmodule file is at least as new as all the
199
227
// dependencies it read when it was built last time.
200
228
static bool
@@ -223,11 +251,7 @@ swiftModuleIsUpToDate(llvm::vfs::FileSystem &FS,
223
251
for (auto In : AllDeps) {
224
252
if (OuterTracker)
225
253
OuterTracker->addDependency (In.Path , /* IsSystem=*/ false );
226
- auto DepBuf = getBufferOfDependency (FS, OutPath, In.Path , Diags,
227
- ModuleID.second );
228
- if (!DepBuf ||
229
- DepBuf->getBufferSize () != In.Size ||
230
- xxHash64 (DepBuf->getBuffer ()) != In.Hash ) {
254
+ if (!dependencyIsUpToDate (FS, In, OutPath, Diags, ModuleID.second )) {
231
255
LLVM_DEBUG (llvm::dbgs () << " Dep " << In.Path
232
256
<< " is directly out of date\n " );
233
257
return false ;
@@ -263,13 +287,15 @@ collectDepsForSerialization(llvm::vfs::FileSystem &FS,
263
287
if (AllDepNames.insert (DepName).second && OuterTracker) {
264
288
OuterTracker->addDependency (DepName, /* IsSystem=*/ false );
265
289
}
290
+ auto Status = getStatusOfDependency (FS, InPath, DepName, Diags, DiagLoc);
291
+ if (!Status)
292
+ return true ;
266
293
auto DepBuf = getBufferOfDependency (FS, InPath, DepName, Diags, DiagLoc);
267
- if (!DepBuf) {
294
+ if (!DepBuf)
268
295
return true ;
269
- }
270
- uint64_t Size = DepBuf->getBufferSize ();
271
- uint64_t Hash = xxHash64 (DepBuf->getBuffer ());
272
- Deps.push_back (FileDependency{Size, Hash, DepName});
296
+ uint64_t mtime =
297
+ Status->getLastModificationTime ().time_since_epoch ().count ();
298
+ Deps.push_back (FileDependency{Status->getSize (), mtime, DepName});
273
299
274
300
if (ModuleCachePath.empty ())
275
301
continue ;
0 commit comments