mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[cxx-interop] Allow AppKit & UIKit to be rebuilt with C++ interop enabled
This removes a workaround from the module interface loader, which was forcing AppKit and UIKit to be rebuilt from their textual interfaces with C++ interop disabled, even if the current compilation explicitly enables it.
The workaround was previously put in place because of a compiler error:
```
error: type 'AttributeScopes.AppKitAttributes.StrikethroughStyleAttribute' does not conform to protocol 'AttributedStringKey'
note: possibly intended match 'AttributeScopes.AppKitAttributes.StrikethroughStyleAttribute.Value' (aka 'NSUnderlineStyle') does not conform to 'Hashable'
```
`NSUnderlineStyle` is a C/C++ type from AppKit that is declared using `NS_OPTIONS` macro. `NS_OPTIONS`/`CF_OPTIONS` macros have different expansions in C vs C++ language modes. The C++ expansions weren't handled correctly by ClangImporter, resulting in two distinct Swift types being created: a `typealias NSUnderlineStyle` which was marked as unavailable in Swift, and `enum NSUnderlineStyle`. This mostly worked fine, since the lookup logic was picking the enum during regular name lookup. However, this silently broke down when rebuilding the explicit conformance from `AppKit.swiftinterface`:
```
extension AppKit.NSUnderlineStyle : Swift.Hashable {}
```
Swift was picking the (unavailable) typealias when rebuilding this extension, which means the (available) enum wasn't getting the conformance.
This is verified by an existing test (`test/Interop/Cxx/objc-correctness/appkit-uikit.swift`).
rdar://142961112
This commit is contained in:
@@ -1861,6 +1861,25 @@ ImportedName NameImporter::importNameImpl(const clang::NamedDecl *D,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In C++ language mode, CF_OPTIONS/NS_OPTIONS macro has a different
|
||||||
|
// expansion: instead of a forward-declared enum, it expands into a typedef
|
||||||
|
// that is marked as `__attribute__((availability(swift,unavailable)))`, and
|
||||||
|
// an anonymous enum that inherits from the typedef. The logic above imports
|
||||||
|
// the anonymous enum with the desired name based on the typedef's name. In
|
||||||
|
// addition to that, we should make sure the unavailable typedef isn't
|
||||||
|
// imported into Swift to avoid having two types with the same name, which
|
||||||
|
// cause subtle name lookup issues.
|
||||||
|
if (swiftCtx.LangOpts.EnableCXXInterop &&
|
||||||
|
isUnavailableInSwift(D, nullptr, true)) {
|
||||||
|
auto loc = D->getEndLoc();
|
||||||
|
if (loc.isMacroID()) {
|
||||||
|
StringRef macroName =
|
||||||
|
clangSema.getPreprocessor().getImmediateMacroName(loc);
|
||||||
|
if (macroName == "CF_OPTIONS" || macroName == "NS_OPTIONS")
|
||||||
|
return ImportedName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether the result is a function name.
|
/// Whether the result is a function name.
|
||||||
bool isFunction = false;
|
bool isFunction = false;
|
||||||
bool isInitializer = false;
|
bool isInitializer = false;
|
||||||
|
|||||||
@@ -2106,10 +2106,7 @@ InterfaceSubContextDelegateImpl::runInSubCompilerInstance(StringRef moduleName,
|
|||||||
// interop enabled by the Swift CI because it uses an old host SDK.
|
// interop enabled by the Swift CI because it uses an old host SDK.
|
||||||
// FIXME: Hack for CoreGraphics.swiftmodule, which cannot be rebuilt because
|
// FIXME: Hack for CoreGraphics.swiftmodule, which cannot be rebuilt because
|
||||||
// of a CF_OPTIONS bug (rdar://142762174).
|
// of a CF_OPTIONS bug (rdar://142762174).
|
||||||
// FIXME: Hack for AppKit.swiftmodule / UIKit.swiftmodule, which cannot be
|
if (moduleName == "Darwin" || moduleName == "CoreGraphics") {
|
||||||
// rebuilt because of an NS_OPTIONS bug (rdar://143033209)
|
|
||||||
if (moduleName == "Darwin" || moduleName == "CoreGraphics"
|
|
||||||
|| moduleName == "AppKit" || moduleName == "UIKit") {
|
|
||||||
subInvocation.getLangOptions().EnableCXXInterop = false;
|
subInvocation.getLangOptions().EnableCXXInterop = false;
|
||||||
subInvocation.getLangOptions().cxxInteropCompatVersion = {};
|
subInvocation.getLangOptions().cxxInteropCompatVersion = {};
|
||||||
BuildArgs.erase(llvm::remove_if(BuildArgs,
|
BuildArgs.erase(llvm::remove_if(BuildArgs,
|
||||||
|
|||||||
@@ -10,13 +10,9 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (__cplusplus)
|
#if (__cplusplus)
|
||||||
#define CF_OPTIONS(_type, _name) \
|
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name
|
||||||
_type __attribute__((availability(swift, unavailable))) _name; \
|
|
||||||
enum __CF_OPTIONS_ATTRIBUTES : _name
|
|
||||||
#else
|
#else
|
||||||
#define CF_OPTIONS(_type, _name) \
|
#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type
|
||||||
enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; \
|
|
||||||
enum _name : _type
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
|
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
|
||||||
|
|||||||
@@ -27,8 +27,7 @@
|
|||||||
// CHECK: static var All: SOColorMask { get }
|
// CHECK: static var All: SOColorMask { get }
|
||||||
// CHECK: }
|
// CHECK: }
|
||||||
|
|
||||||
// CHECK: @available(*, unavailable, message: "Not available in Swift")
|
// CHECK-NOT: typealias CFColorMask = UInt32
|
||||||
// CHECK: typealias CFColorMask = UInt32
|
|
||||||
|
|
||||||
// CHECK: struct CFColorMask : OptionSet {
|
// CHECK: struct CFColorMask : OptionSet {
|
||||||
// CHECK: init(rawValue: UInt32)
|
// CHECK: init(rawValue: UInt32)
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
import CenumsNSOptions
|
import CenumsNSOptions
|
||||||
|
|
||||||
// CHECK: typealias NSAttributedStringFormattingOptions = UInt
|
// CHECK-NOT: typealias NSAttributedStringFormattingOptions = UInt
|
||||||
// CHECK-NEXT: struct __NSAttributedStringFormattingOptions : OptionSet, @unchecked Sendable {
|
|
||||||
|
// CHECK: struct __NSAttributedStringFormattingOptions : OptionSet, @unchecked Sendable {
|
||||||
// CHECK-NEXT: init(rawValue: UInt)
|
// CHECK-NEXT: init(rawValue: UInt)
|
||||||
// CHECK-NEXT: let rawValue: UInt
|
// CHECK-NEXT: let rawValue: UInt
|
||||||
// CHECK-NEXT: typealias RawValue = UInt
|
// CHECK-NEXT: typealias RawValue = UInt
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
import CenumsNSOptions
|
import CenumsNSOptions
|
||||||
|
|
||||||
// CHECK: typealias NSBinarySearchingOptions = UInt
|
// CHECK-NOT: typealias NSBinarySearchingOptions = UInt
|
||||||
// CHECK-NEXT: struct NSBinarySearchingOptions : OptionSet, @unchecked Sendable {
|
|
||||||
|
// CHECK: struct NSBinarySearchingOptions : OptionSet, @unchecked Sendable {
|
||||||
// CHECK-NEXT: init(rawValue: UInt)
|
// CHECK-NEXT: init(rawValue: UInt)
|
||||||
// CHECK-NEXT: let rawValue: UInt
|
// CHECK-NEXT: let rawValue: UInt
|
||||||
// CHECK-NEXT: typealias RawValue = UInt
|
// CHECK-NEXT: typealias RawValue = UInt
|
||||||
|
|||||||
Reference in New Issue
Block a user