Skip to content

Commit 21a3c89

Browse files
committed
[cxx-interop] Add fix for corner case where NS_OPTIONS typedef has to be desugared
This patch is an add-on to #64043. Essentially when encountering NS_OPTIONS enums, in C++-Interop mode if they are not specially handled then they can mangle differently than they do without C++-Interop. This patch adds logic to handle when a typedef and enum have additional clang::ElaboratedType sugar, but otherwise it does the same as the existing 64043 patch. The test case provided was encountered in a real app build. The problem came from when two modules are each compiled one with and one without C++-Interop. For the test case code provided the mangling of the protocol conformance is not consistent and the code in SILGenLazyConformance.cpp crashes on an invalid conformance with reason "Invalid conformance in type-checked AST".
1 parent 9f51c06 commit 21a3c89

File tree

5 files changed

+82
-0
lines changed

5 files changed

+82
-0
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6877,6 +6877,22 @@ const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
68776877
if (!enumDecl->getDeclName().isEmpty())
68786878
return nullptr;
68796879

6880+
if (const clang::ElaboratedType *elaboratedType =
6881+
dyn_cast<clang::ElaboratedType>(
6882+
enumDecl->getIntegerType().getTypePtr())) {
6883+
if (auto typedefType =
6884+
dyn_cast<clang::TypedefType>(elaboratedType->desugar()))
6885+
if (auto enumExtensibilityAttr =
6886+
enumDecl->getAttr<clang::EnumExtensibilityAttr>();
6887+
enumExtensibilityAttr &&
6888+
enumExtensibilityAttr->getExtensibility() ==
6889+
clang::EnumExtensibilityAttr::Open &&
6890+
enumDecl->hasAttr<clang::FlagEnumAttr>()) {
6891+
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
6892+
: nullptr;
6893+
}
6894+
}
6895+
68806896
if (auto typedefType = dyn_cast<clang::TypedefType>(
68816897
enumDecl->getIntegerType().getTypePtr())) {
68826898
if (auto enumExtensibilityAttr =
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
Name: NSOptionsMangling
3+
Tags:
4+
- Name: UIControlState
5+
SwiftName: UIControl.State
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#define __CF_OPTIONS_ATTRIBUTES __attribute__((flag_enum,enum_extensibility(open)))
2+
#if (__cplusplus)
3+
#define CF_OPTIONS(_type, _name) __attribute__((availability(swift,unavailable))) _type _name; enum __CF_OPTIONS_ATTRIBUTES : _name
4+
#else
5+
#define CF_OPTIONS(_type, _name) enum __CF_OPTIONS_ATTRIBUTES _name : _type _name; enum _name : _type
6+
#endif
7+
8+
9+
#define NS_OPTIONS(_type, _name) CF_OPTIONS(_type, _name)
10+
typedef unsigned long NSUInteger;
11+
typedef NS_OPTIONS(NSUInteger, UIControlState) {
12+
UIControlStateNormal = 0,
13+
UIControlStateHighlighted = 1 << 0, // used when UIControl isHighlighted is set
14+
};
15+
16+
#define NS_SWIFT_UI_ACTOR __attribute__((swift_attr("@UIActor")))
17+
#define __API_AVAILABLE_PLATFORM_macos(x) macos,introduced=x
18+
#define __API_AVAILABLE_PLATFORM_macosx(x) macosx,introduced=x
19+
#define __API_AVAILABLE_PLATFORM_ios(x) ios,introduced=x
20+
#define __API_AVAILABLE_PLATFORM_watchos(x) watchos,introduced=x
21+
#define __API_AVAILABLE_PLATFORM_tvos(x) tvos,introduced=x
22+
#define __API_AVAILABLE_PLATFORM_macCatalyst(x) macCatalyst,introduced=x
23+
#define __API_AVAILABLE_PLATFORM_macCatalyst(x) macCatalyst,introduced=x
24+
#define __API_AVAILABLE_PLATFORM_uikitformac(x) uikitformac,introduced=x
25+
#define __API_AVAILABLE_PLATFORM_driverkit(x) driverkit,introduced=x
26+
#define __API_A(x) __attribute__((availability(__API_AVAILABLE_PLATFORM_##x)))
27+
#define __API_AVAILABLE1(x) __API_A(x)
28+
#define __API_AVAILABLE2(x,y) __API_A(x) __API_A(y)
29+
#define __API_AVAILABLE3(x,y,z) __API_A(x) __API_A(y) __API_A(z)
30+
#define __API_AVAILABLE4(x,y,z,t) __API_A(x) __API_A(y) __API_A(z) __API_A(t)
31+
#define __API_AVAILABLE5(x,y,z,t,b) __API_A(x) __API_A(y) __API_A(z) __API_A(t) __API_A(b)
32+
#define __API_AVAILABLE6(x,y,z,t,b,m) __API_A(x) __API_A(y) __API_A(z) __API_A(t) __API_A(b) __API_A(m)
33+
#define __API_AVAILABLE7(x,y,z,t,b,m,d) __API_A(x) __API_A(y) __API_A(z) __API_A(t) __API_A(b) __API_A(m) __API_A(d)
34+
#define __API_AVAILABLE8(x,y,z,t,b,m,d,l) __API_A(x) __API_A(y) __API_A(z) __API_A(t) __API_A(b) __API_A(m) __API_A(d) __API_A(l)
35+
#define __API_AVAILABLE_GET_MACRO(_1,_2,_3,_4,_5,_6,_7,_8,NAME,...) NAME
36+
#define API_AVAILABLE(...) __API_AVAILABLE_GET_MACRO(__VA_ARGS__,__API_AVAILABLE8, __API_AVAILABLE7, __API_AVAILABLE6, __API_AVAILABLE5, __API_AVAILABLE4, __API_AVAILABLE3, __API_AVAILABLE2, __API_AVAILABLE1, 0)(__VA_ARGS__)
37+
38+
#ifdef __cplusplus
39+
#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))
40+
#else
41+
#define UIKIT_EXTERN extern __attribute__((visibility ("default")))
42+
#endif
43+
44+
@interface UIView
45+
@end
46+
47+
UIKIT_EXTERN API_AVAILABLE(ios(2.0)) NS_SWIFT_UI_ACTOR
48+
@interface UIControl : UIView
49+
@end
50+

test/Interop/Cxx/objc-correctness/Inputs/module.modulemap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,6 @@ module CxxClassWithNSStringInit [extern_c] {
99
requires cplusplus
1010
}
1111

12+
module NSOptionsMangling {
13+
header "NSOptionsMangling.h"
14+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// RUN: %target-swift-frontend -I %S/Inputs -c -cxx-interoperability-mode=swift-5.9 %s -S -o - | %FileCheck %s
2+
3+
// CHECK: _$sSo14UIControlStateV4main7FooableACMc
4+
// The following check is to ensure the conformance is mangled properly:
5+
// protocol conformance descriptor for __C.UIControlState : main.Fooable in main
6+
import NSOptionsMangling
7+
protocol Fooable { }
8+
extension UIControl.State: Fooable {}

0 commit comments

Comments
 (0)