Merge pull request #84475 from artemcm/NoCanImportFailOnWrongArch

Do not fail the build on only finding incompatible-architecture modules on `canImport` queries
This commit is contained in:
Artem Chikin
2025-09-25 17:01:38 -04:00
committed by GitHub
10 changed files with 126 additions and 68 deletions

View File

@@ -152,7 +152,7 @@ class ExplicitSwiftModuleLoader: public SerializedModuleLoaderBase {
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleSourceInfoBuffer,
bool SkipBuildingInterface, bool IsFramework,
bool IsCanImportLookup, bool IsFramework,
bool IsTestableDependencyLookup = false) override;
bool isCached(StringRef DepPath) override;

View File

@@ -63,13 +63,19 @@ private:
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<Identifier> &names) const override {
llvm_unreachable("Not used");

View File

@@ -103,7 +103,7 @@ protected:
std::unique_ptr<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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 @@ 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<std::string> &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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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();

View File

@@ -1336,8 +1336,8 @@ std::error_code ModuleInterfaceLoader::findModuleFilesInDirectory(
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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);

View File

@@ -46,7 +46,7 @@ std::error_code SwiftModuleScanner::findModuleFilesInDirectory(
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<std::string> foundIncompatibleArchModules;
identifyArchitectureVariants(Ctx, absoluteBaseName,
foundIncompatibleArchModules);
for (const auto &modulePath : foundIncompatibleArchModules)
incompatibleCandidates.push_back({modulePath,
"invalid architecture"});
return false;
}
static std::vector<std::string> getCompiledCandidates(ASTContext &ctx,
StringRef moduleName,
StringRef interfacePath) {

View File

@@ -550,7 +550,7 @@ std::error_code ImplicitSerializedModuleLoader::findModuleFilesInDirectory(
std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<std::string> &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());
}
}
}
bool ImplicitSerializedModuleLoader::handlePossibleTargetMismatch(
SourceLoc sourceLocation, StringRef moduleName,
const SerializedModuleBaseName &absoluteBaseName,
bool isCanImportLookup) {
std::string foundArchs;
std::vector<std::string> foundIncompatibleArchModules;
identifyArchitectureVariants(Ctx, absoluteBaseName,
foundIncompatibleArchModules);
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.
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<llvm::MemoryBuffer> *moduleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *moduleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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<llvm::MemoryBuffer> *ModuleBuffer,
std::unique_ptr<llvm::MemoryBuffer> *ModuleDocBuffer,
std::unique_ptr<llvm::MemoryBuffer> *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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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());