Skip to content

Commit 83bdd59

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". (cherry picked from commit fe6ccd7)
1 parent cb109dc commit 83bdd59

File tree

5 files changed

+58
-6
lines changed

5 files changed

+58
-6
lines changed

lib/ClangImporter/ClangImporter.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6854,14 +6854,25 @@ const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
68546854
if (!enumDecl->getDeclName().isEmpty())
68556855
return nullptr;
68566856

6857-
if (auto typedefType = dyn_cast<clang::TypedefType>(
6858-
enumDecl->getIntegerType().getTypePtr())) {
6859-
if (auto enumExtensibilityAttr =
6860-
typedefType->getDecl()->getAttr<clang::EnumExtensibilityAttr>();
6861-
enumExtensibilityAttr &&
6857+
const clang::ElaboratedType *elaboratedType =
6858+
dyn_cast<clang::ElaboratedType>(enumDecl->getIntegerType().getTypePtr());
6859+
if (auto typedefType =
6860+
elaboratedType
6861+
? dyn_cast<clang::TypedefType>(elaboratedType->desugar())
6862+
: dyn_cast<clang::TypedefType>(
6863+
enumDecl->getIntegerType().getTypePtr())) {
6864+
auto enumExtensibilityAttr =
6865+
elaboratedType
6866+
? enumDecl->getAttr<clang::EnumExtensibilityAttr>()
6867+
: typedefType->getDecl()->getAttr<clang::EnumExtensibilityAttr>();
6868+
const bool hasFlagEnumAttr =
6869+
elaboratedType ? enumDecl->hasAttr<clang::FlagEnumAttr>()
6870+
: typedefType->getDecl()->hasAttr<clang::FlagEnumAttr>();
6871+
6872+
if (enumExtensibilityAttr &&
68626873
enumExtensibilityAttr->getExtensibility() ==
68636874
clang::EnumExtensibilityAttr::Open &&
6864-
typedefType->getDecl()->hasAttr<clang::FlagEnumAttr>()) {
6875+
hasFlagEnumAttr) {
68656876
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
68666877
: nullptr;
68676878
}
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: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
typedef CF_OPTIONS(unsigned, UIControlState) { UIControlStateNormal = 0 };
9+
10+
#ifdef __cplusplus
11+
#define UIKIT_EXTERN extern "C" __attribute__((visibility ("default")))
12+
#else
13+
#define UIKIT_EXTERN extern __attribute__((visibility ("default")))
14+
#endif
15+
16+
@interface UIView
17+
@end
18+
19+
UIKIT_EXTERN
20+
@interface UIControl : UIView
21+
@end
22+

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: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %target-swift-frontend -I %S/Inputs -c -cxx-interoperability-mode=swift-5.9 %s -S -o - | %FileCheck %s
2+
// RUN: %target-swift-frontend -I %S/Inputs -c %s -S -o - | %FileCheck %s
3+
4+
// REQUIRES: objc_interop
5+
6+
// CHECK: _$sSo14UIControlStateV4main7FooableACMc
7+
// The following check is to ensure the conformance is mangled properly:
8+
// protocol conformance descriptor for __C.UIControlState : main.Fooable in main
9+
import NSOptionsMangling
10+
protocol Fooable { }
11+
extension UIControl.State: Fooable {}

0 commit comments

Comments
 (0)