From bc17581ae67b33a23a3c0b11f3c902e4decbeb21 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 28cc513d1212f..eae6876af861e 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 c371a839f5bdd..8523749e93436 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1971,6 +1971,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 43a68938266c1..e020fe0efef2f 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 eb1c0e71d875231484da0cc8a03a06a704d1bb5d 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 c3d6bae702397..b6987b3c77277 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 5d0d7783bbcd0..9402dfcf02dd8 100644 --- a/lib/ClangImporter/ClangImporter.cpp +++ b/lib/ClangImporter/ClangImporter.cpp @@ -7894,14 +7894,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 402e6cf651142..40fc98135e6b7 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" @@ -774,24 +775,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 6ea604bf9fd665e1df5618fe043134b08c1ba933 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 b824bf1c220b8..f0f4fe853ec7b 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1175,6 +1175,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)); @@ -1278,8 +1285,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 e020fe0efef2f..978bb819fa397 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, @@ -484,7 +484,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(), @@ -493,8 +493,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 ec4e0e23aa702487424e563f32b0b04547009a96 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 ++- ...ohibit-cxx-api-in-evolving-libraries.swift | 2 +- ...x-calls-in-evolving-inlinable-bodies.swift | 2 +- 10 files changed, 41 insertions(+), 7 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 f561948d71abd..f528e282fe4f2 100644 --- a/include/swift/Option/FrontendOptions.td +++ b/include/swift/Option/FrontendOptions.td @@ -502,6 +502,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 eae6876af861e..06b48e2ab2f04 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -637,6 +637,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 f0f4fe853ec7b..a9e5c7b7c9ddc 100644 --- a/lib/Frontend/Frontend.cpp +++ b/lib/Frontend/Frontend.cpp @@ -1094,6 +1094,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 @@ -1286,9 +1306,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 8523749e93436..da842625b9daa 100644 --- a/lib/Frontend/ModuleInterfaceLoader.cpp +++ b/lib/Frontend/ModuleInterfaceLoader.cpp @@ -1987,6 +1987,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 978bb819fa397..c7a1e761c0a03 100644 --- a/lib/Serialization/SerializedModuleLoader.cpp +++ b/lib/Serialization/SerializedModuleLoader.cpp @@ -1031,7 +1031,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/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 {