Skip to content

Commit 10b52e9

Browse files
committed
[cxx-interop] compilations that do not enable C++ interoperability should not be able to import modules that do enable C++ interoperability by default
A supplemental hidden frontend option allows advanced users to opt-out of this requirement. Fixes #65833 Fixes #65832
1 parent f3cabc5 commit 10b52e9

18 files changed

+97
-7
lines changed

include/swift/AST/Decl.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
659659
HasAnyUnavailableValues : 1
660660
);
661661

662-
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
662+
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
663663
/// If the module is compiled as static library.
664664
StaticLibrary : 1,
665665

@@ -709,7 +709,10 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
709709

710710
/// If the map from @objc provided name to top level swift::Decl in this
711711
/// module is populated
712-
ObjCNameLookupCachePopulated : 1
712+
ObjCNameLookupCachePopulated : 1,
713+
714+
/// Whether this module has been built with C++ interoperability enabled.
715+
HasCxxInteroperability : 1
713716
);
714717

715718
SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,

include/swift/AST/DiagnosticsSema.def

+6
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,12 @@ ERROR(need_hermetic_seal_to_import_module,none,
874874
"module %0 was built with -experimental-hermetic-seal-at-link, but "
875875
"current compilation does not have -experimental-hermetic-seal-at-link",
876876
(Identifier))
877+
ERROR(need_cxx_interop_to_import_module,none,
878+
"module %0 was built with C++ interoperability enabled, but "
879+
"current compilation does not enable C++ interoperability",
880+
(Identifier))
881+
NOTE(enable_cxx_interop_docs,none,
882+
"visit https://www.swift.org/documentation/cxx-interop/project-build-setup to learn how to enable C++ interoperability", ())
877883

878884
ERROR(modularization_issue_decl_moved,Fatal,
879885
"reference to %select{top-level|type}0 %1 broken by a context change; "

include/swift/AST/Module.h

+8
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,14 @@ class ModuleDecl
654654
Bits.ModuleDecl.HasHermeticSealAtLink = enabled;
655655
}
656656

657+
/// Returns true if this module was built with C++ interoperability enabled.
658+
bool hasCxxInteroperability() const {
659+
return Bits.ModuleDecl.HasCxxInteroperability;
660+
}
661+
void setHasCxxInteroperability(bool enabled = true) {
662+
Bits.ModuleDecl.HasCxxInteroperability = enabled;
663+
}
664+
657665
/// \returns true if this module is a system module; note that the StdLib is
658666
/// considered a system module.
659667
bool isSystemModule() const {

include/swift/Basic/LangOptions.h

+4
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ namespace swift {
313313
/// Imports getters and setters as computed properties.
314314
bool CxxInteropGettersSettersAsProperties = false;
315315

316+
/// Should the compiler require C++ interoperability to be enabled
317+
/// when importing Swift modules that enable C++ interoperability.
318+
bool RequireCxxInteropToImportCxxInteropModule = true;
319+
316320
/// On Darwin platforms, use the pre-stable ABI's mark bit for Swift
317321
/// classes instead of the stable ABI's bit. This is needed when
318322
/// targeting OSes prior to macOS 10.14.4 and iOS 12.2, where

include/swift/Option/FrontendOptions.td

+5
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,11 @@ def cxx_interop_getters_setters_as_properties :
865865
HelpText<"Import getters and setters as computed properties in Swift">,
866866
Flags<[FrontendOption, HelpHidden]>;
867867

868+
def cxx_interop_disable_requirement_at_import :
869+
Flag<["-"], "disable-cxx-interop-requirement-at-import">,
870+
HelpText<"Do not require C++ interoperability to be enabled when importing a Swift module that enables C++ interoperability">,
871+
Flags<[FrontendOption, HelpHidden]>;
872+
868873
def use_malloc : Flag<["-"], "use-malloc">,
869874
HelpText<"Allocate internal data structures using malloc "
870875
"(for memory debugging)">;

include/swift/Serialization/Validation.h

+5
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class ExtendedValidationInfo {
131131
unsigned IsBuiltFromInterface : 1;
132132
unsigned IsAllowModuleWithCompilerErrorsEnabled : 1;
133133
unsigned IsConcurrencyChecked : 1;
134+
unsigned HasCxxInteroperability : 1;
134135
} Bits;
135136
public:
136137
ExtendedValidationInfo() : Bits() {}
@@ -232,6 +233,10 @@ class ExtendedValidationInfo {
232233
void setIsConcurrencyChecked(bool val = true) {
233234
Bits.IsConcurrencyChecked = val;
234235
}
236+
bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; }
237+
void setHasCxxInteroperability(bool val) {
238+
Bits.HasCxxInteroperability = val;
239+
}
235240
};
236241

237242
struct SearchPath {

lib/AST/Module.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
646646
Bits.ModuleDecl.HasHermeticSealAtLink = 0;
647647
Bits.ModuleDecl.IsConcurrencyChecked = 0;
648648
Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0;
649+
Bits.ModuleDecl.HasCxxInteroperability = 0;
649650
}
650651

651652
void ModuleDecl::setIsSystemModule(bool flag) {

lib/Frontend/CompilerInvocation.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
10431043
Args.hasArg(OPT_experimental_c_foreign_reference_types);
10441044

10451045
Opts.CxxInteropGettersSettersAsProperties = Args.hasArg(OPT_cxx_interop_getters_setters_as_properties);
1046+
Opts.RequireCxxInteropToImportCxxInteropModule =
1047+
!Args.hasArg(OPT_cxx_interop_disable_requirement_at_import);
10461048

10471049
Opts.VerifyAllSubstitutionMaps |= Args.hasArg(OPT_verify_all_substitution_maps);
10481050

lib/Frontend/Frontend.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,8 @@ ModuleDecl *CompilerInstance::getMainModule() const {
13191319
MainModule->setResilienceStrategy(ResilienceStrategy::Resilient);
13201320
if (Invocation.getLangOptions().isSwiftVersionAtLeast(6))
13211321
MainModule->setIsConcurrencyChecked(true);
1322+
if (Invocation.getLangOptions().EnableCXXInterop)
1323+
MainModule->setHasCxxInteroperability();
13221324

13231325
// Register the main module with the AST context.
13241326
Context->addLoadedModule(MainModule);

lib/Serialization/ModuleFile.h

+5
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,11 @@ class ModuleFile
621621
return Core->Bits.HasHermeticSealAtLink;
622622
}
623623

624+
/// Whether this module was built with C++ interoperability enabled.
625+
bool hasCxxInteroperability() const {
626+
return Core->Bits.HasCxxInteroperability;
627+
}
628+
624629
/// Whether the module is resilient. ('-enable-library-evolution')
625630
ResilienceStrategy getResilienceStrategy() const {
626631
return ResilienceStrategy(Core->Bits.ResilienceStrategy);

lib/Serialization/ModuleFileSharedCore.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
181181
case options_block::MODULE_EXPORT_AS_NAME:
182182
extendedInfo.setExportAsName(blobData);
183183
break;
184+
case options_block::HAS_CXX_INTEROPERABILITY_ENABLED:
185+
extendedInfo.setHasCxxInteroperability(true);
186+
break;
184187
default:
185188
// Unknown options record, possibly for use by a future version of the
186189
// module format.
@@ -1378,6 +1381,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
13781381
Bits.IsAllowModuleWithCompilerErrorsEnabled =
13791382
extInfo.isAllowModuleWithCompilerErrorsEnabled();
13801383
Bits.IsConcurrencyChecked = extInfo.isConcurrencyChecked();
1384+
Bits.HasCxxInteroperability = extInfo.hasCxxInteroperability();
13811385
MiscVersion = info.miscVersion;
13821386
ModuleABIName = extInfo.getModuleABIName();
13831387
ModulePackageName = extInfo.getModulePackageName();

lib/Serialization/ModuleFileSharedCore.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -386,8 +386,11 @@ class ModuleFileSharedCore {
386386
/// \c true if this module was built with complete checking for concurrency.
387387
unsigned IsConcurrencyChecked: 1;
388388

389+
/// Whether this module is built with C++ interoperability enabled.
390+
unsigned HasCxxInteroperability : 1;
391+
389392
// Explicitly pad out to the next word boundary.
390-
unsigned : 4;
393+
unsigned : 3;
391394
} Bits = {};
392395
static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small");
393396

lib/Serialization/ModuleFormat.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5858
/// describe what change you made. The content of this comment isn't important;
5959
/// it just ensures a conflict if two people change the module format.
6060
/// Don't worry about adhering to the 80-column limit for this line.
61-
const uint16_t SWIFTMODULE_VERSION_MINOR = 790; // add `out` kind to mark uninitialized instruction
61+
const uint16_t SWIFTMODULE_VERSION_MINOR = 791; // HasCxxInteroperability
6262

6363
/// A standard hash seed used for all string hashes in a serialized module.
6464
///
@@ -888,6 +888,7 @@ namespace options_block {
888888
EXTERNAL_SEARCH_PLUGIN_PATH,
889889
COMPILER_PLUGIN_LIBRARY_PATH,
890890
COMPILER_PLUGIN_EXECUTABLE_PATH,
891+
HAS_CXX_INTEROPERABILITY_ENABLED,
891892
};
892893

893894
using SDKPathLayout = BCRecordLayout<
@@ -976,6 +977,10 @@ namespace options_block {
976977
MODULE_EXPORT_AS_NAME,
977978
BCBlob
978979
>;
980+
981+
using HasCxxInteroperabilityEnabledLayout = BCRecordLayout<
982+
HAS_CXX_INTEROPERABILITY_ENABLED
983+
>;
979984
}
980985

981986
/// The record types within the input block.

lib/Serialization/Serialization.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1090,6 +1090,12 @@ void Serializer::writeHeader(const SerializationOptions &options) {
10901090
IsConcurrencyChecked.emit(ScratchRecord);
10911091
}
10921092

1093+
if (M->hasCxxInteroperability()) {
1094+
options_block::HasCxxInteroperabilityEnabledLayout
1095+
CxxInteroperabilityEnabled(Out);
1096+
CxxInteroperabilityEnabled.emit(ScratchRecord);
1097+
}
1098+
10931099
if (options.SerializeOptionsForDebugging) {
10941100
options_block::SDKPathLayout SDKPath(Out);
10951101
options_block::XCCLayout XCC(Out);

lib/Serialization/SerializedModuleLoader.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
824824
M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName()));
825825
if (loadedModuleFile->isConcurrencyChecked())
826826
M.setIsConcurrencyChecked();
827+
if (loadedModuleFile->hasCxxInteroperability())
828+
M.setHasCxxInteroperability();
827829
if (!loadedModuleFile->getModulePackageName().empty()) {
828830
M.setPackageName(Ctx.getIdentifier(loadedModuleFile->getModulePackageName()));
829831
}
@@ -896,6 +898,19 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
896898
diag::need_hermetic_seal_to_import_module, M.getName());
897899
}
898900

901+
// Non-resilient modules built with C++ interoperability enabled
902+
// are typically incompatible with clients that do not enable
903+
// C++ interoperability.
904+
if (M.hasCxxInteroperability() &&
905+
M.getResilienceStrategy() != ResilienceStrategy::Resilient &&
906+
!Ctx.LangOpts.EnableCXXInterop &&
907+
Ctx.LangOpts.RequireCxxInteropToImportCxxInteropModule) {
908+
auto loc = diagLoc.value_or(SourceLoc());
909+
Ctx.Diags.diagnose(loc, diag::need_cxx_interop_to_import_module,
910+
M.getName());
911+
Ctx.Diags.diagnose(loc, diag::enable_cxx_interop_docs);
912+
}
913+
899914
return fileUnit;
900915
}
901916

test/Interop/Cxx/implementation-only-imports/import-implementation-only-cxx-interop-module-without-interop.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend %S/Inputs/use-module-a-impl-only.swift -I %S/Inputs/ -module-name UseModuleAImplOnly -emit-module -emit-module-path %t/UseModuleAImplOnly.swiftmodule -cxx-interoperability-mode=default
3+
// RUN: %target-swift-frontend %S/Inputs/use-module-a-impl-only.swift -I %S/Inputs/ -module-name UseModuleAImplOnly -emit-module -emit-module-path %t/UseModuleAImplOnly.swiftmodule -cxx-interoperability-mode=default -enable-library-evolution
44

55
// RUN: %target-swift-frontend %s -typecheck -module-name TestMod -I %t -I %S/Inputs
66

77
// Check that we have used something from CxxShim in 'UseModuleAImplOnly'
8-
// RUN: %target-swift-frontend %S/Inputs/use-module-a-impl-only.swift -I %S/Inputs/ -module-name UseModuleAImplOnly -emit-module -emit-module-path %t/UseModuleAImplOnly.swiftmodule -cxx-interoperability-mode=default -emit-sil -o - | %FileCheck %s
8+
// RUN: %target-swift-frontend %S/Inputs/use-module-a-impl-only.swift -I %S/Inputs/ -module-name UseModuleAImplOnly -emit-module -emit-module-path %t/UseModuleAImplOnly.swiftmodule -cxx-interoperability-mode=default -emit-sil -o - -enable-library-evolution | %FileCheck %s
99
// CHECK: __swift_interopStaticCast
1010

1111
import UseModuleAImplOnly

test/Interop/Cxx/implementation-only-imports/import-implementation-only-cxxstdlib-interop-module-without-interop.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22

3-
// RUN: %target-swift-frontend %S/Inputs/use-cxx-stdlib-impl-only.swift -I %S/Inputs/ -module-name UseCxxStdlibImplOnly -emit-module -emit-module-path %t/UseCxxStdlibImplOnly.swiftmodule -cxx-interoperability-mode=default
3+
// RUN: %target-swift-frontend %S/Inputs/use-cxx-stdlib-impl-only.swift -I %S/Inputs/ -module-name UseCxxStdlibImplOnly -emit-module -emit-module-path %t/UseCxxStdlibImplOnly.swiftmodule -cxx-interoperability-mode=default -enable-library-evolution
44

55
// RUN: %target-swift-frontend %s -typecheck -module-name TestMod -I %t -I %S/Inputs
66

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend %s -module-name UsesCxxInterop -emit-module -emit-module-path %t/UsesCxxInterop.swiftmodule -cxx-interoperability-mode=default
4+
5+
// RUN: %target-swift-frontend %s -D USE -typecheck -module-name TestMod -I %t -verify
6+
7+
// RUN: %target-swift-frontend %s -D USE -typecheck -module-name TestMod -I %t -disable-cxx-interop-requirement-at-import
8+
9+
#if USE
10+
import UsesCxxInterop // expected-error {{module 'UsesCxxInterop' was built with C++ interoperability enabled, but current compilation does not enable C++ interoperability}}
11+
// expected-note@-1 {{visit https://www.swift.org/documentation/cxx-interop/project-build-setup to learn how to enable C++ interoperability}}
12+
13+
#else
14+
public func testFun() { }
15+
16+
#endif

0 commit comments

Comments
 (0)