Skip to content

Commit 1d2a23b

Browse files
authored
Merge pull request #73767 from artemcm/60DepScanCPPInterop
[6.0🍒][Explicit Module Builds] C++ Interoperability mode fixes
2 parents d7ff19f + 298521b commit 1d2a23b

19 files changed

+161
-33
lines changed

include/swift/AST/ModuleDependencies.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,9 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
403403
/// CASID for the Root of ClangIncludeTree. Empty if not used.
404404
std::string CASClangIncludeTreeRootID;
405405

406+
/// Whether this is a "system" module.
407+
bool IsSystem;
408+
406409
ClangModuleDependencyStorage(const std::string &pcmOutputPath,
407410
const std::string &mappedPCMPath,
408411
const std::string &moduleMapFile,
@@ -412,15 +415,16 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase {
412415
const std::vector<std::string> &capturedPCMArgs,
413416
const std::string &CASFileSystemRootID,
414417
const std::string &clangIncludeTreeRoot,
415-
const std::string &moduleCacheKey)
418+
const std::string &moduleCacheKey,
419+
bool IsSystem)
416420
: ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang,
417421
moduleCacheKey),
418422
pcmOutputPath(pcmOutputPath), mappedPCMPath(mappedPCMPath),
419423
moduleMapFile(moduleMapFile), contextHash(contextHash),
420424
buildCommandLine(buildCommandLine), fileDependencies(fileDependencies),
421425
capturedPCMArgs(capturedPCMArgs),
422426
CASFileSystemRootID(CASFileSystemRootID),
423-
CASClangIncludeTreeRootID(clangIncludeTreeRoot) {}
427+
CASClangIncludeTreeRootID(clangIncludeTreeRoot), IsSystem(IsSystem) {}
424428

425429
ModuleDependencyInfoStorageBase *clone() const override {
426430
return new ClangModuleDependencyStorage(*this);
@@ -549,11 +553,12 @@ class ModuleDependencyInfo {
549553
const std::vector<std::string> &capturedPCMArgs,
550554
const std::string &CASFileSystemRootID,
551555
const std::string &clangIncludeTreeRoot,
552-
const std::string &moduleCacheKey) {
556+
const std::string &moduleCacheKey,
557+
bool IsSystem) {
553558
return ModuleDependencyInfo(std::make_unique<ClangModuleDependencyStorage>(
554559
pcmOutputPath, mappedPCMPath, moduleMapFile, contextHash,
555560
nonPathCommandLine, fileDependencies, capturedPCMArgs,
556-
CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey));
561+
CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey, IsSystem));
557562
}
558563

559564
/// Describe a placeholder dependency swift module.

include/swift/Basic/LangOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,9 @@ namespace swift {
402402
bool DisableImplicitBacktracingModuleImport =
403403
!SWIFT_IMPLICIT_BACKTRACING_IMPORT;
404404

405+
/// Disable the implicit import of the Cxx module.
406+
bool DisableImplicitCxxModuleImport = false;
407+
405408
// Whether to use checked continuations when making an async call from
406409
// Swift into ObjC. If false, will use unchecked continuations instead.
407410
bool UseCheckedAsyncObjCBridging = false;

include/swift/ClangImporter/ClangImporter.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,11 @@ bool requiresCPlusPlus(const clang::Module *module);
665665
/// (std_vector, std_iosfwd, etc).
666666
bool isCxxStdModule(const clang::Module *module);
667667

668+
/// Returns true if the given module is one of the C++ standard library modules.
669+
/// This could be the top-level std module, or any of the libc++ split modules
670+
/// (std_vector, std_iosfwd, etc).
671+
bool isCxxStdModule(StringRef moduleName, bool IsSystem);
672+
668673
/// Returns the pointee type if the given type is a C++ `const`
669674
/// reference type, `None` otherwise.
670675
std::optional<clang::QualType>

include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ using llvm::BCVBR;
4040
/// Every .moddepcache file begins with these 4 bytes, for easy identification.
4141
const unsigned char MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE[] = {'I', 'M', 'D','C'};
4242
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR =
43-
6; // mappedPCMPath
43+
7; // isSystem
4444
/// Increment this on every change.
4545
const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 1;
4646

@@ -53,6 +53,8 @@ using ContextHashIDField = IdentifierIDField;
5353

5454
/// A bit that indicates whether or not a module is a framework
5555
using IsFrameworkField = BCFixed<1>;
56+
/// A bit that indicates whether or not a module is a system module
57+
using IsSystemField = BCFixed<1>;
5658

5759
/// Arrays of various identifiers, distinguished for readability
5860
using IdentifierIDArryField = llvm::BCArray<IdentifierIDField>;
@@ -193,7 +195,8 @@ using ClangModuleDetailsLayout =
193195
FlagIDArrayIDField, // capturedPCMArgs
194196
IdentifierIDField, // CASFileSystemRootID
195197
IdentifierIDField, // clangIncludeTreeRoot
196-
IdentifierIDField // moduleCacheKey
198+
IdentifierIDField, // moduleCacheKey
199+
IsSystemField // isSystem
197200
>;
198201
} // namespace graph_block
199202

include/swift/Frontend/Frontend.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,9 @@ class CompilerInvocation {
405405
/// imported.
406406
bool shouldImportSwiftBacktracing() const;
407407

408+
/// Whether the CXX module should be implicitly imported.
409+
bool shouldImportCxx() const;
410+
408411
/// Performs input setup common to these tools:
409412
/// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm.
410413
/// Return value includes the buffer so caller can keep it alive.
@@ -660,6 +663,9 @@ class CompilerInstance {
660663
/// i.e. if it can be found.
661664
bool canImportSwiftBacktracing() const;
662665

666+
/// Whether the Cxx library can be imported
667+
bool canImportCxx() const;
668+
663669
/// Whether the CxxShim library can be imported
664670
/// i.e. if it can be found.
665671
bool canImportCxxShim() const;

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,10 @@ def disable_implicit_backtracing_module_import : Flag<["-"],
505505
"disable-implicit-backtracing-module-import">,
506506
HelpText<"Disable the implicit import of the _Backtracing module.">;
507507

508+
def disable_implicit_cxx_module_import : Flag<["-"],
509+
"disable-implicit-cxx-module-import">,
510+
HelpText<"Disable the implicit import of the C++ Standard Library module.">;
511+
508512
def disable_arc_opts : Flag<["-"], "disable-arc-opts">,
509513
HelpText<"Don't run SIL ARC optimization passes.">;
510514
def disable_ossa_opts : Flag<["-"], "disable-ossa-opts">,

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ class SerializedModuleLoaderBase : public ModuleLoader {
171171
std::string headerImport;
172172
};
173173

174-
static BinaryModuleImports
175-
getImportsOfModule(const ModuleFileSharedCore &loadedModule,
174+
llvm::ErrorOr<BinaryModuleImports>
175+
getImportsOfModule(const ModuleFileSharedCore &loadedModuleFile,
176176
ModuleLoadingBehavior transitiveBehavior,
177177
StringRef packageName, bool isTestableImport);
178178

include/swift/Strings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ constexpr static const StringLiteral SWIFT_BACKTRACING_NAME = "_Backtracing";
3939
constexpr static const StringLiteral SWIFT_SHIMS_NAME = "SwiftShims";
4040
/// The name of the CxxShim module, which contains a cxx casting utility.
4141
constexpr static const StringLiteral CXX_SHIM_NAME = "CxxShim";
42+
/// The name of the Cxx module, which contains C++ interop helper protocols.
43+
constexpr static const StringLiteral CXX_MODULE_NAME = "Cxx";
4244
/// The name of the Builtin module, which contains Builtin functions.
4345
constexpr static const StringLiteral BUILTIN_NAME = "Builtin";
4446
/// The name of the clang imported header module.

lib/ClangImporter/ClangImporter.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7875,14 +7875,20 @@ bool importer::requiresCPlusPlus(const clang::Module *module) {
78757875
}
78767876

78777877
bool importer::isCxxStdModule(const clang::Module *module) {
7878-
if (module->getTopLevelModuleName() == "std")
7878+
return isCxxStdModule(module->getTopLevelModuleName(),
7879+
module->getTopLevelModule()->IsSystem);
7880+
}
7881+
7882+
bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) {
7883+
if (moduleName == "std")
78797884
return true;
78807885
// In recent libc++ versions the module is split into multiple top-level
78817886
// modules (std_vector, std_utility, etc).
7882-
if (module->getTopLevelModule()->IsSystem &&
7883-
module->getTopLevelModuleName().starts_with("std_"))
7887+
if (IsSystem && moduleName.starts_with("std_")) {
7888+
if (moduleName == "std_errno_h")
7889+
return false;
78847890
return true;
7885-
7891+
}
78867892
return false;
78877893
}
78887894

lib/ClangImporter/ClangModuleDependencyScanner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,7 @@ ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies(
289289
auto dependencies = ModuleDependencyInfo::forClangModule(
290290
pcmPath, mappedPCMPath, clangModuleDep.ClangModuleMapFile,
291291
clangModuleDep.ID.ContextHash, swiftArgs, fileDeps, capturedPCMArgs,
292-
RootID, IncludeTree, /*module-cache-key*/ "");
292+
RootID, IncludeTree, /*module-cache-key*/ "", clangModuleDep.IsSystem);
293293
for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
294294
dependencies.addModuleImport(moduleName.ModuleName, &alreadyAddedModules);
295295
// It is safe to assume that all dependencies of a Clang module are Clang modules.

lib/DependencyScan/ModuleDependencyCacheSerialization.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
574574
cache.configureForContextHash(getContextHash());
575575
unsigned pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID,
576576
commandLineArrayID, fileDependenciesArrayID, capturedPCMArgsArrayID,
577-
CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID;
577+
CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID, isSystem;
578578
ClangModuleDetailsLayout::readRecord(
579579
Scratch, pcmOutputPathID, mappedPCMPathID, moduleMapPathID,
580580
contextHashID, commandLineArrayID, fileDependenciesArrayID,
581581
capturedPCMArgsArrayID, CASFileSystemRootID, clangIncludeTreeRootID,
582-
moduleCacheKeyID);
582+
moduleCacheKeyID, isSystem);
583583
auto pcmOutputPath = getIdentifier(pcmOutputPathID);
584584
if (!pcmOutputPath)
585585
llvm::report_fatal_error("Bad pcm output path");
@@ -615,7 +615,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi
615615
auto moduleDep = ModuleDependencyInfo::forClangModule(
616616
*pcmOutputPath, *mappedPCMPath, *moduleMapPath, *contextHash,
617617
*commandLineArgs, *fileDependencies, *capturedPCMArgs,
618-
*rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey);
618+
*rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey, isSystem);
619619

620620
// Add dependencies of this module
621621
for (const auto &moduleName : *currentModuleImports)
@@ -1064,7 +1064,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo(
10641064
getArrayID(moduleID, ModuleIdentifierArrayKind::CapturedPCMArgs),
10651065
getIdentifier(clangDeps->CASFileSystemRootID),
10661066
getIdentifier(clangDeps->CASClangIncludeTreeRootID),
1067-
getIdentifier(clangDeps->moduleCacheKey));
1067+
getIdentifier(clangDeps->moduleCacheKey), clangDeps->IsSystem);
10681068

10691069
break;
10701070
}

lib/DependencyScan/ModuleDependencyScanner.cpp

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/TypeCheckRequests.h"
2222
#include "swift/Basic/FileTypes.h"
2323
#include "swift/Basic/PrettyStackTrace.h"
24+
#include "swift/ClangImporter/ClangImporter.h"
2425
#include "swift/DependencyScan/ModuleDependencyScanner.h"
2526
#include "swift/Frontend/ModuleInterfaceLoader.h"
2627
#include "swift/Serialization/SerializedModuleLoader.h"
@@ -763,24 +764,46 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependencies(
763764
// FIXME: Once all clients know to fetch these dependencies from
764765
// `swiftOverlayDependencies`, the goal is to no longer have them in
765766
// `directDependencies` so the following will need to go away.
766-
directDependencies.insert({moduleName, cachedInfo->getKind()});
767+
directDependencies.insert({moduleName, cachedInfo->getKind()});
767768
} else {
768769
// Cache discovered module dependencies.
769770
cache.recordDependencies(lookupResult.value());
770771
if (!lookupResult.value().empty()) {
771-
swiftOverlayDependencies.insert(
772-
{moduleName, lookupResult.value()[0].first.Kind});
772+
swiftOverlayDependencies.insert({moduleName, lookupResult.value()[0].first.Kind});
773773
// FIXME: Once all clients know to fetch these dependencies from
774774
// `swiftOverlayDependencies`, the goal is to no longer have them in
775775
// `directDependencies` so the following will need to go away.
776-
directDependencies.insert(
777-
{moduleName, lookupResult.value()[0].first.Kind});
778-
}
776+
directDependencies.insert({moduleName, lookupResult.value()[0].first.Kind});
777+
}
779778
}
780779
}
781780
};
782781
for (const auto &clangDep : clangDependencies)
783782
recordResult(clangDep);
783+
784+
// C++ Interop requires additional handling
785+
if (ScanCompilerInvocation.getLangOptions().EnableCXXInterop) {
786+
for (const auto &clangDepName : clangDependencies) {
787+
// If this Clang module is a part of the C++ stdlib, and we haven't loaded
788+
// the overlay for it so far, it is a split libc++ module (e.g.
789+
// std_vector). Load the CxxStdlib overlay explicitly.
790+
const auto &clangDepInfo =
791+
cache.findDependency(clangDepName, ModuleDependencyKind::Clang)
792+
.value()
793+
->getAsClangModule();
794+
if (importer::isCxxStdModule(clangDepName, clangDepInfo->IsSystem) &&
795+
!swiftOverlayDependencies.contains(
796+
{clangDepName, ModuleDependencyKind::SwiftInterface}) &&
797+
!swiftOverlayDependencies.contains(
798+
{clangDepName, ModuleDependencyKind::SwiftBinary})) {
799+
ScanningThreadPool.async(
800+
scanForSwiftDependency,
801+
getModuleImportIdentifier(ScanASTContext.Id_CxxStdlib.str()));
802+
ScanningThreadPool.wait();
803+
recordResult(ScanASTContext.Id_CxxStdlib.str().str());
804+
}
805+
}
806+
}
784807
}
785808

786809
void ModuleDependencyScanner::discoverCrossImportOverlayDependencies(

lib/Frontend/CompilerInvocation.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,9 @@ validateCxxInteropCompatibilityMode(StringRef mode) {
506506
// Swift 5 is the default language version.
507507
if (mode == "swift-5.9")
508508
return {CxxCompatMode::enabled, version::Version({5})};
509+
// Note: If this is updated, corresponding code in
510+
// InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl needs
511+
// to be updated also.
509512
return {CxxCompatMode::invalid, {}};
510513
}
511514

@@ -639,6 +642,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
639642
Opts.DisableImplicitStringProcessingModuleImport |=
640643
Args.hasArg(OPT_disable_implicit_string_processing_module_import);
641644

645+
Opts.DisableImplicitCxxModuleImport |=
646+
Args.hasArg(OPT_disable_implicit_cxx_module_import);
647+
642648
Opts.DisableImplicitBacktracingModuleImport =
643649
Args.hasFlag(OPT_disable_implicit_backtracing_module_import,
644650
OPT_enable_implicit_backtracing_module_import,

lib/Frontend/Frontend.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,6 +1084,26 @@ bool CompilerInvocation::shouldImportSwiftBacktracing() const {
10841084
FrontendOptions::ParseInputMode::SwiftModuleInterface;
10851085
}
10861086

1087+
bool CompilerInvocation::shouldImportCxx() const {
1088+
// C++ Interop is disabled
1089+
if (!getLangOptions().EnableCXXInterop)
1090+
return false;
1091+
// Avoid C++ stdlib when building Swift stdlib
1092+
if (getImplicitStdlibKind() == ImplicitStdlibKind::Builtin)
1093+
return false;
1094+
// Avoid importing Cxx when building Cxx itself
1095+
if (getFrontendOptions().ModuleName == CXX_MODULE_NAME)
1096+
return false;
1097+
// Cxx cannot be imported when Library evolution is enabled
1098+
if (getFrontendOptions().EnableLibraryEvolution)
1099+
return false;
1100+
// Implicit import of Cxx is disabled
1101+
if (getLangOptions().DisableImplicitCxxModuleImport)
1102+
return false;
1103+
1104+
return true;
1105+
}
1106+
10871107
/// Implicitly import the SwiftOnoneSupport module in non-optimized
10881108
/// builds. This allows for use of popular specialized functions
10891109
/// from the standard library, which makes the non-optimized builds
@@ -1165,6 +1185,13 @@ bool CompilerInstance::canImportSwiftBacktracing() const {
11651185
return getASTContext().testImportModule(modulePath);
11661186
}
11671187

1188+
bool CompilerInstance::canImportCxx() const {
1189+
ImportPath::Module::Builder builder(
1190+
getASTContext().getIdentifier(CXX_MODULE_NAME));
1191+
auto modulePath = builder.get();
1192+
return getASTContext().testImportModule(modulePath);
1193+
}
1194+
11681195
bool CompilerInstance::canImportCxxShim() const {
11691196
ImportPath::Module::Builder builder(
11701197
getASTContext().getIdentifier(CXX_SHIM_NAME));
@@ -1268,8 +1295,11 @@ ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const {
12681295
}
12691296
}
12701297

1271-
if (Invocation.getLangOptions().EnableCXXInterop && canImportCxxShim()) {
1272-
pushImport(CXX_SHIM_NAME, {ImportFlags::ImplementationOnly});
1298+
if (Invocation.getLangOptions().EnableCXXInterop) {
1299+
if (Invocation.shouldImportCxx() && canImportCxx())
1300+
pushImport(CXX_MODULE_NAME);
1301+
if (canImportCxxShim())
1302+
pushImport(CXX_SHIM_NAME, {ImportFlags::ImplementationOnly});
12731303
}
12741304

12751305
imports.ShouldImportUnderlyingModule = frontendOpts.ImportUnderlyingModule;

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,33 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl(
19691969
GenericArgs.push_back("-blocklist-file");
19701970
GenericArgs.push_back(blocklist);
19711971
}
1972+
1973+
// For now, we only inherit the C++ interoperability mode in
1974+
// Explicit Module Builds.
1975+
if (langOpts.EnableCXXInterop &&
1976+
(frontendOpts.DisableImplicitModules ||
1977+
LoaderOpts.requestedAction ==
1978+
FrontendOptions::ActionType::ScanDependencies)) {
1979+
// Modelled after a reverse of validateCxxInteropCompatibilityMode
1980+
genericSubInvocation.getLangOptions().EnableCXXInterop = true;
1981+
genericSubInvocation.getLangOptions().cxxInteropCompatVersion =
1982+
langOpts.cxxInteropCompatVersion;
1983+
std::string compatVersion;
1984+
if (langOpts.cxxInteropCompatVersion.empty())
1985+
compatVersion = "default";
1986+
else if (langOpts.cxxInteropCompatVersion[0] == 5)
1987+
compatVersion = "swift-5.9";
1988+
else if (langOpts.cxxInteropCompatVersion[0] == 6)
1989+
compatVersion = "swift-6";
1990+
else if (langOpts.cxxInteropCompatVersion[0] ==
1991+
version::getUpcomingCxxInteropCompatVersion())
1992+
compatVersion = "upcoming-swift";
1993+
else // TODO: This may need to be updated once more versions are added
1994+
compatVersion = "default";
1995+
1996+
GenericArgs.push_back(
1997+
ArgSaver.save("-cxx-interoperability-mode=" + compatVersion));
1998+
}
19721999
}
19732000

19742001
/// Calculate an output filename in \p genericSubInvocation's cache path that

0 commit comments

Comments
 (0)