diff --git a/include/swift/Frontend/ModuleInterfaceLoader.h b/include/swift/Frontend/ModuleInterfaceLoader.h index 668c7a8263105..50661110b2cd0 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 1799d7262f803..709ade4521666 100644 --- a/include/swift/Serialization/ScanningLoaders.h +++ b/include/swift/Serialization/ScanningLoaders.h @@ -63,13 +63,19 @@ class SwiftModuleScanner : public SerializedModuleLoaderBase { 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, 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 6eb1a0d14779a..ae1f744f04e3b 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -103,7 +103,7 @@ class SerializedModuleLoaderBase : public ModuleLoader { 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 @@ class SerializedModuleLoaderBase : public ModuleLoader { 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( @@ -151,13 +151,23 @@ class SerializedModuleLoaderBase : public ModuleLoader { /// 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) { @@ -278,13 +288,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( + bool handlePossibleTargetMismatch( SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &BaseName) override; + const SerializedModuleBaseName &BaseName, + bool isCanImportLookup) override; public: virtual ~ImplicitSerializedModuleLoader(); @@ -336,14 +347,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 2dc62e5d08502..fade5b2bf48d3 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 070a915bb33de..9029739e2639b 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; @@ -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 328345b9ffab7..27c190ded4bdb 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); @@ -577,46 +577,60 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory( return std::error_code(); } -bool ImplicitSerializedModuleLoader::maybeDiagnoseTargetMismatch( - SourceLoc sourceLocation, StringRef moduleName, - const SerializedModuleBaseName &absoluteBaseName) { +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); - return true; + Ctx.Diags + .diagnose(sourceLocation, diag::sema_no_import_target, moduleName, + llvm::sys::path::filename(absoluteBaseName.baseName), + foundArchs, absoluteBaseName.baseName) + .limitBehaviorIf(isCanImportLookup, DiagnosticBehavior::Warning); + return !isCanImportLookup; } SerializedModuleBaseName::SerializedModuleBaseName( @@ -720,7 +734,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 +780,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; @@ -779,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)) + handlePossibleTargetMismatch(moduleID.Loc, moduleName, + *firstAbsoluteBaseName, isCanImportLookup)) return SearchResult::Error; return SearchResult::NotFound; @@ -838,7 +852,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 +1526,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 +1621,7 @@ SerializedModuleLoaderBase::loadModule(SourceLoc importLoc, if (!findModule(moduleID, &moduleInterfacePath, &moduleInterfaceSourcePath, &moduleInputBuffer, &moduleDocInputBuffer, &moduleSourceInfoInputBuffer, - /*skipBuildingInterface=*/false, + /*isCanImportLookup=*/false, /*isTestableDependencyLookup=*/false, isFramework, isSystemModule)) { @@ -1747,7 +1761,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 +1770,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 218a5e7912b72..4edc561fce25e 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/ScanDependencies/incompatible-arch.swift b/test/ScanDependencies/incompatible-arch.swift new file mode 100644 index 0000000000000..58cc7ec916fa4 --- /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 diff --git a/test/Serialization/can-import-invalid-arch.swift b/test/Serialization/can-import-invalid-arch.swift new file mode 100644 index 0000000000000..2d4e7bf45babf --- /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 8dd785f3dbeb0..d71c151eb239b 100644 --- a/unittests/FrontendTool/ModuleLoadingTests.cpp +++ b/unittests/FrontendTool/ModuleLoadingTests.cpp @@ -131,7 +131,7 @@ class ModuleInterfaceLoaderTest : public testing::Test { 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());