[Dependency Scanning][C++ Interop] Avoid 'CxxStdlib' overlay lookup for binary Swift dependencies which were not built with C++ interop

In addition to skipping it on textual Swift module dependencies which were built without C++ interop enabled, also skip it over similarly on binary Swift dependencies
This commit is contained in:
Artem Chikin
2025-08-04 17:34:50 -07:00
parent 3db1a66f08
commit 77a61a242f
7 changed files with 87 additions and 36 deletions

View File

@@ -393,8 +393,8 @@ public:
ArrayRef<LinkLibrary> linkLibraries,
ArrayRef<serialization::SearchPath> serializedSearchPaths,
StringRef headerImport, StringRef definingModuleInterface,
bool isFramework, bool isStatic, StringRef moduleCacheKey,
StringRef userModuleVersion)
bool isFramework, bool isStatic, bool isBuiltWithCxxInterop,
StringRef moduleCacheKey, StringRef userModuleVersion)
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::SwiftBinary,
moduleImports, optionalModuleImports,
linkLibraries, moduleCacheKey),
@@ -403,6 +403,7 @@ public:
definingModuleInterfacePath(definingModuleInterface),
serializedSearchPaths(serializedSearchPaths),
isFramework(isFramework), isStatic(isStatic),
isBuiltWithCxxInterop(isBuiltWithCxxInterop),
userModuleVersion(userModuleVersion) {}
ModuleDependencyInfoStorageBase *clone() const override {
@@ -440,6 +441,10 @@ public:
/// A flag that indicates this dependency is associated with a static archive
const bool isStatic;
/// A flag that indicates this dependency module was built
/// with C++ interop enabled
const bool isBuiltWithCxxInterop;
/// The user module version of this binary module.
const std::string userModuleVersion;
@@ -573,14 +578,14 @@ public:
ArrayRef<LinkLibrary> linkLibraries,
ArrayRef<serialization::SearchPath> serializedSearchPaths,
StringRef headerImport, StringRef definingModuleInterface,
bool isFramework, bool isStatic, StringRef moduleCacheKey,
StringRef userModuleVer) {
bool isFramework, bool isStatic, bool isBuiltWithCxxInterop,
StringRef moduleCacheKey, StringRef userModuleVer) {
return ModuleDependencyInfo(
std::make_unique<SwiftBinaryModuleDependencyStorage>(
compiledModulePath, moduleDocPath, sourceInfoPath, moduleImports,
optionalModuleImports, linkLibraries, serializedSearchPaths,
headerImport, definingModuleInterface,isFramework, isStatic,
moduleCacheKey, userModuleVer));
isBuiltWithCxxInterop, moduleCacheKey, userModuleVer));
}
/// Describe the main Swift module.

View File

@@ -56,6 +56,8 @@ using IsFrameworkField = BCFixed<1>;
using IsSystemField = BCFixed<1>;
/// A bit that indicates whether or not a module is that of a static archive
using IsStaticField = BCFixed<1>;
/// A bit that indicates whether or not a module is built with C++ interop
using IsBuiltWithCxxInteropField = BCFixed<1>;
/// A bit that indicates whether or not a link library is a force-load one
using IsForceLoadField = BCFixed<1>;
/// A bit that indicates whether or not an import statement is optional
@@ -267,6 +269,7 @@ using SwiftBinaryModuleDetailsLayout =
SearchPathArrayIDField, // serializedSearchPaths
IsFrameworkField, // isFramework
IsStaticField, // isStatic
IsBuiltWithCxxInteropField, // IsBuiltWithCxxInterop
IdentifierIDField, // moduleCacheKey
IdentifierIDField // UserModuleVersion
>;

View File

@@ -679,13 +679,14 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
unsigned compiledModulePathID, moduleDocPathID, moduleSourceInfoPathID,
headerImportID, definingInterfacePathID, searchPathArrayID,
headerModuleDependenciesArrayID, headerImportsSourceFilesArrayID,
isFramework, isStatic, moduleCacheKeyID, userModuleVersionID;
isFramework, isStatic, isBuiltWithCxxInterop, moduleCacheKeyID,
userModuleVersionID;
SwiftBinaryModuleDetailsLayout::readRecord(
Scratch, compiledModulePathID, moduleDocPathID,
moduleSourceInfoPathID, headerImportID, definingInterfacePathID,
headerModuleDependenciesArrayID, headerImportsSourceFilesArrayID,
searchPathArrayID, isFramework, isStatic, moduleCacheKeyID,
userModuleVersionID);
searchPathArrayID, isFramework, isStatic, isBuiltWithCxxInterop,
moduleCacheKeyID, userModuleVersionID);
auto compiledModulePath = getIdentifier(compiledModulePathID);
if (!compiledModulePath)
@@ -720,7 +721,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(
*compiledModulePath, *moduleDocPath, *moduleSourceInfoPath,
importStatements, optionalImportStatements, linkLibraries,
*searchPaths, *headerImport, *definingInterfacePath, isFramework,
isStatic, *moduleCacheKey, *userModuleVersion);
isStatic, isBuiltWithCxxInterop, *moduleCacheKey, *userModuleVersion);
addCommonDependencyInfo(moduleDep);
addSwiftCommonDependencyInfo(moduleDep);
@@ -1629,6 +1630,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(
ModuleIdentifierArrayKind::HeaderInputDependencySourceFiles),
getSearchPathArrayID(moduleID),
swiftBinDeps->isFramework, swiftBinDeps->isStatic,
swiftBinDeps->isBuiltWithCxxInterop,
getIdentifier(swiftBinDeps->moduleCacheKey),
getIdentifier(swiftBinDeps->userModuleVersion));
break;

View File

@@ -1525,23 +1525,34 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule(
recordResult(clangDep.getKey().str());
// C++ Interop requires additional handling
bool lookupCxxStdLibOverlay = ScanCompilerInvocation.getLangOptions().EnableCXXInterop;
if (lookupCxxStdLibOverlay && moduleID.Kind == ModuleDependencyKind::SwiftInterface) {
bool lookupCxxStdLibOverlay =
ScanCompilerInvocation.getLangOptions().EnableCXXInterop;
if (lookupCxxStdLibOverlay &&
moduleID.Kind == ModuleDependencyKind::SwiftInterface) {
const auto &moduleInfo = cache.findKnownDependency(moduleID);
const auto commandLine = moduleInfo.getCommandline();
// If the textual interface was built without C++ interop, do not query
// the C++ Standard Library Swift overlay for its compilation.
//
// FIXME: We always declare the 'Darwin' module as formally having been built
// without C++Interop, for compatibility with prior versions. Once we are certain
// that we are only building against modules built with support of
// '-formal-cxx-interoperability-mode', this hard-coded check should be removed.
if (moduleID.ModuleName == "Darwin" ||
llvm::find(commandLine, "-formal-cxx-interoperability-mode=off") !=
commandLine.end())
if (llvm::find(commandLine, "-formal-cxx-interoperability-mode=off") !=
commandLine.end())
lookupCxxStdLibOverlay = false;
} else if (lookupCxxStdLibOverlay &&
moduleID.Kind == ModuleDependencyKind::SwiftBinary) {
const auto &moduleDetails =
cache.findKnownDependency(moduleID).getAsSwiftBinaryModule();
// If the binary module was built without C++ interop, do not query
// the C++ Standard Library Swift overlay.
if (!moduleDetails->isBuiltWithCxxInterop)
lookupCxxStdLibOverlay = false;
}
// FIXME: We always declare the 'Darwin' module as formally having been built
// without C++Interop, for compatibility with prior versions. Once we are certain
// that we are only building against modules built with support of
// '-formal-cxx-interoperability-mode', this hard-coded check should be removed.
if (lookupCxxStdLibOverlay && moduleID.ModuleName == "Darwin")
lookupCxxStdLibOverlay = false;
if (lookupCxxStdLibOverlay) {
for (const auto &clangDepNameEntry : visibleClangDependencies) {
auto clangDepName = clangDepNameEntry.getKey().str();

View File

@@ -653,6 +653,11 @@ public:
return Bits.IsStaticLibrary;
}
/// Was this module built with C++ interop enabled.
bool isBuiltWithCxxInterop() const {
return Bits.HasCxxInteroperability;
}
llvm::VersionTuple getUserModuleVersion() const {
return UserModuleVersion;
}

View File

@@ -340,6 +340,7 @@ llvm::ErrorOr<ModuleDependencyInfo> SwiftModuleScanner::scanBinaryModuleFile(
binaryModuleOptionalImports->moduleImports, linkLibraries,
serializedSearchPaths, binaryModuleImports->headerImport,
definingModulePath, isFramework, loadedModuleFile->isStaticLibrary(),
loadedModuleFile->isBuiltWithCxxInterop(),
/*module-cache-key*/ "", userModuleVer);
for (auto &macro : loadedModuleFile->getExternalMacros()) {

View File

@@ -1,3 +1,4 @@
// RUN: %empty-directory(%t)
// RUN: %empty-directory(%t/deps)
// RUN: split-file %s %t
@@ -8,17 +9,29 @@
// RUN: %target-swift-frontend -scan-dependencies -o %t/deps_no_interop_dep.json %t/clientNoInteropDep.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -verify
// RUN: cat %t/deps_no_interop_dep.json | %FileCheck %s -check-prefix=DISABLE-CHECK
// RUN: %target-swift-frontend -emit-module %t/BinaryDepNoInterop.swift -emit-module-path %t/deps/BinaryDepNoInterop.swiftmodule -module-name BinaryDepNoInterop -I %t/deps -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import
// RUN: %target-swift-frontend -scan-dependencies -o %t/deps_no_interop_binary_dep.json %t/clientNoInteropBinaryDep.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -verify
// RUN: cat %t/deps_no_interop_binary_dep.json | %FileCheck %s -check-prefix=DISABLE-BINARY-CHECK
// RUN: %target-swift-frontend -scan-dependencies -o %t/deps_darwin_dep.json %t/clientDarwin.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -verify
// RUN: cat %t/deps_darwin_dep.json | %FileCheck %s -check-prefix=DARWIN-CHECK
//--- deps/bar.h
void bar(void);
//--- deps/baz.h
#include "bar.h"
void baz(void);
//--- deps/module.modulemap
module std_Bar [system] {
header "bar.h"
export *
}
module normal {
header "baz.h"
export *
}
//--- deps/Foo.swiftinterface
// swift-interface-format-version: 1.0
@@ -39,12 +52,19 @@ public struct Foo2 {}
import std_Bar
public struct Foo3 {}
//--- BinaryDepNoInterop.swift
import normal
public struct Foo6 {}
//--- clientWithInteropDep.swift
import Foo
//--- clientNoInteropDep.swift
import FooNoInterop
//--- clientNoInteropBinaryDep.swift
import BinaryDepNoInterop
//--- clientDarwin.swift
import Darwin
@@ -87,21 +107,25 @@ import Darwin
// DISABLE-CHECK: }
// DISABLE-CHECK: ],
// Ensure that the the 'Darwin' dependency does not get the C++ standard library overlay for its 'std_*' dependencies
//
// 'Darwin' as it appears in direct deps
// DARWIN-CHECK: "swift": "Darwin"
// 'Darwin' as it appears in source-import deps
// DARWIN-CHECK: "swift": "Darwin"
// Actual dependency info node
// DARWIN-CHECK: "swift": "Darwin"
// DISABLE-BINARY-CHECK: "modulePath": "{{.*}}{{/|\\}}BinaryDepNoInterop.swiftmodule"
// DISABLE-BINARY-CHECK: "directDependencies": [
// DISABLE-BINARY-CHECK-NEXT: {
// DISABLE-BINARY-CHECK-NEXT: "swift": "Swift"
// DISABLE-BINARY-CHECK-NEXT: },
// DISABLE-BINARY-CHECK-NEXT: {
// DISABLE-BINARY-CHECK-NEXT: "swift": "SwiftOnoneSupport"
// DISABLE-BINARY-CHECK-NEXT: },
// DISABLE-BINARY-CHECK-NEXT: {
// DISABLE-BINARY-CHECK-NEXT: "clang": "normal"
// DISABLE-BINARY-CHECK-NEXT: }
// DISABLE-BINARY-CHECK-NEXT: ],
// DARWIN-CHECK: "modulePath": "{{.*}}{{/|\\}}Darwin-{{.*}}.swiftmodule"
// DARWIN-CHECK: "directDependencies": [
// DARWIN-CHECK: {
// DARWIN-CHECK: "swift": "SwiftOnoneSupport"
// DARWIN-CHECK: },
// DARWIN-CHECK: {
// DARWIN-CHECK: "clang": "std_Bar"
// DARWIN-CHECK: }
// DARWIN-CHECK: ],
// DARWIN-CHECK-NEXT: {
// DARWIN-CHECK-NEXT: "swift": "SwiftOnoneSupport"
// DARWIN-CHECK-NEXT: },
// DARWIN-CHECK-NEXT: {
// DARWIN-CHECK-NEXT: "clang": "std_Bar"
// DARWIN-CHECK-NEXT: }
// DARWIN-CHECK-NEXT: ],