From 6414440f510768d3b18d852aa2a1ff8f6c5c4111 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 7 Nov 2023 17:00:36 -0500 Subject: [PATCH 1/4] [Explicit Module Builds] Propagate the C++ Interop mode to interface sub-invocations and dependency scanner --- .../Serialization/SerializedModuleLoader.h | 4 +-- lib/Frontend/CompilerInvocation.cpp | 3 +++ lib/Frontend/ModuleInterfaceLoader.cpp | 25 +++++++++++++++++++ lib/Serialization/SerializedModuleLoader.cpp | 7 ++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 87820f5c4d004..9f330634e0645 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -171,8 +171,8 @@ class SerializedModuleLoaderBase : public ModuleLoader { std::string headerImport; }; - static BinaryModuleImports - getImportsOfModule(const ModuleFileSharedCore &loadedModule, + llvm::ErrorOr + getImportsOfModule(Twine modulePath, ModuleLoadingBehavior transitiveBehavior, StringRef packageName, bool isTestableImport); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index f15f0525f3015..b79c064e0ae8d 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -506,6 +506,9 @@ validateCxxInteropCompatibilityMode(StringRef mode) { // Swift 5 is the default language version. if (mode == "swift-5.9") return {CxxCompatMode::enabled, version::Version({5})}; + // Note: If this is updated, corresponding code in + // InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl needs + // to be updated also. return {CxxCompatMode::invalid, {}}; } diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index 952fa247afb4e..b3196c3637cd1 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1969,6 +1969,31 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( GenericArgs.push_back("-blocklist-file"); GenericArgs.push_back(blocklist); } + + // For now, we only inherit the C++ interoperability mode in + // Explicit Module Builds. + if (langOpts.EnableCXXInterop && + (frontendOpts.DisableImplicitModules || + LoaderOpts.requestedAction == + FrontendOptions::ActionType::ScanDependencies)) { + // Modelled after a reverse of validateCxxInteropCompatibilityMode + genericSubInvocation.getLangOptions().EnableCXXInterop = true; + genericSubInvocation.getLangOptions().cxxInteropCompatVersion = + langOpts.cxxInteropCompatVersion; + std::string compatVersion; + if (langOpts.cxxInteropCompatVersion.empty()) + compatVersion = "default"; + else if (langOpts.cxxInteropCompatVersion[0] == 5) + compatVersion = "swift-5.9"; + else if (langOpts.cxxInteropCompatVersion[0] == + version::getUpcomingCxxInteropCompatVersion()) + compatVersion = "upcoming-swift"; + else // TODO: This may need to be updated once more versions are added + compatVersion = "default"; + + GenericArgs.push_back( + ArgSaver.save("-cxx-interoperability-mode=" + compatVersion)); + } } /// Calculate an output filename in \p genericSubInvocation's cache path that diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index a44ee0f19e41a..4fb3055258e42 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -422,6 +422,13 @@ SerializedModuleLoaderBase::getImportsOfModule( if (dotPos != std::string::npos) moduleName = moduleName.slice(0, dotPos); + // Reverse rewrite of user-specified C++ standard + // library module name to one used in the modulemap. + // TODO: If we are going to do this for more than this module, + // we will need a centralized system for doing module import name remap. + if (moduleName == Ctx.Id_CxxStdlib.str()) + moduleName = "std"; + importedModuleNames.insert(moduleName); } From 7470b77326aaf94aec9486e6c9b5c94e67c62054 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Mon, 12 Feb 2024 16:55:21 -0800 Subject: [PATCH 2/4] [Dependency Scanning] Add required additional C++ interop overlay module queries --- include/swift/AST/ModuleDependencies.h | 13 ++++--- include/swift/ClangImporter/ClangImporter.h | 5 +++ .../SerializedModuleDependencyCacheFormat.h | 5 ++- lib/ClangImporter/ClangImporter.cpp | 14 +++++--- .../ClangModuleDependencyScanner.cpp | 2 +- .../ModuleDependencyCacheSerialization.cpp | 8 ++--- .../ModuleDependencyScanner.cpp | 35 +++++++++++++++---- 7 files changed, 62 insertions(+), 20 deletions(-) diff --git a/include/swift/AST/ModuleDependencies.h b/include/swift/AST/ModuleDependencies.h index 64a7a2cfe99d6..945ffc49572c2 100644 --- a/include/swift/AST/ModuleDependencies.h +++ b/include/swift/AST/ModuleDependencies.h @@ -403,6 +403,9 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { /// CASID for the Root of ClangIncludeTree. Empty if not used. std::string CASClangIncludeTreeRootID; + /// Whether this is a "system" module. + bool IsSystem; + ClangModuleDependencyStorage(const std::string &pcmOutputPath, const std::string &mappedPCMPath, const std::string &moduleMapFile, @@ -412,7 +415,8 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { const std::vector &capturedPCMArgs, const std::string &CASFileSystemRootID, const std::string &clangIncludeTreeRoot, - const std::string &moduleCacheKey) + const std::string &moduleCacheKey, + bool IsSystem) : ModuleDependencyInfoStorageBase(ModuleDependencyKind::Clang, moduleCacheKey), pcmOutputPath(pcmOutputPath), mappedPCMPath(mappedPCMPath), @@ -420,7 +424,7 @@ class ClangModuleDependencyStorage : public ModuleDependencyInfoStorageBase { buildCommandLine(buildCommandLine), fileDependencies(fileDependencies), capturedPCMArgs(capturedPCMArgs), CASFileSystemRootID(CASFileSystemRootID), - CASClangIncludeTreeRootID(clangIncludeTreeRoot) {} + CASClangIncludeTreeRootID(clangIncludeTreeRoot), IsSystem(IsSystem) {} ModuleDependencyInfoStorageBase *clone() const override { return new ClangModuleDependencyStorage(*this); @@ -549,11 +553,12 @@ class ModuleDependencyInfo { const std::vector &capturedPCMArgs, const std::string &CASFileSystemRootID, const std::string &clangIncludeTreeRoot, - const std::string &moduleCacheKey) { + const std::string &moduleCacheKey, + bool IsSystem) { return ModuleDependencyInfo(std::make_unique( pcmOutputPath, mappedPCMPath, moduleMapFile, contextHash, nonPathCommandLine, fileDependencies, capturedPCMArgs, - CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey)); + CASFileSystemRootID, clangIncludeTreeRoot, moduleCacheKey, IsSystem)); } /// Describe a placeholder dependency swift module. diff --git a/include/swift/ClangImporter/ClangImporter.h b/include/swift/ClangImporter/ClangImporter.h index 01d6415d525d1..5603a928e9117 100644 --- a/include/swift/ClangImporter/ClangImporter.h +++ b/include/swift/ClangImporter/ClangImporter.h @@ -665,6 +665,11 @@ bool requiresCPlusPlus(const clang::Module *module); /// (std_vector, std_iosfwd, etc). bool isCxxStdModule(const clang::Module *module); +/// Returns true if the given module is one of the C++ standard library modules. +/// This could be the top-level std module, or any of the libc++ split modules +/// (std_vector, std_iosfwd, etc). +bool isCxxStdModule(StringRef moduleName, bool IsSystem); + /// Returns the pointee type if the given type is a C++ `const` /// reference type, `None` otherwise. std::optional diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index 7c1c042abc07a..d338cf3bf98db 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -53,6 +53,8 @@ using ContextHashIDField = IdentifierIDField; /// A bit that indicates whether or not a module is a framework using IsFrameworkField = BCFixed<1>; +/// A bit that indicates whether or not a module is a system module +using IsSystemField = BCFixed<1>; /// Arrays of various identifiers, distinguished for readability using IdentifierIDArryField = llvm::BCArray; @@ -193,7 +195,8 @@ using ClangModuleDetailsLayout = FlagIDArrayIDField, // capturedPCMArgs IdentifierIDField, // CASFileSystemRootID IdentifierIDField, // clangIncludeTreeRoot - IdentifierIDField // moduleCacheKey + IdentifierIDField, // moduleCacheKey + IsSystemField // isSystem >; } // namespace graph_block diff --git a/lib/ClangImporter/ClangImporter.cpp b/lib/ClangImporter/ClangImporter.cpp index ef7aff5927cf2..17e511ec0ce23 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7875,14 +7875,20 @@ bool importer::requiresCPlusPlus(const clang::Module *module) { } bool importer::isCxxStdModule(const clang::Module *module) { - if (module->getTopLevelModuleName() == "std") + return isCxxStdModule(module->getTopLevelModuleName(), + module->getTopLevelModule()->IsSystem); +} + +bool importer::isCxxStdModule(StringRef moduleName, bool IsSystem) { + if (moduleName == "std") return true; // In recent libc++ versions the module is split into multiple top-level // modules (std_vector, std_utility, etc). - if (module->getTopLevelModule()->IsSystem && - module->getTopLevelModuleName().starts_with("std_")) + if (IsSystem && moduleName.starts_with("std_")) { + if (moduleName == "std_errno_h") + return false; return true; - + } return false; } diff --git a/lib/ClangImporter/ClangModuleDependencyScanner.cpp b/lib/ClangImporter/ClangModuleDependencyScanner.cpp index 193ea128567fd..278d53f9762a8 100644 --- a/lib/ClangImporter/ClangModuleDependencyScanner.cpp +++ b/lib/ClangImporter/ClangModuleDependencyScanner.cpp @@ -289,7 +289,7 @@ ModuleDependencyVector ClangImporter::bridgeClangModuleDependencies( auto dependencies = ModuleDependencyInfo::forClangModule( pcmPath, mappedPCMPath, clangModuleDep.ClangModuleMapFile, clangModuleDep.ID.ContextHash, swiftArgs, fileDeps, capturedPCMArgs, - RootID, IncludeTree, /*module-cache-key*/ ""); + RootID, IncludeTree, /*module-cache-key*/ "", clangModuleDep.IsSystem); for (const auto &moduleName : clangModuleDep.ClangModuleDeps) { dependencies.addModuleImport(moduleName.ModuleName, &alreadyAddedModules); // It is safe to assume that all dependencies of a Clang module are Clang modules. diff --git a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp index 32f31dbf31bb7..aa3801c9344d1 100644 --- a/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp +++ b/lib/DependencyScan/ModuleDependencyCacheSerialization.cpp @@ -574,12 +574,12 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi cache.configureForContextHash(getContextHash()); unsigned pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID, commandLineArrayID, fileDependenciesArrayID, capturedPCMArgsArrayID, - CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID; + CASFileSystemRootID, clangIncludeTreeRootID, moduleCacheKeyID, isSystem; ClangModuleDetailsLayout::readRecord( Scratch, pcmOutputPathID, mappedPCMPathID, moduleMapPathID, contextHashID, commandLineArrayID, fileDependenciesArrayID, capturedPCMArgsArrayID, CASFileSystemRootID, clangIncludeTreeRootID, - moduleCacheKeyID); + moduleCacheKeyID, isSystem); auto pcmOutputPath = getIdentifier(pcmOutputPathID); if (!pcmOutputPath) llvm::report_fatal_error("Bad pcm output path"); @@ -615,7 +615,7 @@ bool ModuleDependenciesCacheDeserializer::readGraph(SwiftDependencyScanningServi auto moduleDep = ModuleDependencyInfo::forClangModule( *pcmOutputPath, *mappedPCMPath, *moduleMapPath, *contextHash, *commandLineArgs, *fileDependencies, *capturedPCMArgs, - *rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey); + *rootFileSystemID, *clangIncludeTreeRoot, *moduleCacheKey, isSystem); // Add dependencies of this module for (const auto &moduleName : *currentModuleImports) @@ -1064,7 +1064,7 @@ void ModuleDependenciesCacheSerializer::writeModuleInfo( getArrayID(moduleID, ModuleIdentifierArrayKind::CapturedPCMArgs), getIdentifier(clangDeps->CASFileSystemRootID), getIdentifier(clangDeps->CASClangIncludeTreeRootID), - getIdentifier(clangDeps->moduleCacheKey)); + getIdentifier(clangDeps->moduleCacheKey), clangDeps->IsSystem); break; } diff --git a/lib/DependencyScan/ModuleDependencyScanner.cpp b/lib/DependencyScan/ModuleDependencyScanner.cpp index b75ea0393f19f..0b501942dbb72 100644 --- a/lib/DependencyScan/ModuleDependencyScanner.cpp +++ b/lib/DependencyScan/ModuleDependencyScanner.cpp @@ -21,6 +21,7 @@ #include "swift/AST/TypeCheckRequests.h" #include "swift/Basic/FileTypes.h" #include "swift/Basic/PrettyStackTrace.h" +#include "swift/ClangImporter/ClangImporter.h" #include "swift/DependencyScan/ModuleDependencyScanner.h" #include "swift/Frontend/ModuleInterfaceLoader.h" #include "swift/Serialization/SerializedModuleLoader.h" @@ -763,24 +764,46 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependencies( // FIXME: Once all clients know to fetch these dependencies from // `swiftOverlayDependencies`, the goal is to no longer have them in // `directDependencies` so the following will need to go away. - directDependencies.insert({moduleName, cachedInfo->getKind()}); + directDependencies.insert({moduleName, cachedInfo->getKind()}); } else { // Cache discovered module dependencies. cache.recordDependencies(lookupResult.value()); if (!lookupResult.value().empty()) { - swiftOverlayDependencies.insert( - {moduleName, lookupResult.value()[0].first.Kind}); + swiftOverlayDependencies.insert({moduleName, lookupResult.value()[0].first.Kind}); // FIXME: Once all clients know to fetch these dependencies from // `swiftOverlayDependencies`, the goal is to no longer have them in // `directDependencies` so the following will need to go away. - directDependencies.insert( - {moduleName, lookupResult.value()[0].first.Kind}); - } + directDependencies.insert({moduleName, lookupResult.value()[0].first.Kind}); + } } } }; for (const auto &clangDep : clangDependencies) recordResult(clangDep); + + // C++ Interop requires additional handling + if (ScanCompilerInvocation.getLangOptions().EnableCXXInterop) { + for (const auto &clangDepName : clangDependencies) { + // If this Clang module is a part of the C++ stdlib, and we haven't loaded + // the overlay for it so far, it is a split libc++ module (e.g. + // std_vector). Load the CxxStdlib overlay explicitly. + const auto &clangDepInfo = + cache.findDependency(clangDepName, ModuleDependencyKind::Clang) + .value() + ->getAsClangModule(); + if (importer::isCxxStdModule(clangDepName, clangDepInfo->IsSystem) && + !swiftOverlayDependencies.contains( + {clangDepName, ModuleDependencyKind::SwiftInterface}) && + !swiftOverlayDependencies.contains( + {clangDepName, ModuleDependencyKind::SwiftBinary})) { + ScanningThreadPool.async( + scanForSwiftDependency, + getModuleImportIdentifier(ScanASTContext.Id_CxxStdlib.str())); + ScanningThreadPool.wait(); + recordResult(ScanASTContext.Id_CxxStdlib.str().str()); + } + } + } } void ModuleDependencyScanner::discoverCrossImportOverlayDependencies( From 2d86330c7f45c62055a438c615cf04b3c8c22282 Mon Sep 17 00:00:00 2001 From: Artem Chikin Date: Tue, 13 Feb 2024 14:14:28 -0800 Subject: [PATCH 3/4] Always add an implicit import of 'Cxx' module when C++ Interop is enabled. We cannot always rely on being able to do so only as an overlay query upon loading 'requires cplusplus' modulemap modules. The 'requires' statement only applies to submodules, and we may not be able to query language feature modulemap attributes in dependency scanning context. --- include/swift/Frontend/Frontend.h | 3 +++ .../swift/Serialization/SerializedModuleLoader.h | 2 +- include/swift/Strings.h | 2 ++ lib/Frontend/Frontend.cpp | 16 ++++++++++++++-- lib/Serialization/SerializedModuleLoader.cpp | 8 ++++---- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index 9cb172ef10cc9..f6ea86b7306eb 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -660,6 +660,9 @@ class CompilerInstance { /// i.e. if it can be found. bool canImportSwiftBacktracing() const; + /// Whether the Cxx library can be imported + bool canImportCxx() const; + /// Whether the CxxShim library can be imported /// i.e. if it can be found. bool canImportCxxShim() const; diff --git a/include/swift/Serialization/SerializedModuleLoader.h b/include/swift/Serialization/SerializedModuleLoader.h index 9f330634e0645..433d7136edc33 100644 --- a/include/swift/Serialization/SerializedModuleLoader.h +++ b/include/swift/Serialization/SerializedModuleLoader.h @@ -172,7 +172,7 @@ class SerializedModuleLoaderBase : public ModuleLoader { }; llvm::ErrorOr - getImportsOfModule(Twine modulePath, + getImportsOfModule(const ModuleFileSharedCore &loadedModuleFile, ModuleLoadingBehavior transitiveBehavior, StringRef packageName, bool isTestableImport); diff --git a/include/swift/Strings.h b/include/swift/Strings.h index 5e574fdc0f7f7..8538e6931a88b 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -39,6 +39,8 @@ constexpr static const StringLiteral SWIFT_BACKTRACING_NAME = "_Backtracing"; constexpr static const StringLiteral SWIFT_SHIMS_NAME = "SwiftShims"; /// The name of the CxxShim module, which contains a cxx casting utility. constexpr static const StringLiteral CXX_SHIM_NAME = "CxxShim"; +/// The name of the Cxx module, which contains C++ interop helper protocols. +constexpr static const StringLiteral CXX_MODULE_NAME = "Cxx"; /// The name of the Builtin module, which contains Builtin functions. constexpr static const StringLiteral BUILTIN_NAME = "Builtin"; /// The name of the clang imported header module. diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index edbd903a63e2e..d30fab0a397aa 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1165,6 +1165,13 @@ bool CompilerInstance::canImportSwiftBacktracing() const { return getASTContext().testImportModule(modulePath); } +bool CompilerInstance::canImportCxx() const { + ImportPath::Module::Builder builder( + getASTContext().getIdentifier(CXX_MODULE_NAME)); + auto modulePath = builder.get(); + return getASTContext().testImportModule(modulePath); +} + bool CompilerInstance::canImportCxxShim() const { ImportPath::Module::Builder builder( getASTContext().getIdentifier(CXX_SHIM_NAME)); @@ -1268,8 +1275,13 @@ ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const { } } - if (Invocation.getLangOptions().EnableCXXInterop && canImportCxxShim()) { - pushImport(CXX_SHIM_NAME, {ImportFlags::ImplementationOnly}); + if (Invocation.getLangOptions().EnableCXXInterop) { + if (imports.StdlibKind != ImplicitStdlibKind::Builtin && + Invocation.getFrontendOptions().ModuleName != CXX_MODULE_NAME && + canImportCxx()) + pushImport(CXX_MODULE_NAME); + if (canImportCxxShim()) + pushImport(CXX_SHIM_NAME, {ImportFlags::ImplementationOnly}); } imports.ShouldImportUnderlyingModule = frontendOpts.ImportUnderlyingModule; diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index 4fb3055258e42..d736a22eea631 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -392,7 +392,7 @@ std::error_code SerializedModuleLoaderBase::openModuleFile( return std::error_code(); } -SerializedModuleLoaderBase::BinaryModuleImports +llvm::ErrorOr SerializedModuleLoaderBase::getImportsOfModule( const ModuleFileSharedCore &loadedModuleFile, ModuleLoadingBehavior transitiveBehavior, StringRef packageName, @@ -478,7 +478,7 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, getImportsOfModule(*loadedModuleFile, ModuleLoadingBehavior::Optional, Ctx.LangOpts.PackageName, isTestableImport); - auto importedModuleSet = binaryModuleImports.moduleImports; + auto importedModuleSet = binaryModuleImports->moduleImports; std::vector importedModuleNames; importedModuleNames.reserve(importedModuleSet.size()); llvm::transform(importedModuleSet.keys(), @@ -487,8 +487,8 @@ SerializedModuleLoaderBase::scanModuleFile(Twine modulePath, bool isFramework, return N.str(); }); - auto importedHeader = binaryModuleImports.headerImport; - auto &importedOptionalModuleSet = binaryModuleOptionalImports.moduleImports; + auto importedHeader = binaryModuleImports->headerImport; + auto &importedOptionalModuleSet = binaryModuleOptionalImports->moduleImports; std::vector importedOptionalModuleNames; for (const auto optionalImportedModule : importedOptionalModuleSet.keys()) if (!importedModuleSet.contains(optionalImportedModule)) From 298521b87b244a6db9f3c62288458b441bdfb07b Mon Sep 17 00:00:00 2001 From: artemcm Date: Wed, 15 May 2024 14:30:23 -0400 Subject: [PATCH 4/4] Allow users to opt-out of implicit `Cxx` import with `-disable-implicit-cxx-module-import` --- include/swift/Basic/LangOptions.h | 3 +++ .../SerializedModuleDependencyCacheFormat.h | 2 +- include/swift/Frontend/Frontend.h | 3 +++ include/swift/Option/FrontendOptions.td | 4 ++++ lib/Frontend/CompilerInvocation.cpp | 3 +++ lib/Frontend/Frontend.cpp | 24 ++++++++++++++++--- lib/Frontend/ModuleInterfaceLoader.cpp | 2 ++ lib/Serialization/SerializedModuleLoader.cpp | 3 ++- .../Cxx/foreign-reference/witness-table.swift | 2 +- ...ohibit-cxx-api-in-evolving-libraries.swift | 2 +- ...x-calls-in-evolving-inlinable-bodies.swift | 2 +- 11 files changed, 42 insertions(+), 8 deletions(-) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 39bea1df6156a..1ede442d0d425 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -402,6 +402,9 @@ namespace swift { bool DisableImplicitBacktracingModuleImport = !SWIFT_IMPLICIT_BACKTRACING_IMPORT; + /// Disable the implicit import of the Cxx module. + bool DisableImplicitCxxModuleImport = false; + // Whether to use checked continuations when making an async call from // Swift into ObjC. If false, will use unchecked continuations instead. bool UseCheckedAsyncObjCBridging = false; diff --git a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h index d338cf3bf98db..f5895cf28eeb5 100644 --- a/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h +++ b/include/swift/DependencyScan/SerializedModuleDependencyCacheFormat.h @@ -40,7 +40,7 @@ using llvm::BCVBR; /// Every .moddepcache file begins with these 4 bytes, for easy identification. const unsigned char MODULE_DEPENDENCY_CACHE_FORMAT_SIGNATURE[] = {'I', 'M', 'D','C'}; const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MAJOR = - 6; // mappedPCMPath + 7; // isSystem /// Increment this on every change. const unsigned MODULE_DEPENDENCY_CACHE_FORMAT_VERSION_MINOR = 1; diff --git a/include/swift/Frontend/Frontend.h b/include/swift/Frontend/Frontend.h index f6ea86b7306eb..e8e97b06cb1fd 100644 --- a/include/swift/Frontend/Frontend.h +++ b/include/swift/Frontend/Frontend.h @@ -405,6 +405,9 @@ class CompilerInvocation { /// imported. bool shouldImportSwiftBacktracing() const; + /// Whether the CXX module should be implicitly imported. + bool shouldImportCxx() const; + /// Performs input setup common to these tools: /// sil-opt, sil-func-extractor, sil-llvm-gen, and sil-nm. /// Return value includes the buffer so caller can keep it alive. diff --git a/include/swift/Option/FrontendOptions.td b/include/swift/Option/FrontendOptions.td index bdd835be11d26..d9c15342f4d0a 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -498,6 +498,10 @@ def disable_implicit_backtracing_module_import : Flag<["-"], "disable-implicit-backtracing-module-import">, HelpText<"Disable the implicit import of the _Backtracing module.">; +def disable_implicit_cxx_module_import : Flag<["-"], + "disable-implicit-cxx-module-import">, + HelpText<"Disable the implicit import of the C++ Standard Library module.">; + def disable_arc_opts : Flag<["-"], "disable-arc-opts">, HelpText<"Don't run SIL ARC optimization passes.">; def disable_ossa_opts : Flag<["-"], "disable-ossa-opts">, diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index b79c064e0ae8d..30f749ca3e3f8 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -642,6 +642,9 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.DisableImplicitStringProcessingModuleImport |= Args.hasArg(OPT_disable_implicit_string_processing_module_import); + Opts.DisableImplicitCxxModuleImport |= + Args.hasArg(OPT_disable_implicit_cxx_module_import); + Opts.DisableImplicitBacktracingModuleImport = Args.hasFlag(OPT_disable_implicit_backtracing_module_import, OPT_enable_implicit_backtracing_module_import, diff --git a/lib/Frontend/Frontend.cpp b/lib/Frontend/Frontend.cpp index d30fab0a397aa..654fe864e5d40 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1084,6 +1084,26 @@ bool CompilerInvocation::shouldImportSwiftBacktracing() const { FrontendOptions::ParseInputMode::SwiftModuleInterface; } +bool CompilerInvocation::shouldImportCxx() const { + // C++ Interop is disabled + if (!getLangOptions().EnableCXXInterop) + return false; + // Avoid C++ stdlib when building Swift stdlib + if (getImplicitStdlibKind() == ImplicitStdlibKind::Builtin) + return false; + // Avoid importing Cxx when building Cxx itself + if (getFrontendOptions().ModuleName == CXX_MODULE_NAME) + return false; + // Cxx cannot be imported when Library evolution is enabled + if (getFrontendOptions().EnableLibraryEvolution) + return false; + // Implicit import of Cxx is disabled + if (getLangOptions().DisableImplicitCxxModuleImport) + return false; + + return true; +} + /// Implicitly import the SwiftOnoneSupport module in non-optimized /// builds. This allows for use of popular specialized functions /// from the standard library, which makes the non-optimized builds @@ -1276,9 +1296,7 @@ ImplicitImportInfo CompilerInstance::getImplicitImportInfo() const { } if (Invocation.getLangOptions().EnableCXXInterop) { - if (imports.StdlibKind != ImplicitStdlibKind::Builtin && - Invocation.getFrontendOptions().ModuleName != CXX_MODULE_NAME && - canImportCxx()) + if (Invocation.shouldImportCxx() && canImportCxx()) pushImport(CXX_MODULE_NAME); if (canImportCxxShim()) pushImport(CXX_SHIM_NAME, {ImportFlags::ImplementationOnly}); diff --git a/lib/Frontend/ModuleInterfaceLoader.cpp b/lib/Frontend/ModuleInterfaceLoader.cpp index b3196c3637cd1..85bed118fcf58 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1985,6 +1985,8 @@ InterfaceSubContextDelegateImpl::InterfaceSubContextDelegateImpl( compatVersion = "default"; else if (langOpts.cxxInteropCompatVersion[0] == 5) compatVersion = "swift-5.9"; + else if (langOpts.cxxInteropCompatVersion[0] == 6) + compatVersion = "swift-6"; else if (langOpts.cxxInteropCompatVersion[0] == version::getUpcomingCxxInteropCompatVersion()) compatVersion = "upcoming-swift"; diff --git a/lib/Serialization/SerializedModuleLoader.cpp b/lib/Serialization/SerializedModuleLoader.cpp index d736a22eea631..62d0de51da0f7 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1023,7 +1023,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST( if (M.hasCxxInteroperability() && M.getResilienceStrategy() != ResilienceStrategy::Resilient && !Ctx.LangOpts.EnableCXXInterop && - Ctx.LangOpts.RequireCxxInteropToImportCxxInteropModule) { + Ctx.LangOpts.RequireCxxInteropToImportCxxInteropModule && + M.getName().str() != CXX_MODULE_NAME) { auto loc = diagLoc.value_or(SourceLoc()); Ctx.Diags.diagnose(loc, diag::need_cxx_interop_to_import_module, M.getName()); diff --git a/test/Interop/Cxx/foreign-reference/witness-table.swift b/test/Interop/Cxx/foreign-reference/witness-table.swift index 62073bd4de8d3..ec30a494cdc5e 100644 --- a/test/Interop/Cxx/foreign-reference/witness-table.swift +++ b/test/Interop/Cxx/foreign-reference/witness-table.swift @@ -1,4 +1,4 @@ -// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none -Xfrontend -disable-llvm-verify -Xfrontend -disable-availability-checking -g) +// RUN: %target-run-simple-swift(-I %S/Inputs/ -Xfrontend -enable-experimental-cxx-interop -Xfrontend -validate-tbd-against-ir=none -Xfrontend -disable-llvm-verify -Xfrontend -disable-availability-checking -Xfrontend -disable-implicit-cxx-module-import -g) // // REQUIRES: executable_test // XFAIL: OS=windows-msvc diff --git a/test/Interop/Cxx/library-evolution/prohibit-cxx-api-in-evolving-libraries.swift b/test/Interop/Cxx/library-evolution/prohibit-cxx-api-in-evolving-libraries.swift index 01ce4791e0e8b..9356ec7dc9cfd 100644 --- a/test/Interop/Cxx/library-evolution/prohibit-cxx-api-in-evolving-libraries.swift +++ b/test/Interop/Cxx/library-evolution/prohibit-cxx-api-in-evolving-libraries.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: split-file %s %t -// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -typecheck -enable-library-evolution -enable-experimental-cxx-interop -disable-availability-checking -verify +// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -typecheck -enable-library-evolution -enable-experimental-cxx-interop -disable-availability-checking -disable-implicit-cxx-module-import -verify //--- Inputs/module.modulemap module CxxModule { diff --git a/test/Interop/Cxx/library-evolution/prohibit-cxx-calls-in-evolving-inlinable-bodies.swift b/test/Interop/Cxx/library-evolution/prohibit-cxx-calls-in-evolving-inlinable-bodies.swift index 8bc8daf3e7630..43ea0c0767827 100644 --- a/test/Interop/Cxx/library-evolution/prohibit-cxx-calls-in-evolving-inlinable-bodies.swift +++ b/test/Interop/Cxx/library-evolution/prohibit-cxx-calls-in-evolving-inlinable-bodies.swift @@ -1,6 +1,6 @@ // RUN: %empty-directory(%t) // RUN: split-file %s %t -// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -typecheck -enable-library-evolution -enable-experimental-cxx-interop -verify +// RUN: %target-swift-frontend %t/test.swift -I %t/Inputs -typecheck -enable-library-evolution -enable-experimental-cxx-interop -disable-implicit-cxx-module-import -verify //--- Inputs/module.modulemap module CxxModule {