Skip to content

Commit a9b744e

Browse files
committed
[cxx-interop] Fix assertion failure from unavailable NS_ENUM typedef
The NS_OPTIONS macro sometimes uses a pattern where it loosely associates a typedef with an anonymous enum via a shared underlying integer type (emphasis on "loosely"). The typedef is marked as unavailable in Swift so as to not cause name ambiguity when we associate the anonymous enum with said typedef. We use unavailability as a heuristic during the import process, but that conflates NS_OPTIONS with NS_ENUMs that can be marked as unavailable for entirely unrelated reasons. That in and of itself is fine, because the import logic is general enough to handle both cases, but we have an assertion that seems to be unaware of this scenario, and trips on unavailable NS_ENUMs. (In those cases, the typedef points to the enum rather than the underlying integer type.) This patch fixes the assertion to be resilient against such cases by looking through the enum a typedef refers to. rdar://150399978
1 parent 2c7d01f commit a9b744e

File tree

2 files changed

+72
-3
lines changed

2 files changed

+72
-3
lines changed

lib/ClangImporter/ImportEnumInfo.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,19 @@ ImportedType importer::findOptionSetEnum(clang::QualType type,
259259
if (!clangEnum)
260260
return ImportedType();
261261

262-
// If this fails, it means that we need a stronger predicate for
262+
// Assert that the typedef has the same underlying integer representation as
263+
// the enum we think it assigns a type name to.
264+
//
265+
// If these fails, it means that we need a stronger predicate for
263266
// determining the relationship between an enum and typedef.
264-
assert(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
265-
typedefType->getCanonicalTypeInternal());
267+
if (auto *tdEnum =
268+
dyn_cast<clang::EnumType>(typedefType->getCanonicalTypeInternal())) {
269+
assert(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
270+
tdEnum->getDecl()->getIntegerType()->getCanonicalTypeInternal());
271+
} else {
272+
assert(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
273+
typedefType->getCanonicalTypeInternal());
274+
}
266275

267276
if (auto *swiftEnum = Impl.importDecl(*clangEnum, Impl.CurrentVersion))
268277
return {cast<TypeDecl>(swiftEnum)->getDeclaredInterfaceType(), false};
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// RUN: split-file %s %t
2+
// RUN: %target-swift-frontend -typecheck -verify %t/main.swift -I %t/include -module-name main
3+
// RUN: %target-swift-frontend -typecheck -verify %t/main.swift -I %t/include -module-name main -cxx-interoperability-mode=default
4+
// REQUIRES: objc_interop
5+
6+
//--- include/module.modulemap
7+
module ObjCModule {
8+
header "header.h"
9+
}
10+
11+
//--- include/header.h
12+
#include <Foundation/Foundation.h>
13+
14+
#define UNAVAILABLE API_UNAVAILABLE(macos)
15+
16+
UNAVAILABLE
17+
typedef NS_ENUM(NSUInteger, MyUnavailableEnum) {
18+
MyUnavailableEnumCase1 = 0,
19+
MyUnavailableEnumCase2,
20+
};
21+
22+
UNAVAILABLE
23+
void unavailableParam(MyUnavailableEnum e);
24+
25+
UNAVAILABLE
26+
MyUnavailableEnum unavailableReturn(void);
27+
28+
struct UNAVAILABLE UnavailableStruct {
29+
MyUnavailableEnum field;
30+
};
31+
32+
UNAVAILABLE
33+
@interface UnavailableClass
34+
@property (nonatomic, readonly) MyUnavailableEnum prop;
35+
@end
36+
37+
UNAVAILABLE
38+
__attribute__((swift_name("getter:UnavailableStruct.iProp(self:)")))
39+
inline MyUnavailableEnum getUnavailableInjProp(struct UnavailableStruct s) {
40+
return MyUnavailableEnumCase1;
41+
}
42+
43+
//--- main.swift
44+
import Foundation
45+
import ObjCModule
46+
47+
@available(*, unavailable)
48+
func useParam(_ e: MyUnavailableEnum) { unavailableParam(e) }
49+
50+
@available(*, unavailable)
51+
func useReturn() -> MyUnavailableEnum { return unavailableReturn() }
52+
53+
@available(*, unavailable)
54+
func useField(_ o: UnavailableStruct) -> MyUnavailableEnum { return o.field }
55+
56+
@available(*, unavailable)
57+
func useIProp(_ o: UnavailableStruct) -> MyUnavailableEnum { return o.iProp }
58+
59+
@available(*, unavailable)
60+
func useProp(_ o: UnavailableClass) -> MyUnavailableEnum { return o.prop }

0 commit comments

Comments
 (0)