Skip to content

Commit ea2c501

Browse files
authored
Merge pull request #78672 from artemcm/DepScanInvalidRejectedBinaryModulesWarn
[Dependency Scanning] Emit a warning when failing to load a binary module of a non-resilient dependency
2 parents ab8b1cd + 550538f commit ea2c501

File tree

6 files changed

+89
-51
lines changed

6 files changed

+89
-51
lines changed

include/swift/AST/DiagnosticsSema.def

+8-2
Original file line numberDiff line numberDiff line change
@@ -1232,8 +1232,14 @@ REMARK(module_api_import_aliases,none,
12321232
"%select{, which reexports definition from %2|}3",
12331233
(const Decl *, ModuleDecl *, ModuleDecl *, bool))
12341234

1235-
REMARK(skip_module_invalid,none,"skip invalid swiftmodule: %0", (StringRef))
1236-
WARNING(skip_module_not_testable,none,"ignore swiftmodule built without '-enable-testing': %0", (StringRef))
1235+
REMARK(dependency_scan_skip_module_invalid,none,
1236+
"module file '%0' skipped by the dependency scan because it is "
1237+
"incompatible with this Swift compiler: %1", (StringRef, StringRef))
1238+
WARNING(skip_module_not_testable,none,
1239+
"ignore swiftmodule built without '-enable-testing': %0", (StringRef))
1240+
WARNING(dependency_scan_module_incompatible, none,
1241+
"module file '%0' is incompatible with this Swift compiler: %1",
1242+
(StringRef, StringRef))
12371243

12381244
REMARK(macro_loaded,none,
12391245
"loaded macro implementation module %0 from "

include/swift/Serialization/SerializedModuleLoader.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "swift/AST/ModuleDependencies.h"
1919
#include "swift/AST/ModuleLoader.h"
2020
#include "swift/AST/SearchPathOptions.h"
21+
#include "swift/Serialization/Validation.h"
2122
#include "llvm/Support/MemoryBuffer.h"
2223
#include "llvm/Support/PrefixMapper.h"
2324
#include "llvm/TargetParser/Triple.h"
@@ -165,7 +166,8 @@ class SerializedModuleLoaderBase : public ModuleLoader {
165166

166167
/// Scan the given serialized module file to determine dependencies.
167168
llvm::ErrorOr<ModuleDependencyInfo>
168-
scanModuleFile(Twine modulePath, bool isFramework, bool isTestableImport);
169+
scanModuleFile(Twine modulePath, bool isFramework,
170+
bool isTestableImport, bool isCandidateForTextualModule);
169171

170172
struct BinaryModuleImports {
171173
llvm::StringSet<> moduleImports;
@@ -267,6 +269,10 @@ class SerializedModuleLoaderBase : public ModuleLoader {
267269
InterfaceSubContextDelegate &delegate,
268270
llvm::PrefixMapper *mapper,
269271
bool isTestableImport) override;
272+
273+
/// A textual reason why the compiler rejected a binary module load
274+
/// attempt with a given status, to be used for diagnostic output.
275+
static std::optional<std::string> invalidModuleReason(serialization::Status status);
270276
};
271277

272278
/// Imports serialized Swift modules into an ASTContext.

lib/Frontend/ModuleInterfaceLoader.cpp

+2-41
Original file line numberDiff line numberDiff line change
@@ -325,45 +325,6 @@ struct ModuleRebuildInfo {
325325
return false;
326326
}
327327

328-
const char *invalidModuleReason(serialization::Status status) {
329-
using namespace serialization;
330-
switch (status) {
331-
case Status::FormatTooOld:
332-
return "compiled with an older version of the compiler";
333-
case Status::FormatTooNew:
334-
return "compiled with a newer version of the compiler";
335-
case Status::RevisionIncompatible:
336-
return "compiled with a different version of the compiler";
337-
case Status::ChannelIncompatible:
338-
return "compiled for a different distribution channel";
339-
case Status::NotInOSSA:
340-
return "module was not built with OSSA";
341-
case Status::MissingDependency:
342-
return "missing dependency";
343-
case Status::MissingUnderlyingModule:
344-
return "missing underlying module";
345-
case Status::CircularDependency:
346-
return "circular dependency";
347-
case Status::FailedToLoadBridgingHeader:
348-
return "failed to load bridging header";
349-
case Status::Malformed:
350-
return "malformed";
351-
case Status::MalformedDocumentation:
352-
return "malformed documentation";
353-
case Status::NameMismatch:
354-
return "name mismatch";
355-
case Status::TargetIncompatible:
356-
return "compiled for a different target platform";
357-
case Status::TargetTooNew:
358-
return "target platform newer than current platform";
359-
case Status::SDKMismatch:
360-
return "SDK does not match";
361-
case Status::Valid:
362-
return nullptr;
363-
}
364-
llvm_unreachable("bad status");
365-
}
366-
367328
/// Emits a diagnostic for all out-of-date compiled or forwarding modules
368329
/// encountered while trying to load a module.
369330
template<typename... DiagArgs>
@@ -406,9 +367,9 @@ struct ModuleRebuildInfo {
406367
// If there was a compiled module that wasn't able to be read, diagnose
407368
// the reason we couldn't read it.
408369
if (auto status = mod.serializationStatus) {
409-
if (auto reason = invalidModuleReason(*status)) {
370+
if (auto reason = SerializedModuleLoaderBase::invalidModuleReason(*status)) {
410371
diags.diagnose(loc, diag::compiled_module_invalid_reason,
411-
mod.path, reason);
372+
mod.path, reason.value());
412373
} else {
413374
diags.diagnose(loc, diag::compiled_module_invalid, mod.path);
414375
}

lib/Serialization/ScanningLoaders.cpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
6161
if (fs.exists(ModPath)) {
6262
// The module file will be loaded directly.
6363
auto dependencies =
64-
scanModuleFile(ModPath, IsFramework, isTestableDependencyLookup);
64+
scanModuleFile(ModPath, IsFramework,
65+
isTestableDependencyLookup,
66+
/* isCandidateForTextualModule */ false);
6567
if (dependencies) {
6668
this->dependencies = std::move(dependencies.get());
6769
return std::error_code();
@@ -164,8 +166,9 @@ SwiftModuleScanner::scanInterfaceFile(Twine moduleInterfacePath,
164166
Ctx.SearchPathOpts.ScannerModuleValidation) {
165167
assert(compiledCandidates.size() == 1 &&
166168
"Should only have 1 candidate module");
167-
auto BinaryDep = scanModuleFile(compiledCandidates[0], isFramework,
168-
isTestableImport);
169+
auto BinaryDep = scanModuleFile(compiledCandidates[0],
170+
isFramework, isTestableImport,
171+
/* isCandidateForTextualModule */ true);
169172
if (BinaryDep) {
170173
Result = *BinaryDep;
171174
return std::error_code();

lib/Serialization/SerializedModuleLoader.cpp

+53-4
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,45 @@ SerializedModuleLoaderBase::getModuleName(ASTContext &Ctx, StringRef modulePath,
304304
return ModuleFile::getModuleName(Ctx, modulePath, Name);
305305
}
306306

307+
std::optional<std::string> SerializedModuleLoaderBase::invalidModuleReason(serialization::Status status) {
308+
using namespace serialization;
309+
switch (status) {
310+
case Status::FormatTooOld:
311+
return "compiled with an older version of the compiler";
312+
case Status::FormatTooNew:
313+
return "compiled with a newer version of the compiler";
314+
case Status::RevisionIncompatible:
315+
return "compiled with a different version of the compiler";
316+
case Status::ChannelIncompatible:
317+
return "compiled for a different distribution channel";
318+
case Status::NotInOSSA:
319+
return "module was not built with OSSA";
320+
case Status::MissingDependency:
321+
return "missing dependency";
322+
case Status::MissingUnderlyingModule:
323+
return "missing underlying module";
324+
case Status::CircularDependency:
325+
return "circular dependency";
326+
case Status::FailedToLoadBridgingHeader:
327+
return "failed to load bridging header";
328+
case Status::Malformed:
329+
return "malformed";
330+
case Status::MalformedDocumentation:
331+
return "malformed documentation";
332+
case Status::NameMismatch:
333+
return "name mismatch";
334+
case Status::TargetIncompatible:
335+
return "compiled for a different target platform";
336+
case Status::TargetTooNew:
337+
return "target platform newer than current platform";
338+
case Status::SDKMismatch:
339+
return "SDK does not match";
340+
case Status::Valid:
341+
return std::nullopt;
342+
}
343+
llvm_unreachable("bad status");
344+
}
345+
307346
llvm::ErrorOr<llvm::StringSet<>>
308347
SerializedModuleLoaderBase::getMatchingPackageOnlyImportsOfModule(
309348
Twine modulePath, bool isFramework, bool isRequiredOSSAModules,
@@ -504,7 +543,8 @@ SerializedModuleLoaderBase::resolveMacroPlugin(const ExternalMacroPlugin &macro,
504543

505544
llvm::ErrorOr<ModuleDependencyInfo>
506545
SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework,
507-
bool isTestableImport) {
546+
bool isTestableImport,
547+
bool isCandidateForTextualModule) {
508548
const std::string moduleDocPath;
509549
const std::string sourceInfoPath;
510550

@@ -521,10 +561,19 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework,
521561

522562
if (Ctx.SearchPathOpts.ScannerModuleValidation) {
523563
// If failed to load, just ignore and return do not found.
524-
if (loadInfo.status != serialization::Status::Valid) {
564+
if (auto loadFailureReason = invalidModuleReason(loadInfo.status)) {
565+
// If no textual interface was found, then for this dependency
566+
// scanning query this was *the* module discovered, which means
567+
// it would be helpful to let the user know why the scanner
568+
// was not able to use it because the scan will ultimately fail to
569+
// resolve this dependency due to this incompatibility.
570+
if (!isCandidateForTextualModule)
571+
Ctx.Diags.diagnose(SourceLoc(), diag::dependency_scan_module_incompatible,
572+
modulePath.str(), loadFailureReason.value());
573+
525574
if (Ctx.LangOpts.EnableModuleLoadingRemarks)
526-
Ctx.Diags.diagnose(SourceLoc(), diag::skip_module_invalid,
527-
modulePath.str());
575+
Ctx.Diags.diagnose(SourceLoc(), diag::dependency_scan_skip_module_invalid,
576+
modulePath.str(), loadFailureReason.value());
528577
return std::make_error_code(std::errc::no_such_file_or_directory);
529578
}
530579

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: mkdir -p %t/moduleInputs
4+
5+
// RUN: echo "Not Really a module" >> %t/moduleInputs/FooBar.swiftmodule
6+
7+
// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %t/moduleInputs -diagnostic-style llvm -scanner-module-validation 2>&1 | %FileCheck %s
8+
9+
import FooBar
10+
11+
// CHECK: warning: module file '{{.*}}{{/|\\}}moduleInputs{{/|\\}}FooBar.swiftmodule' is incompatible with this Swift compiler: malformed
12+
// CHECK: error: Unable to find module dependency: 'FooBar'
13+

0 commit comments

Comments
 (0)