Skip to content

[Dependency Scanning] Discard and diagnose discovered binary modules built for an incompatible target #82552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -1290,15 +1290,6 @@ REMARK(module_api_import_aliases,none,
"%select{, which reexports definition from %2|}3",
(const Decl *, ModuleDecl *, ModuleDecl *, bool))

REMARK(dependency_scan_skip_module_invalid,none,
"module file '%0' skipped by the dependency scan because it is "
"incompatible with this Swift compiler: %1", (StringRef, StringRef))
WARNING(skip_module_not_testable,none,
"ignore swiftmodule built without '-enable-testing': %0", (StringRef))
WARNING(dependency_scan_module_incompatible, none,
"module file '%0' is incompatible with this Swift compiler: %1",
(StringRef, StringRef))

REMARK(macro_loaded,none,
"loaded macro implementation module %0 from "
"%select{shared library '%2'|executable '%2'|"
Expand Down Expand Up @@ -2377,9 +2368,11 @@ ERROR(alignment_not_power_of_two,none,
"alignment value must be a power of two", ())

// Dependency Scanning
ERROR(dependency_scan_module_not_found, none, "Unable to find module dependency: '%0'", (StringRef))
ERROR(dependency_scan_module_not_found, none, "unable to resolve module dependency: '%0'", (StringRef))

GROUPED_ERROR(dependency_scan_module_not_found_on_specified_search_paths, MissingModuleOnKnownPaths, none,
"Compilation search paths unable to resolve module dependency: '%0'", (StringRef))
"compilation search paths unable to resolve module dependency: '%0'", (StringRef))

NOTE(unresolved_import_location,none,
"also imported here", ())
NOTE(dependency_as_imported_by_main_module,none,
Expand All @@ -2388,10 +2381,21 @@ NOTE(dependency_as_imported_by, none,
"a dependency of %select{Swift|Clang}2 module '%0': '%1'", (StringRef, StringRef, bool))
NOTE(inherited_search_path_resolves_module,none,
"'%0' can be found using a search path that was specified when building module '%1' ('%2'). "
"This search path was not explicitly specified on the current compilation.", (StringRef, StringRef, StringRef))
"This search path was not explicitly specified on the current compilation", (StringRef, StringRef, StringRef))

ERROR(dependency_scan_compatible_swift_module_not_found, none,
"unable to resolve Swift module dependency to a compatible module: '%0'",
(StringRef))
NOTE(dependency_scan_incompatible_module_found,none,
"found incompatible module '%0': %1", (StringRef, StringRef))

WARNING(dependency_scan_module_incompatible, none,
"module file '%0' is incompatible with this Swift compiler: %1",
(StringRef, StringRef))

ERROR(clang_dependency_scan_error, none, "clang dependency scanning failure: %0", (StringRef))

ERROR(clang_dependency_scan_error, none, "Clang dependency scanner failure: %0", (StringRef))
ERROR(clang_header_dependency_scan_error, none, "Bridging header dependency scan failure: %0", (StringRef))
ERROR(clang_header_dependency_scan_error, none, "bridging header dependency scanning failure: %0", (StringRef))

// Enum annotations
ERROR(indirect_case_without_payload,none,
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/ModuleDependencies.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ struct ScannerImportStatementInfo {
uint32_t columnNumber;
};

ScannerImportStatementInfo(std::string importIdentifier)
: importIdentifier(importIdentifier), importLocations(),
isExported(false), accessLevel(AccessLevel::Public) {}

ScannerImportStatementInfo(std::string importIdentifier, bool isExported,
AccessLevel accessLevel)
: importIdentifier(importIdentifier), importLocations(),
Expand Down
54 changes: 44 additions & 10 deletions include/swift/DependencyScan/ModuleDependencyScanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class ModuleDependencyScanningWorker {
&alreadySeenModules);

/// Retrieve the module dependencies for the Swift module with the given name.
ModuleDependencyVector scanFilesystemForSwiftModuleDependency(
SwiftModuleScannerQueryResult scanFilesystemForSwiftModuleDependency(
Identifier moduleName, bool isTestableImport = false);

/// Query dependency information for header dependencies
Expand Down Expand Up @@ -112,6 +112,46 @@ class ModuleDependencyScanningWorker {
friend class ModuleDependencyScanner;
};

class ModuleDependencyIssueReporter {
private:
ModuleDependencyIssueReporter(DiagnosticEngine &Diagnostics)
: Diagnostics(Diagnostics) {}

/// Diagnose scanner failure and attempt to reconstruct the dependency
/// path from the main module to the missing dependency
void diagnoseModuleNotFoundFailure(
const ScannerImportStatementInfo &moduleImport,
const ModuleDependenciesCache &cache,
std::optional<ModuleDependencyID> dependencyOf,
std::optional<std::pair<ModuleDependencyID, std::string>>
resolvingSerializedSearchPath,
std::optional<
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>>
foundIncompatibleCandidates = std::nullopt);

/// Upon query failure, if incompatible binary module
/// candidates were found, emit a failure diagnostic
void diagnoseFailureOnOnlyIncompatibleCandidates(
const ScannerImportStatementInfo &moduleImport,
const std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
&candidates,
const ModuleDependenciesCache &cache,
std::optional<ModuleDependencyID> dependencyOf);

/// Emit warnings for each discovered binary Swift module
/// which was incompatible with the current compilation
/// when querying \c moduleName
void warnOnIncompatibleCandidates(
StringRef moduleName,
const std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate>
&candidates);

DiagnosticEngine &Diagnostics;
std::unordered_set<std::string> ReportedMissing;
// Restrict access to the parent scanner class.
friend class ModuleDependencyScanner;
};

class ModuleDependencyScanner {
public:
ModuleDependencyScanner(SwiftDependencyScanningService &ScanningService,
Expand Down Expand Up @@ -182,7 +222,7 @@ class ModuleDependencyScanner {
StringRef mainModuleName, ModuleDependenciesCache &cache,
llvm::function_ref<void(ModuleDependencyID)> action);

/// Performance BridgingHeader Chaining.
/// Perform Bridging Header Chaining.
llvm::Error
performBridgingHeaderChaining(const ModuleDependencyID &rootModuleID,
ModuleDependenciesCache &cache,
Expand All @@ -197,12 +237,6 @@ class ModuleDependencyScanner {
/// for a given module name.
Identifier getModuleImportIdentifier(StringRef moduleName);

/// Diagnose scanner failure and attempt to reconstruct the dependency
/// path from the main module to the missing dependency.
void diagnoseScannerFailure(const ScannerImportStatementInfo &moduleImport,
const ModuleDependenciesCache &cache,
std::optional<ModuleDependencyID> dependencyOf);

/// Assuming the \c `moduleImport` failed to resolve,
/// iterate over all binary Swift module dependencies with serialized
/// search paths and attempt to diagnose if the failed-to-resolve module
Expand All @@ -211,12 +245,12 @@ class ModuleDependencyScanner {
std::optional<std::pair<ModuleDependencyID, std::string>>
attemptToFindResolvingSerializedSearchPath(
const ScannerImportStatementInfo &moduleImport,
const ModuleDependenciesCache &cache, const SourceLoc &importLoc);
const ModuleDependenciesCache &cache);

private:
const CompilerInvocation &ScanCompilerInvocation;
ASTContext &ScanASTContext;
DiagnosticEngine &Diagnostics;
ModuleDependencyIssueReporter IssueReporter;

/// The available pool of workers for filesystem module search
unsigned NumThreads;
Expand Down
18 changes: 16 additions & 2 deletions include/swift/Serialization/ScanningLoaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@
#include "swift/Serialization/SerializedModuleLoader.h"

namespace swift {

/// Result of looking up a Swift module on the current filesystem
/// search paths.
struct SwiftModuleScannerQueryResult {
struct IncompatibleCandidate {
std::string path;
std::string incompatibilityReason;
};

std::vector<IncompatibleCandidate> incompatibleCandidates;
std::optional<ModuleDependencyInfo> foundDependencyInfo;
};

/// A module "loader" that looks for .swiftinterface and .swiftmodule files
/// for the purpose of determining dependencies, but does not attempt to
/// load the module files.
Expand Down Expand Up @@ -60,7 +73,8 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
std::vector<std::string> swiftModuleClangCC1CommandLineArgs;

public:
std::optional<ModuleDependencyInfo> dependencies;
std::vector<SwiftModuleScannerQueryResult::IncompatibleCandidate> incompatibleCandidates;
std::optional<ModuleDependencyInfo> foundDependencyInfo;

SwiftModuleScanner(ASTContext &ctx, ModuleLoadingMode LoadMode,
InterfaceSubContextDelegate &astDelegate,
Expand All @@ -74,7 +88,7 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase {
swiftModuleClangCC1CommandLineArgs(swiftModuleClangCC1CommandLineArgs) {}

/// Perform a filesystem search for a Swift module with a given name
llvm::SmallVector<std::pair<ModuleDependencyID, ModuleDependencyInfo>, 1>
SwiftModuleScannerQueryResult
lookupSwiftModule(Identifier moduleName, bool isTestableImport);
};
} // namespace swift
Expand Down
1 change: 1 addition & 0 deletions include/swift/Serialization/SerializedModuleLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class SerializedModuleLoaderBase : public ModuleLoader {
bool isFramework,
bool isRequiredOSSAModules,
StringRef SDKName,
const llvm::Triple &target,
StringRef packageName,
llvm::vfs::FileSystem *fileSystem,
PathObfuscator &recoverer);
Expand Down
10 changes: 5 additions & 5 deletions include/swift/Serialization/Validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"

namespace llvm {
class Triple;
}
#include "llvm/TargetParser/Triple.h"

namespace swift {

Expand Down Expand Up @@ -296,6 +293,8 @@ struct SearchPath {
/// compiled with -enable-ossa-modules.
/// \param requiredSDK If not empty, only accept modules built with
/// a compatible SDK. The StringRef represents the canonical SDK name.
/// \param target The target triple of the current compilation for
/// validating that the module we are attempting to load is compatible.
/// \param[out] extendedInfo If present, will be populated with additional
/// compilation options serialized into the AST at build time that may be
/// necessary to load it properly.
Expand All @@ -307,7 +306,8 @@ ValidationInfo validateSerializedAST(
ExtendedValidationInfo *extendedInfo = nullptr,
SmallVectorImpl<SerializationOptions::FileDependency> *dependencies =
nullptr,
SmallVectorImpl<SearchPath> *searchPaths = nullptr);
SmallVectorImpl<SearchPath> *searchPaths = nullptr,
std::optional<llvm::Triple> target = std::nullopt);

/// Emit diagnostics explaining a failure to load a serialized AST.
///
Expand Down
Loading