Skip to content

Commit 33df36d

Browse files
author
Harlan Haskins
committed
[ModuleInterfaces] Rebuild if a dependency is missing
A dependency being removed is not a hard error, because the recovery step is to recompile the interface. That might fail because of the change in dependencies, but that is a more actionable error. Fixes rdar://51959698
1 parent 815ae1f commit 33df36d

File tree

2 files changed

+57
-32
lines changed

2 files changed

+57
-32
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,6 @@ ERROR(unsupported_version_of_module_interface,none,
281281
(StringRef, llvm::VersionTuple))
282282
ERROR(error_extracting_flags_from_module_interface,none,
283283
"error extracting flags from module interface", ())
284-
ERROR(missing_dependency_of_module_interface,none,
285-
"missing dependency '%0' of module interface '%1': %2",
286-
(StringRef, StringRef, StringRef))
287284
REMARK(rebuilding_module_from_interface,none,
288285
"rebuilding module '%0' from interface '%1'", (StringRef, StringRef))
289286
NOTE(out_of_date_module_here,none,
@@ -292,6 +289,9 @@ NOTE(out_of_date_module_here,none,
292289
NOTE(module_interface_dependency_out_of_date,none,
293290
"dependency is out of date: '%0'",
294291
(StringRef))
292+
NOTE(module_interface_dependency_missing,none,
293+
"dependency is missing: '%0'",
294+
(StringRef))
295295
NOTE(compiled_module_invalid,none,
296296
"unable to load compiled module '%0'",
297297
(StringRef))

lib/Frontend/ParseableInterfaceModuleLoader.cpp

Lines changed: 54 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -222,27 +222,19 @@ static bool serializedASTLooksValid(const llvm::MemoryBuffer &buf) {
222222
}
223223

224224
static std::unique_ptr<llvm::MemoryBuffer> getBufferOfDependency(
225-
llvm::vfs::FileSystem &fs, StringRef depPath, StringRef interfacePath,
226-
DiagnosticEngine &diags, SourceLoc diagnosticLoc) {
225+
llvm::vfs::FileSystem &fs, StringRef depPath) {
227226
auto depBuf = fs.getBufferForFile(depPath, /*FileSize=*/-1,
228227
/*RequiresNullTerminator=*/false);
229228
if (!depBuf) {
230-
diags.diagnose(diagnosticLoc,
231-
diag::missing_dependency_of_module_interface,
232-
depPath, interfacePath, depBuf.getError().message());
233229
return nullptr;
234230
}
235231
return std::move(depBuf.get());
236232
}
237233

238234
static Optional<llvm::vfs::Status> getStatusOfDependency(
239-
llvm::vfs::FileSystem &fs, StringRef depPath, StringRef interfacePath,
240-
DiagnosticEngine &diags, SourceLoc diagnosticLoc) {
235+
llvm::vfs::FileSystem &fs, StringRef depPath) {
241236
auto status = fs.status(depPath);
242237
if (!status) {
243-
diags.diagnose(diagnosticLoc,
244-
diag::missing_dependency_of_module_interface,
245-
depPath, interfacePath, status.getError().message());
246238
return None;
247239
}
248240
return status.get();
@@ -432,8 +424,7 @@ class swift::ParseableInterfaceBuilder {
432424
if (DepName.startswith(ResourcePath))
433425
continue;
434426

435-
auto Status = getStatusOfDependency(fs, DepName, interfacePath,
436-
diags, diagnosticLoc);
427+
auto Status = getStatusOfDependency(fs, DepName);
437428
if (!Status)
438429
return true;
439430

@@ -443,8 +434,7 @@ class swift::ParseableInterfaceBuilder {
443434
std::unique_ptr<llvm::MemoryBuffer> DepBuf = nullptr;
444435
auto getDepBuf = [&]() -> llvm::MemoryBuffer * {
445436
if (DepBuf) return DepBuf.get();
446-
if (auto Buf = getBufferOfDependency(fs, DepName, interfacePath,
447-
diags, diagnosticLoc)) {
437+
if (auto Buf = getBufferOfDependency(fs, DepName)) {
448438
DepBuf = std::move(Buf);
449439
return DepBuf.get();
450440
}
@@ -644,14 +634,15 @@ struct ModuleRebuildInfo {
644634
Optional<serialization::Status> serializationStatus;
645635
ModuleKind kind;
646636
SmallVector<std::string, 10> outOfDateDependencies;
637+
SmallVector<std::string, 10> missingDependencies;
647638
};
648639
SmallVector<OutOfDateModule, 3> outOfDateModules;
649640

650641
OutOfDateModule &getOrInsertOutOfDateModule(StringRef path) {
651642
for (auto &mod : outOfDateModules) {
652643
if (mod.path == path) return mod;
653644
}
654-
outOfDateModules.push_back({path, None, ModuleKind::Normal, {}});
645+
outOfDateModules.push_back({path, None, ModuleKind::Normal, {}, {}});
655646
return outOfDateModules.back();
656647
}
657648

@@ -674,6 +665,13 @@ struct ModuleRebuildInfo {
674665
.outOfDateDependencies.push_back(depPath);
675666
}
676667

668+
/// Registers a missing dependency at \c depPath for the module
669+
/// at \c modulePath.
670+
void addMissingDependency(StringRef modulePath, StringRef depPath) {
671+
getOrInsertOutOfDateModule(modulePath)
672+
.missingDependencies.push_back(depPath);
673+
}
674+
677675
const char *invalidModuleReason(serialization::Status status) {
678676
using namespace serialization;
679677
switch (status) {
@@ -710,6 +708,11 @@ struct ModuleRebuildInfo {
710708
dep);
711709
}
712710

711+
// Diagnose any missing dependencies in this module.
712+
for (auto &dep : mod.missingDependencies) {
713+
ctx.Diags.diagnose(loc, diag::module_interface_dependency_missing, dep);
714+
}
715+
713716
// If there was a compiled module that wasn't able to be read, diagnose
714717
// the reason we couldn't read it.
715718
if (auto status = mod.serializationStatus) {
@@ -823,31 +826,44 @@ class ParseableInterfaceModuleLoaderImpl {
823826
return StringRef(scratch.data(), scratch.size());
824827
}
825828

829+
enum class DependencyStatus {
830+
UpToDate,
831+
OutOfDate,
832+
Missing
833+
};
834+
826835
// Checks that a dependency read from the cached module is up to date compared
827836
// to the interface file it represents.
828-
bool dependencyIsUpToDate(const FileDependency &dep, StringRef fullPath) {
829-
auto status = getStatusOfDependency(fs, fullPath, interfacePath,
830-
diags, diagnosticLoc);
831-
if (!status) return false;
837+
DependencyStatus checkDependency(StringRef modulePath,
838+
const FileDependency &dep,
839+
StringRef fullPath) {
840+
auto status = getStatusOfDependency(fs, fullPath);
841+
if (!status)
842+
return DependencyStatus::Missing;
832843

833844
// If the sizes differ, then we know the file has changed.
834-
if (status->getSize() != dep.getSize()) return false;
845+
if (status->getSize() != dep.getSize())
846+
return DependencyStatus::OutOfDate;
835847

836848
// Otherwise, if this dependency is verified by modification time, check
837849
// it vs. the modification time of the file.
838850
if (dep.isModificationTimeBased()) {
839851
uint64_t mtime =
840852
status->getLastModificationTime().time_since_epoch().count();
841-
return mtime == dep.getModificationTime();
853+
return mtime == dep.getModificationTime() ?
854+
DependencyStatus::UpToDate :
855+
DependencyStatus::OutOfDate;
842856
}
843857

844858
// Slow path: if the dependency is verified by content hash, check it vs.
845859
// the hash of the file.
846-
auto buf = getBufferOfDependency(fs, fullPath, interfacePath,
847-
diags, diagnosticLoc);
848-
if (!buf) return false;
860+
auto buf = getBufferOfDependency(fs, fullPath);
861+
if (!buf)
862+
return DependencyStatus::Missing;
849863

850-
return xxHash64(buf->getBuffer()) == dep.getContentHash();
864+
return xxHash64(buf->getBuffer()) == dep.getContentHash() ?
865+
DependencyStatus::UpToDate :
866+
DependencyStatus::OutOfDate;
851867
}
852868

853869
// Check if all the provided file dependencies are up-to-date compared to
@@ -857,13 +873,19 @@ class ParseableInterfaceModuleLoaderImpl {
857873
SmallString<128> SDKRelativeBuffer;
858874
for (auto &in : deps) {
859875
StringRef fullPath = getFullDependencyPath(in, SDKRelativeBuffer);
860-
if (!dependencyIsUpToDate(in, fullPath)) {
861-
LLVM_DEBUG(llvm::dbgs() << "Dep " << fullPath
862-
<< " is directly out of date\n");
876+
switch (checkDependency(modulePath, in, fullPath)) {
877+
case DependencyStatus::UpToDate:
878+
LLVM_DEBUG(llvm::dbgs() << "Dep " << fullPath << " is up to date\n");
879+
break;
880+
case DependencyStatus::OutOfDate:
881+
LLVM_DEBUG(llvm::dbgs() << "Dep " << fullPath << " is out of date\n");
863882
rebuildInfo.addOutOfDateDependency(modulePath, fullPath);
864883
return false;
884+
case DependencyStatus::Missing:
885+
LLVM_DEBUG(llvm::dbgs() << "Dep " << fullPath << " is missing\n");
886+
rebuildInfo.addMissingDependency(modulePath, fullPath);
887+
return false;
865888
}
866-
LLVM_DEBUG(llvm::dbgs() << "Dep " << fullPath << " is up to date\n");
867889
}
868890
return true;
869891
}
@@ -1148,6 +1170,9 @@ class ParseableInterfaceModuleLoaderImpl {
11481170
ModuleRebuildInfo::ModuleKind::Normal);
11491171
}
11501172
} else if (adjacentModuleBuffer.getError() != notFoundError) {
1173+
LLVM_DEBUG(llvm::dbgs() << "Found unreadable module at "
1174+
<< modulePath
1175+
<< "; deferring to serialized module loader\n");
11511176
return std::make_error_code(std::errc::not_supported);
11521177
}
11531178

0 commit comments

Comments
 (0)