Skip to content

[cxx-interop] compilations that do not enable C++ interoperability sh… #66474

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
HasAnyUnavailableValues : 1
);

SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
SWIFT_INLINE_BITFIELD(ModuleDecl, TypeDecl, 1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1,
/// If the module is compiled as static library.
StaticLibrary : 1,

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

/// If the map from @objc provided name to top level swift::Decl in this
/// module is populated
ObjCNameLookupCachePopulated : 1
ObjCNameLookupCachePopulated : 1,

/// Whether this module has been built with C++ interoperability enabled.
HasCxxInteroperability : 1
);

SWIFT_INLINE_BITFIELD(PrecedenceGroupDecl, Decl, 1+2,
Expand Down
6 changes: 6 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,12 @@ ERROR(need_hermetic_seal_to_import_module,none,
"module %0 was built with -experimental-hermetic-seal-at-link, but "
"current compilation does not have -experimental-hermetic-seal-at-link",
(Identifier))
ERROR(need_cxx_interop_to_import_module,none,
"module %0 was built with C++ interoperability enabled, but "
"current compilation does not enable C++ interoperability",
(Identifier))
NOTE(enable_cxx_interop_docs,none,
"visit https://www.swift.org/documentation/cxx-interop/project-build-setup to learn how to enable C++ interoperability", ())

ERROR(modularization_issue_decl_moved,Fatal,
"reference to %select{top-level declaration|type}0 %1 broken by a context change; "
Expand Down
8 changes: 8 additions & 0 deletions include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,14 @@ class ModuleDecl
Bits.ModuleDecl.HasHermeticSealAtLink = enabled;
}

/// Returns true if this module was built with C++ interoperability enabled.
bool hasCxxInteroperability() const {
return Bits.ModuleDecl.HasCxxInteroperability;
}
void setHasCxxInteroperability(bool enabled = true) {
Bits.ModuleDecl.HasCxxInteroperability = enabled;
}

/// \returns true if this module is a system module; note that the StdLib is
/// considered a system module.
bool isSystemModule() const {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,10 @@ namespace swift {
/// Imports getters and setters as computed properties.
bool CxxInteropGettersSettersAsProperties = false;

/// Should the compiler require C++ interoperability to be enabled
/// when importing Swift modules that enable C++ interoperability.
bool RequireCxxInteropToImportCxxInteropModule = true;

/// On Darwin platforms, use the pre-stable ABI's mark bit for Swift
/// classes instead of the stable ABI's bit. This is needed when
/// targeting OSes prior to macOS 10.14.4 and iOS 12.2, where
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/FrontendOptions.td
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,11 @@ def cxx_interop_getters_setters_as_properties :
HelpText<"Import getters and setters as computed properties in Swift">,
Flags<[FrontendOption, HelpHidden]>;

def cxx_interop_disable_requirement_at_import :
Flag<["-"], "disable-cxx-interop-requirement-at-import">,
HelpText<"Do not require C++ interoperability to be enabled when importing a Swift module that enables C++ interoperability">,
Flags<[FrontendOption, HelpHidden]>;

def use_malloc : Flag<["-"], "use-malloc">,
HelpText<"Allocate internal data structures using malloc "
"(for memory debugging)">;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Serialization/Validation.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class ExtendedValidationInfo {
unsigned IsBuiltFromInterface : 1;
unsigned IsAllowModuleWithCompilerErrorsEnabled : 1;
unsigned IsConcurrencyChecked : 1;
unsigned HasCxxInteroperability : 1;
} Bits;
public:
ExtendedValidationInfo() : Bits() {}
Expand Down Expand Up @@ -232,6 +233,10 @@ class ExtendedValidationInfo {
void setIsConcurrencyChecked(bool val = true) {
Bits.IsConcurrencyChecked = val;
}
bool hasCxxInteroperability() const { return Bits.HasCxxInteroperability; }
void setHasCxxInteroperability(bool val) {
Bits.HasCxxInteroperability = val;
}
};

struct SearchPath {
Expand Down
1 change: 1 addition & 0 deletions lib/AST/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ ModuleDecl::ModuleDecl(Identifier name, ASTContext &ctx,
Bits.ModuleDecl.HasHermeticSealAtLink = 0;
Bits.ModuleDecl.IsConcurrencyChecked = 0;
Bits.ModuleDecl.ObjCNameLookupCachePopulated = 0;
Bits.ModuleDecl.HasCxxInteroperability = 0;
}

void ModuleDecl::setIsSystemModule(bool flag) {
Expand Down
2 changes: 2 additions & 0 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1043,6 +1043,8 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Args.hasArg(OPT_experimental_c_foreign_reference_types);

Opts.CxxInteropGettersSettersAsProperties = Args.hasArg(OPT_cxx_interop_getters_setters_as_properties);
Opts.RequireCxxInteropToImportCxxInteropModule =
!Args.hasArg(OPT_cxx_interop_disable_requirement_at_import);

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

Expand Down
3 changes: 3 additions & 0 deletions lib/Frontend/Frontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,9 @@ ModuleDecl *CompilerInstance::getMainModule() const {
MainModule->setResilienceStrategy(ResilienceStrategy::Resilient);
if (Invocation.getLangOptions().isSwiftVersionAtLeast(6))
MainModule->setIsConcurrencyChecked(true);
if (Invocation.getLangOptions().EnableCXXInterop &&
Invocation.getLangOptions().RequireCxxInteropToImportCxxInteropModule)
MainModule->setHasCxxInteroperability();

// Register the main module with the AST context.
Context->addLoadedModule(MainModule);
Expand Down
5 changes: 5 additions & 0 deletions lib/Serialization/ModuleFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,11 @@ class ModuleFile
return Core->Bits.HasHermeticSealAtLink;
}

/// Whether this module was built with C++ interoperability enabled.
bool hasCxxInteroperability() const {
return Core->Bits.HasCxxInteroperability;
}

/// Whether the module is resilient. ('-enable-library-evolution')
ResilienceStrategy getResilienceStrategy() const {
return ResilienceStrategy(Core->Bits.ResilienceStrategy);
Expand Down
4 changes: 4 additions & 0 deletions lib/Serialization/ModuleFileSharedCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ static bool readOptionsBlock(llvm::BitstreamCursor &cursor,
case options_block::MODULE_EXPORT_AS_NAME:
extendedInfo.setExportAsName(blobData);
break;
case options_block::HAS_CXX_INTEROPERABILITY_ENABLED:
extendedInfo.setHasCxxInteroperability(true);
break;
default:
// Unknown options record, possibly for use by a future version of the
// module format.
Expand Down Expand Up @@ -1378,6 +1381,7 @@ ModuleFileSharedCore::ModuleFileSharedCore(
Bits.IsAllowModuleWithCompilerErrorsEnabled =
extInfo.isAllowModuleWithCompilerErrorsEnabled();
Bits.IsConcurrencyChecked = extInfo.isConcurrencyChecked();
Bits.HasCxxInteroperability = extInfo.hasCxxInteroperability();
MiscVersion = info.miscVersion;
ModuleABIName = extInfo.getModuleABIName();
ModulePackageName = extInfo.getModulePackageName();
Expand Down
5 changes: 4 additions & 1 deletion lib/Serialization/ModuleFileSharedCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,8 +386,11 @@ class ModuleFileSharedCore {
/// \c true if this module was built with complete checking for concurrency.
unsigned IsConcurrencyChecked: 1;

/// Whether this module is built with C++ interoperability enabled.
unsigned HasCxxInteroperability : 1;

// Explicitly pad out to the next word boundary.
unsigned : 4;
unsigned : 3;
} Bits = {};
static_assert(sizeof(ModuleBits) <= 8, "The bit set should be small");

Expand Down
7 changes: 6 additions & 1 deletion lib/Serialization/ModuleFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
/// describe what change you made. The content of this comment isn't important;
/// it just ensures a conflict if two people change the module format.
/// Don't worry about adhering to the 80-column limit for this line.
const uint16_t SWIFTMODULE_VERSION_MINOR = 790; // add `out` kind to mark uninitialized instruction
const uint16_t SWIFTMODULE_VERSION_MINOR = 791; // HasCxxInteroperability

/// A standard hash seed used for all string hashes in a serialized module.
///
Expand Down Expand Up @@ -888,6 +888,7 @@ namespace options_block {
EXTERNAL_SEARCH_PLUGIN_PATH,
COMPILER_PLUGIN_LIBRARY_PATH,
COMPILER_PLUGIN_EXECUTABLE_PATH,
HAS_CXX_INTEROPERABILITY_ENABLED,
};

using SDKPathLayout = BCRecordLayout<
Expand Down Expand Up @@ -976,6 +977,10 @@ namespace options_block {
MODULE_EXPORT_AS_NAME,
BCBlob
>;

using HasCxxInteroperabilityEnabledLayout = BCRecordLayout<
HAS_CXX_INTEROPERABILITY_ENABLED
>;
}

/// The record types within the input block.
Expand Down
7 changes: 7 additions & 0 deletions lib/Serialization/Serialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,7 @@ void Serializer::writeBlockInfoBlock() {
BLOCK_RECORD(options_block, IS_ALLOW_MODULE_WITH_COMPILER_ERRORS_ENABLED);
BLOCK_RECORD(options_block, MODULE_ABI_NAME);
BLOCK_RECORD(options_block, IS_CONCURRENCY_CHECKED);
BLOCK_RECORD(options_block, HAS_CXX_INTEROPERABILITY_ENABLED);
BLOCK_RECORD(options_block, MODULE_PACKAGE_NAME);
BLOCK_RECORD(options_block, MODULE_EXPORT_AS_NAME);
BLOCK_RECORD(options_block, PLUGIN_SEARCH_PATH);
Expand Down Expand Up @@ -1090,6 +1091,12 @@ void Serializer::writeHeader(const SerializationOptions &options) {
IsConcurrencyChecked.emit(ScratchRecord);
}

if (M->hasCxxInteroperability()) {
options_block::HasCxxInteroperabilityEnabledLayout
CxxInteroperabilityEnabled(Out);
CxxInteroperabilityEnabled.emit(ScratchRecord);
}

if (options.SerializeOptionsForDebugging) {
options_block::SDKPathLayout SDKPath(Out);
options_block::XCCLayout XCC(Out);
Expand Down
15 changes: 15 additions & 0 deletions lib/Serialization/SerializedModuleLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,8 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
M.setABIName(Ctx.getIdentifier(loadedModuleFile->getModuleABIName()));
if (loadedModuleFile->isConcurrencyChecked())
M.setIsConcurrencyChecked();
if (loadedModuleFile->hasCxxInteroperability())
M.setHasCxxInteroperability();
if (!loadedModuleFile->getModulePackageName().empty()) {
M.setPackageName(Ctx.getIdentifier(loadedModuleFile->getModulePackageName()));
}
Expand Down Expand Up @@ -896,6 +898,19 @@ LoadedFile *SerializedModuleLoaderBase::loadAST(
diag::need_hermetic_seal_to_import_module, M.getName());
}

// Non-resilient modules built with C++ interoperability enabled
// are typically incompatible with clients that do not enable
// C++ interoperability.
if (M.hasCxxInteroperability() &&
M.getResilienceStrategy() != ResilienceStrategy::Resilient &&
!Ctx.LangOpts.EnableCXXInterop &&
Ctx.LangOpts.RequireCxxInteropToImportCxxInteropModule) {
auto loc = diagLoc.value_or(SourceLoc());
Ctx.Diags.diagnose(loc, diag::need_cxx_interop_to_import_module,
M.getName());
Ctx.Diags.diagnose(loc, diag::enable_cxx_interop_docs);
}

return fileUnit;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// RUN: %empty-directory(%t)

// 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
// 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

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

// Check that we have used something from CxxShim in 'UseModuleAImplOnly'
// 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
// 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
// CHECK: __swift_interopStaticCast

import UseModuleAImplOnly
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)

// 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
// 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

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

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend %s -module-name UsesCxxInterop -emit-module -emit-module-path %t/UsesCxxInterop.swiftmodule -cxx-interoperability-mode=default

// RUN: %target-swift-frontend %s -D USE -typecheck -module-name TestMod -I %t -verify

// RUN: %target-swift-frontend %s -D USE -typecheck -module-name TestMod -I %t -disable-cxx-interop-requirement-at-import

// Verify that 'disable-cxx-interop-requirement-at-import' works for the module being built.
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend %s -module-name UsesCxxInterop -emit-module -emit-module-path %t/UsesCxxInterop.swiftmodule -cxx-interoperability-mode=default -disable-cxx-interop-requirement-at-import
// RUN: %target-swift-frontend %s -D USE -typecheck -module-name TestMod -I %t

#if USE
import UsesCxxInterop // expected-error {{module 'UsesCxxInterop' was built with C++ interoperability enabled, but current compilation does not enable C++ interoperability}}
// expected-note@-1 {{visit https://www.swift.org/documentation/cxx-interop/project-build-setup to learn how to enable C++ interoperability}}

#else
public func testFun() { }

#endif