From c73869e479eba9499089132c1e073a00d3b1b3b9 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 23 Sep 2025 14:45:57 -0700 Subject: [PATCH 1/2] Do not fail the build on only finding incompatible-architecture modules on 'canImport' This change refactors the module loaders to explicitly take a parameter indicating whether or not the loader is handling a 'canImport' query, in order to avoid emitting an error when finding a dependency Swift binary module with only imcompatible architecture variants present. Resolves rdar://161175498 --- .../swift/Frontend/ModuleInterfaceLoader.h | 10 +++--- include/swift/Serialization/ScanningLoaders.h | 2 +- .../Serialization/SerializedModuleLoader.h | 23 ++++++------- lib/Frontend/ModuleInterfaceLoader.cpp | 20 +++++------ lib/Serialization/ScanningLoaders.cpp | 2 +- lib/Serialization/SerializedModuleLoader.cpp | 33 +++++++++---------- .../can_import_in_inactive.swift | 2 +- .../can-import-invalid-arch.swift | 13 ++++++++ unittests/FrontendTool/ModuleLoadingTests.cpp | 2 +- 9 files changed, 56 insertions(+), 51 deletions(-) create mode 100644 test/Serialization/can-import-invalid-arch.swift diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 668c7a82631..50661110b2c 100644 --- a/include/swift/Frontend/ModuleInterfaceLoader.h +++ b/include/swift/Frontend/ModuleInterfaceLoader.h @@ -152,7 +152,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool isCanImportLookup, bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule) override; std::error_code findModuleFilesInDirectory( @@ -162,7 +162,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase { std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, + bool isCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup = false) override; bool canImportModule(ImportPath::Module named, SourceLoc loc, @@ -201,7 +201,7 @@ class ExplicitCASModuleLoader : public SerializedModuleLoaderBase { std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool isCanImportLookup, bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule) override; std::error_code findModuleFilesInDirectory( @@ -211,7 +211,7 @@ class ExplicitCASModuleLoader : public SerializedModuleLoaderBase { std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup = false) override; bool canImportModule(ImportPath::Module named, SourceLoc loc, @@ -561,7 +561,7 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase { std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup = false) override; bool isCached(StringRef DepPath) override; diff --git a/include/swift/Serialization/ScanningLoaders.h b/include/swift/Serialization/ScanningLoaders.h index 1799d7262f8..aca27bf78d3 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -63,7 +63,7 @@ private: std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup) override; bool canImportModule(ImportPath::Module named, SourceLoc loc, diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 6eb1a0d1477..c3f10e4a9b1 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -103,7 +103,7 @@ protected: std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool isCanImportLookup, bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule); /// Attempts to search the provided directory for a loadable serialized @@ -125,8 +125,8 @@ protected: std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, - bool isTestableDependencyLookup = false) = 0; + bool IsCanImportLookup, bool IsFramework, + bool IsTestableDependencyLookup = false) = 0; std::error_code openModuleFile( @@ -154,7 +154,8 @@ protected: virtual bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &BaseName) { + const SerializedModuleBaseName &BaseName, + bool isCanImportLookup) { return false; } @@ -278,13 +279,14 @@ class ImplicitSerializedModuleLoader : public SerializedModuleLoaderBase { std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, - bool isTestableDependencyLookup = false) override; + bool IsCanImportLookup, bool IsFramework, + bool IsTestableDependencyLookup = false) override; bool maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &BaseName) override; + const SerializedModuleBaseName &BaseName, + bool isCanImportLookup) override; public: virtual ~ImplicitSerializedModuleLoader(); @@ -336,14 +338,9 @@ class MemoryBufferSerializedModuleLoader : public SerializedModuleLoaderBase { std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool SkipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup = false) override; - bool maybeDiagnoseTargetMismatch( - SourceLoc sourceLocation, - StringRef moduleName, - const SerializedModuleBaseName &BaseName) override; - bool BypassResilience; public: virtual ~MemoryBufferSerializedModuleLoader(); diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 2dc62e5d085..fade5b2bf48 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1336,8 +1336,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, - bool isTestableImport) { + bool IsCanImportLookup, bool IsFramework, + bool IsTestableImport) { // If running in OnlySerialized mode, ModuleInterfaceLoader // should not have been constructed at all. @@ -1361,11 +1361,9 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory( if (ModuleInterfaceSourcePath) ModuleInterfaceSourcePath->assign(InPath->begin(), InPath->end()); - // If we've been told to skip building interfaces, we are done here and do - // not need to have the module actually built. For example, if we are - // currently answering a `canImport` query, it is enough to have found - // the interface. - if (skipBuildingInterface) { + // If we are currently answering a `canImport` query, it is enough to have + // found the interface. + if (IsCanImportLookup) { if (ModuleInterfacePath) ModuleInterfacePath->assign(InPath->begin(), InPath->end()); return std::error_code(); @@ -2317,7 +2315,7 @@ bool ExplicitSwiftModuleLoader::findModule( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool IsCanImportLookup, bool isTestableDependencyLookup, bool &IsFramework, bool &IsSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). @@ -2396,7 +2394,7 @@ std::error_code ExplicitSwiftModuleLoader::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup) { llvm_unreachable("Not supported in the Explicit Swift Module Loader."); return std::make_error_code(std::errc::not_supported); @@ -2674,7 +2672,7 @@ bool ExplicitCASModuleLoader::findModule( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool IsCanImportLookup, bool IsTestableDependencyLookup, bool &IsFramework, bool &IsSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). @@ -2763,7 +2761,7 @@ std::error_code ExplicitCASModuleLoader::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup) { llvm_unreachable("Not supported in the Explicit Swift Module Loader."); return std::make_error_code(std::errc::not_supported); diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index 070a915bb33..cc64d18180a 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -46,7 +46,7 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, + bool IsCanImportLookup, bool IsFramework, bool isTestableDependencyLookup) { using namespace llvm::sys; diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 328345b9ffa..e3ce288fbd5 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -550,7 +550,7 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, bool IsTestableDependencyLookup) { + bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup) { if (LoadMode == ModuleLoadingMode::OnlyInterface || Ctx.IgnoreAdjacentModules) return std::make_error_code(std::errc::not_supported); @@ -579,7 +579,8 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( bool ImplicitSerializedModuleLoader::maybeDiagnoseTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &absoluteBaseName) { + const SerializedModuleBaseName &absoluteBaseName, + bool isCanImportLookup) { llvm::vfs::FileSystem &fs = *Ctx.SourceMgr.getFileSystem(); // Get the last component of the base name, which is the target-specific one. @@ -614,9 +615,11 @@ bool ImplicitSerializedModuleLoader::maybeDiagnoseTargetMismatch( return false; } - Ctx.Diags.diagnose(sourceLocation, diag::sema_no_import_target, moduleName, - target, foundArchs, dir); - return true; + Ctx.Diags + .diagnose(sourceLocation, diag::sema_no_import_target, moduleName, target, + foundArchs, dir) + .limitBehaviorIf(isCanImportLookup, DiagnosticBehavior::Warning); + return !isCanImportLookup; } SerializedModuleBaseName::SerializedModuleBaseName( @@ -720,7 +723,7 @@ bool SerializedModuleLoaderBase::findModule( std::unique_ptr *moduleBuffer, std::unique_ptr *moduleDocBuffer, std::unique_ptr *moduleSourceInfoBuffer, - bool skipBuildingInterface, bool isTestableDependencyLookup, + bool isCanImportLookup, bool isTestableDependencyLookup, bool &isFramework, bool &isSystemModule) { // Find a module with an actual, physical name on disk, in case // -module-alias is used (otherwise same). @@ -766,7 +769,7 @@ bool SerializedModuleLoaderBase::findModule( auto result = findModuleFilesInDirectory( moduleID, absoluteBaseName, moduleInterfacePath, moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer, - moduleSourceInfoBuffer, skipBuildingInterface, IsFramework, + moduleSourceInfoBuffer, isCanImportLookup, IsFramework, isTestableDependencyLookup); if (!result) return SearchResult::Found; @@ -780,7 +783,7 @@ bool SerializedModuleLoaderBase::findModule( // 'std::errc::no_such_file_or_directory'. if (firstAbsoluteBaseName && maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName, - *firstAbsoluteBaseName)) + *firstAbsoluteBaseName, isCanImportLookup)) return SearchResult::Error; return SearchResult::NotFound; @@ -838,7 +841,7 @@ bool SerializedModuleLoaderBase::findModule( auto result = findModuleFilesInDirectory( moduleID, absoluteBaseName, moduleInterfacePath, moduleInterfaceSourcePath, moduleBuffer, moduleDocBuffer, - moduleSourceInfoBuffer, skipBuildingInterface, isFramework, + moduleSourceInfoBuffer, isCanImportLookup, isFramework, isTestableDependencyLookup); if (!result) return true; @@ -1512,7 +1515,7 @@ bool SerializedModuleLoaderBase::canImportModule( mID, /*moduleInterfacePath=*/nullptr, &moduleInterfaceSourcePath, &moduleInputBuffer, /*moduleDocBuffer=*/nullptr, /*moduleSourceInfoBuffer=*/nullptr, - /*skipBuildingInterface=*/true, isTestableDependencyLookup, + /*isCanImportLookup=*/true, isTestableDependencyLookup, isFramework, isSystemModule); // If we cannot find the module, don't continue. if (!found) @@ -1607,7 +1610,7 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, if (!findModule(moduleID, &moduleInterfacePath, &moduleInterfaceSourcePath, &moduleInputBuffer, &moduleDocInputBuffer, &moduleSourceInfoInputBuffer, - /*skipBuildingInterface=*/false, + /*isCanImportLookup=*/false, /*isTestableDependencyLookup=*/false, isFramework, isSystemModule)) { @@ -1747,7 +1750,7 @@ std::error_code MemoryBufferSerializedModuleLoader::findModuleFilesInDirectory( std::unique_ptr *ModuleBuffer, std::unique_ptr *ModuleDocBuffer, std::unique_ptr *ModuleSourceInfoBuffer, - bool skipBuildingInterface, bool IsFramework, + bool isCanImportLookup, bool IsFramework, bool isTestableDependencyLookup) { // This is a soft error instead of an llvm_unreachable because this API is // primarily used by LLDB which makes it more likely that unwitting changes to @@ -1756,12 +1759,6 @@ std::error_code MemoryBufferSerializedModuleLoader::findModuleFilesInDirectory( return std::make_error_code(std::errc::not_supported); } -bool MemoryBufferSerializedModuleLoader::maybeDiagnoseTargetMismatch( - SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &absoluteBaseName) { - return false; -} - void SerializedModuleLoaderBase::verifyAllModules() { #ifndef NDEBUG for (const LoadedModulePair &loaded : LoadedModuleFiles) diff --git a/test/Parse/ConditionalCompilation/can_import_in_inactive.swift b/test/Parse/ConditionalCompilation/can_import_in_inactive.swift index 218a5e7912b..4edc561fce2 100644 --- a/test/Parse/ConditionalCompilation/can_import_in_inactive.swift +++ b/test/Parse/ConditionalCompilation/can_import_in_inactive.swift @@ -21,7 +21,7 @@ #endif #if canImport(SomeModule) -// CHECK: :[[@LINE-1]]:{{.*}}: error: could not find module 'SomeModule' for target '{{.*}}'; found: i386 +// CHECK: :[[@LINE-1]]:{{.*}}: warning: could not find module 'SomeModule' for target '{{.*}}'; found: i386 #endif import SomeModule diff --git a/test/Serialization/can-import-invalid-arch.swift b/test/Serialization/can-import-invalid-arch.swift new file mode 100644 index 00000000000..2d4e7bf45ba --- /dev/null +++ b/test/Serialization/can-import-invalid-arch.swift @@ -0,0 +1,13 @@ +// RUN: %empty-directory(%t) +// RUN: mkdir %t/Foo.swiftmodule +// RUN: touch %t/Foo.swiftmodule/i387.swiftmodule +// RUN: touch %t/Foo.swiftmodule/ppc65.swiftmodule +// RUN: touch %t/Foo.swiftmodule/i387.swiftdoc +// RUN: touch %t/Foo.swiftmodule/ppc65.swiftdoc +// RUN: %target-swift-frontend %s -typecheck -I %t 2>&1 | %FileCheck %s -DTARGET_ARCHITECTURE=%module-target-triple + +// CHECK: {{.*}} warning: could not find module 'Foo' for target '[[TARGET_ARCHITECTURE]]'; found: {{ppc65, i387|i387, ppc65}}, at: {{.*}}Foo.swiftmodule + +#if canImport(Foo) + import Foo +#endif diff --git a/unittests/FrontendTool/ModuleLoadingTests.cpp b/unittests/FrontendTool/ModuleLoadingTests.cpp index 8dd785f3dbe..d71c151eb23 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -131,7 +131,7 @@ protected: SerializedModuleBaseName(tempDir, SerializedModuleBaseName("Library")), /*ModuleInterfacePath=*/nullptr, /*ModuleInterfaceSourcePath=*/nullptr, &moduleBuffer, &moduleDocBuffer, &moduleSourceInfoBuffer, - /*skipBuildingInterface*/ false, /*IsFramework*/false); + /*isCanImportLookup*/ false, /*IsFramework*/false); ASSERT_FALSE(error); ASSERT_FALSE(diags.hadAnyError()); From 48c2a328ece0cd565f4d44b8dd90f67f8cfa57a5 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 23 Sep 2025 15:36:11 -0700 Subject: [PATCH 2/2] [Dependency Scanning] Add support for diagnosing invalid architecture swift binary module candidates Refactor 'maybeDiagnoseTargetMismatch' to separately collect mismatching target variant modules in 'identifyArchitectureVariants' and rename it to 'handlePossibleTargetMismatch'. Prior uses of 'maybeDiagnoseTargetMismatch' will continue diagnosing errors/warnings on only discovering incompatible swift binary module target variants. A new overload of 'handlePossibleTargetMismatch', in 'SwiftModuleScanner', instead collects it as a discovered incompatible candidate, for diagnosis downstream. --- include/swift/Serialization/ScanningLoaders.h | 6 +++ .../Serialization/SerializedModuleLoader.h | 15 ++++-- lib/Serialization/ScanningLoaders.cpp | 15 ++++++ lib/Serialization/SerializedModuleLoader.cpp | 51 +++++++++++-------- test/ScanDependencies/incompatible-arch.swift | 12 +++++ 5 files changed, 76 insertions(+), 23 deletions(-) create mode 100644 test/ScanDependencies/incompatible-arch.swift diff --git a/include/swift/Serialization/ScanningLoaders.h b/include/swift/Serialization/ScanningLoaders.h index aca27bf78d3..709ade45216 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -70,6 +70,12 @@ private: ModuleVersionInfo *versionInfo, bool isTestableImport) override; + bool handlePossibleTargetMismatch( + SourceLoc sourceLocation, + StringRef moduleName, + const SerializedModuleBaseName &BaseName, + bool isCanImportLookup) override; + virtual void collectVisibleTopLevelModuleNames( SmallVectorImpl &names) const override { llvm_unreachable("Not used"); diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index c3f10e4a9b1..ae1f744f04e 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -151,14 +151,23 @@ protected: /// to list the architectures that \e are present. /// /// \returns true if an error diagnostic was emitted - virtual bool maybeDiagnoseTargetMismatch( + virtual bool handlePossibleTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &BaseName, + const SerializedModuleBaseName &baseName, bool isCanImportLookup) { return false; } + /// Assuming the \c baseName is a target-specific Swift module path, + /// for a missing target variant, collect all adjacent binary module + /// files to build a list of discovered modules for incompatible + /// architectures. + static void identifyArchitectureVariants( + ASTContext &Ctx, + const SerializedModuleBaseName &baseName, + std::vector &incompatibleArchModules); + /// Determines if the provided path is a cached artifact for dependency /// tracking purposes. virtual bool isCached(StringRef DepPath) { @@ -282,7 +291,7 @@ class ImplicitSerializedModuleLoader : public SerializedModuleLoaderBase { bool IsCanImportLookup, bool IsFramework, bool IsTestableDependencyLookup = false) override; - bool maybeDiagnoseTargetMismatch( + bool handlePossibleTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, const SerializedModuleBaseName &BaseName, diff --git a/lib/Serialization/ScanningLoaders.cpp b/lib/Serialization/ScanningLoaders.cpp index cc64d18180a..9029739e263 100644 --- a/lib/Serialization/ScanningLoaders.cpp +++ b/lib/Serialization/ScanningLoaders.cpp @@ -107,6 +107,21 @@ bool SwiftModuleScanner::canImportModule( path, loc, versionInfo, isTestableDependencyLookup); } +bool SwiftModuleScanner::handlePossibleTargetMismatch( + SourceLoc sourceLocation, StringRef moduleName, + const SerializedModuleBaseName &absoluteBaseName, + bool isCanImportLookup) { + std::vector foundIncompatibleArchModules; + identifyArchitectureVariants(Ctx, absoluteBaseName, + foundIncompatibleArchModules); + + for (const auto &modulePath : foundIncompatibleArchModules) + incompatibleCandidates.push_back({modulePath, + "invalid architecture"}); + + return false; +} + static std::vector getCompiledCandidates(ASTContext &ctx, StringRef moduleName, StringRef interfacePath) { diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index e3ce288fbd5..27c190ded4b 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -577,47 +577,58 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( return std::error_code(); } -bool ImplicitSerializedModuleLoader::maybeDiagnoseTargetMismatch( - SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &absoluteBaseName, - bool isCanImportLookup) { +void SerializedModuleLoaderBase::identifyArchitectureVariants( + ASTContext &Ctx, const SerializedModuleBaseName &absoluteBaseName, + std::vector &incompatibleArchModules) { llvm::vfs::FileSystem &fs = *Ctx.SourceMgr.getFileSystem(); - // Get the last component of the base name, which is the target-specific one. - auto target = llvm::sys::path::filename(absoluteBaseName.baseName); - // Strip off the last component to get the .swiftmodule folder. auto dir = absoluteBaseName.baseName; llvm::sys::path::remove_filename(dir); std::error_code errorCode; - std::string foundArchs; for (llvm::vfs::directory_iterator directoryIterator = fs.dir_begin(dir, errorCode), endIterator; directoryIterator != endIterator; directoryIterator.increment(errorCode)) { if (errorCode) - return false; + continue; StringRef filePath = directoryIterator->path(); StringRef extension = llvm::sys::path::extension(filePath); if (file_types::lookupTypeForExtension(extension) == file_types::TY_SwiftModuleFile) { - if (!foundArchs.empty()) - foundArchs += ", "; - foundArchs += llvm::sys::path::stem(filePath).str(); + incompatibleArchModules.push_back(filePath.str()); } } +} - if (foundArchs.empty()) { - // Maybe this swiftmodule directory only contains swiftinterfaces, or - // maybe something else is going on. Regardless, we shouldn't emit a - // possibly incorrect diagnostic. +bool ImplicitSerializedModuleLoader::handlePossibleTargetMismatch( + SourceLoc sourceLocation, StringRef moduleName, + const SerializedModuleBaseName &absoluteBaseName, + bool isCanImportLookup) { + std::string foundArchs; + std::vector foundIncompatibleArchModules; + identifyArchitectureVariants(Ctx, absoluteBaseName, + foundIncompatibleArchModules); + + // Maybe this swiftmodule directory only contains swiftinterfaces, or + // maybe something else is going on. Regardless, we shouldn't emit a + // possibly incorrect diagnostic. + if (foundIncompatibleArchModules.empty()) return false; + + // Generate combined list of discovered architectures + // for the diagnostic + for (const auto &modulePath : foundIncompatibleArchModules) { + if (!foundArchs.empty()) + foundArchs += ", "; + foundArchs += llvm::sys::path::stem(modulePath).str(); } Ctx.Diags - .diagnose(sourceLocation, diag::sema_no_import_target, moduleName, target, - foundArchs, dir) + .diagnose(sourceLocation, diag::sema_no_import_target, moduleName, + llvm::sys::path::filename(absoluteBaseName.baseName), + foundArchs, absoluteBaseName.baseName) .limitBehaviorIf(isCanImportLookup, DiagnosticBehavior::Warning); return !isCanImportLookup; } @@ -782,8 +793,8 @@ bool SerializedModuleLoaderBase::findModule( // We can only get here if all targetFileNamePairs failed with // 'std::errc::no_such_file_or_directory'. if (firstAbsoluteBaseName && - maybeDiagnoseTargetMismatch(moduleID.Loc, moduleName, - *firstAbsoluteBaseName, isCanImportLookup)) + handlePossibleTargetMismatch(moduleID.Loc, moduleName, + *firstAbsoluteBaseName, isCanImportLookup)) return SearchResult::Error; return SearchResult::NotFound; diff --git a/test/ScanDependencies/incompatible-arch.swift b/test/ScanDependencies/incompatible-arch.swift new file mode 100644 index 00000000000..58cc7ec916f --- /dev/null +++ b/test/ScanDependencies/incompatible-arch.swift @@ -0,0 +1,12 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/module-cache) +// RUN: %empty-directory(%t/inputs/Foo.swiftmodule) +// RUN: touch %t/inputs/Foo.swiftmodule/i387.swiftmodule +// RUN: touch %t/inputs/Foo.swiftmodule/ppc65.swiftmodule + +// RUN: %target-swift-frontend -scan-dependencies -module-cache-path %t/module-cache %s -o %t/deps.json -I %t/inputs -diagnostic-style llvm -scanner-module-validation 2>&1 | %FileCheck %s + +// CHECK: error: unable to resolve Swift module dependency to a compatible module: 'Foo' +// CHECK-DAG: note: found incompatible module '{{.*}}Foo.swiftmodule{{/|\\}}ppc65.swiftmodule': invalid architecture +// CHECK-DAG: note: found incompatible module '{{.*}}Foo.swiftmodule{{/|\\}}i387.swiftmodule': invalid architecture +import Foo