Skip to content

Commit fe6ccd7

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 fe6ccd7

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
@@ -6877,14 +6877,25 @@ const clang::TypedefType *ClangImporter::getTypeDefForCXXCFOptionsDefinition(
68776877
if (!enumDecl->getDeclName().isEmpty())
68786878
return nullptr;
68796879

6880-
if (auto typedefType = dyn_cast<clang::TypedefType>(
6881-
enumDecl->getIntegerType().getTypePtr())) {
6882-
if (auto enumExtensibilityAttr =
6883-
typedefType->getDecl()->getAttr<clang::EnumExtensibilityAttr>();
6884-
enumExtensibilityAttr &&
6880+
const clang::ElaboratedType *elaboratedType =
6881+
dyn_cast<clang::ElaboratedType>(enumDecl->getIntegerType().getTypePtr());
6882+
if (auto typedefType =
6883+
elaboratedType
6884+
? dyn_cast<clang::TypedefType>(elaboratedType->desugar())
6885+
: dyn_cast<clang::TypedefType>(
6886+
enumDecl->getIntegerType().getTypePtr())) {
6887+
auto enumExtensibilityAttr =
6888+
elaboratedType
6889+
? enumDecl->getAttr<clang::EnumExtensibilityAttr>()
6890+
: typedefType->getDecl()->getAttr<clang::EnumExtensibilityAttr>();
6891+
const bool hasFlagEnumAttr =
6892+
elaboratedType ? enumDecl->hasAttr<clang::FlagEnumAttr>()
6893+
: typedefType->getDecl()->hasAttr<clang::FlagEnumAttr>();
6894+
6895+
if (enumExtensibilityAttr &&
68856896
enumExtensibilityAttr->getExtensibility() ==
68866897
clang::EnumExtensibilityAttr::Open &&
6887-
typedefType->getDecl()->hasAttr<clang::FlagEnumAttr>()) {
6898+
hasFlagEnumAttr) {
68886899
return Impl.isUnavailableInSwift(typedefType->getDecl()) ? typedefType
68896900
: nullptr;
68906901
}
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)