Skip to content

Commit 323e9f0

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 (cherry picked from commit 80db054)
1 parent 1586d01 commit 323e9f0

File tree

2 files changed

+76
-3
lines changed

2 files changed

+76
-3
lines changed

lib/ClangImporter/ImportEnumInfo.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,23 @@ 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+
// Only ASSERT() on assertions-enabled builds. This preserves existing
263+
// behavior and de-risks existing builds, but should be removed after 6.2.
264+
#ifndef NDEBUG
265+
// Assert that the typedef has the same underlying integer representation as
266+
// the enum we think it assigns a type name to.
267+
//
268+
// If these fails, it means that we need a stronger predicate for
263269
// determining the relationship between an enum and typedef.
264-
assert(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
265-
typedefType->getCanonicalTypeInternal());
270+
if (auto *tdEnum =
271+
dyn_cast<clang::EnumType>(typedefType->getCanonicalTypeInternal())) {
272+
ASSERT(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
273+
tdEnum->getDecl()->getIntegerType()->getCanonicalTypeInternal());
274+
} else {
275+
ASSERT(clangEnum.value()->getIntegerType()->getCanonicalTypeInternal() ==
276+
typedefType->getCanonicalTypeInternal());
277+
}
278+
#endif // !NDEBUG
266279

267280
if (auto *swiftEnum = Impl.importDecl(*clangEnum, Impl.CurrentVersion))
268281
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)