Hard-code the 'Darwin' module as having been built without C++ interop

Textual interfaces for 'Darwin' built with recent compilers specify that it is built witout C++ interop enabled. However, to ensure compatibility with versions of the 'Darwin' module built with older compilers, we hard-code this fact. This is required to break the module cycle that occurs when building the 'Darwin' module with C++ interop enabled, where the underlying 'Darwin' clang module depends on C++ standard library for which the compiler brings in the 'CxxStdlib' Swift overlay, which depends on 'Darwin'.
This commit is contained in:
Artem Chikin
2025-05-29 16:47:00 -07:00
parent 20b38687c5
commit 5749ef3c14
7 changed files with 68 additions and 8 deletions

View File

@@ -45,6 +45,7 @@ namespace swift {
struct DiagnosticBehavior;
class DiagnosticEngine;
class FrontendOptions;
/// Kind of implicit platform conditions.
enum class PlatformConditionKind {
@@ -339,7 +340,8 @@ namespace swift {
std::optional<version::Version> FormalCxxInteropMode;
void setCxxInteropFromArgs(llvm::opt::ArgList &Args,
swift::DiagnosticEngine &Diags);
swift::DiagnosticEngine &Diags,
const FrontendOptions &FrontendOpts);
/// The C++ standard library used for the current build. This can differ
/// from the default C++ stdlib on a particular platform when `-Xcc

View File

@@ -1479,7 +1479,13 @@ void ModuleDependencyScanner::resolveSwiftOverlayDependenciesForModule(
// If the textual interface was built without C++ interop, do not query
// the C++ Standard Library Swift overlay for its compilation.
if (llvm::find(commandLine, "-formal-cxx-interoperability-mode=off") ==
//
// 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()) {
for (const auto &clangDepName : allClangDependencies) {
// If this Clang module is a part of the C++ stdlib, and we haven't

View File

@@ -214,7 +214,8 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
Options.AvailabilityIsBlockList = A->getOption().matches(OPT_block_availability_platforms);
}
Invocation.getLangOptions().setCxxInteropFromArgs(ParsedArgs, Diags);
Invocation.getLangOptions().setCxxInteropFromArgs(ParsedArgs, Diags,
Invocation.getFrontendOptions());
std::string InstanceSetupError;
if (CI.setup(Invocation, InstanceSetupError)) {

View File

@@ -133,7 +133,8 @@ int swift_synthesize_interface_main(ArrayRef<const char *> Args,
Invocation.setImportSearchPaths(ImportSearchPaths);
Invocation.getLangOptions().EnableObjCInterop = Target.isOSDarwin();
Invocation.getLangOptions().setCxxInteropFromArgs(ParsedArgs, Diags);
Invocation.getLangOptions().setCxxInteropFromArgs(ParsedArgs, Diags,
Invocation.getFrontendOptions());
std::string ModuleCachePath = "";
if (auto *A = ParsedArgs.getLastArg(OPT_module_cache_path)) {

View File

@@ -680,7 +680,8 @@ static void diagnoseCxxInteropCompatMode(Arg *verArg, ArgList &Args,
}
void LangOptions::setCxxInteropFromArgs(ArgList &Args,
swift::DiagnosticEngine &Diags) {
swift::DiagnosticEngine &Diags,
const FrontendOptions &FrontendOpts) {
if (Arg *A = Args.getLastArg(options::OPT_cxx_interoperability_mode)) {
if (Args.hasArg(options::OPT_enable_experimental_cxx_interop)) {
Diags.diagnose(SourceLoc(), diag::dont_enable_interop_and_compat);
@@ -735,7 +736,12 @@ void LangOptions::setCxxInteropFromArgs(ArgList &Args,
// version, and is either 4, 5, 6, or 7 (even though only 5.9 and 6.* make
// any sense). For now, we don't actually care about the version, so we'll
// just use version 6 (i.e., 'swift-6') to mean that C++ interop mode is on.
if (EnableCXXInterop)
//
// 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 (EnableCXXInterop && (FrontendOpts.ModuleName.compare("Darwin") != 0))
FormalCxxInteropMode = {6};
else
FormalCxxInteropMode = std::nullopt;
@@ -1558,7 +1564,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
if (const Arg *A = Args.getLastArg(OPT_clang_target_variant))
Opts.ClangTargetVariant = llvm::Triple(A->getValue());
Opts.setCxxInteropFromArgs(Args, Diags);
Opts.setCxxInteropFromArgs(Args, Diags, FrontendOpts);
if (!Args.hasArg(options::OPT_formal_cxx_interoperability_mode))
ModuleInterfaceOpts.PublicFlags.IgnorableFlags +=
" " + printFormalCxxInteropVersion(Opts);

View File

@@ -6,9 +6,14 @@
// RUN: %target-swift-frontend -typecheck %t/clientWithInteropDep.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -module-cache-path %t/module-cache &> %t/interop_dep.txt
// RUN: cat %t/interop_dep.txt | %FileCheck %s -check-prefix=ENABLE-CHECK
// RUN: %target-swift-frontend -typecheck -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 -module-cache-path %t/module-cache &> %t/no_interop_dep.txt
// RUN: %empty-directory(%t/module-cache)
// RUN: %target-swift-frontend -typecheck %t/clientNoInteropDep.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -module-cache-path %t/module-cache &> %t/no_interop_dep.txt
// RUN: cat %t/no_interop_dep.txt | %FileCheck %s -check-prefix=DISABLE-CHECK
// RUN: %empty-directory(%t/module-cache)
// RUN: %target-swift-frontend -typecheck %t/clientDarwin.swift -I %t/deps -cxx-interoperability-mode=default -disable-implicit-string-processing-module-import -disable-implicit-concurrency-module-import -module-cache-path %t/module-cache &> %t/darwin_dep.txt
// RUN: cat %t/darwin_dep.txt | %FileCheck %s -check-prefix=DISABLE-CHECK
// ENABLE-CHECK: remark: loaded module 'CxxStdlib' (overlay for a clang dependency)
// DISABLE-CHECK-NOT: remark: loaded module 'CxxStdlib' (overlay for a clang dependency)
@@ -43,9 +48,19 @@ public struct Foo1 {}
import Bar
public struct Foo2 {}
//--- deps/Darwin.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Darwin -enable-library-evolution
// swift-module-flags-ignorable: -Rmodule-loading
import Bar
public struct Foo2 {}
//--- clientWithInteropDep.swift
import Foo
//--- clientNoInteropDep.swift
import FooNoInterop
//--- clientDarwin.swift
import Darwin

View File

@@ -8,6 +8,9 @@
// 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 -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);
@@ -30,12 +33,21 @@ public struct Foo1 {}
import std_Bar
public struct Foo2 {}
//--- deps/Darwin.swiftinterface
// swift-interface-format-version: 1.0
// swift-module-flags: -module-name Darwin -enable-library-evolution
import std_Bar
public struct Foo3 {}
//--- clientWithInteropDep.swift
import Foo
//--- clientNoInteropDep.swift
import FooNoInterop
//--- clientDarwin.swift
import Darwin
// Ensure that when the 'Foo' dependency was built with C++ interop enabled,
// it gets the C++ standard library overlay for its 'std_*' dependency
//
@@ -75,4 +87,21 @@ import FooNoInterop
// 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"
// DARWIN-CHECK: "directDependencies": [
// DARWIN-CHECK: {
// DARWIN-CHECK: "swift": "SwiftOnoneSupport"
// DARWIN-CHECK: },
// DARWIN-CHECK: {
// DARWIN-CHECK: "clang": "std_Bar"
// DARWIN-CHECK: }
// DARWIN-CHECK: ],