Skip to content

Commit a03c40c

Browse files
authored
[ClangImporter] Classify enums using flag_enum and enum_extensibility (#8910)
These new Clang attributes identify whether an enum is intended to represent an option set or not, and whether the set of cases listed in the enum declaration is exhaustive. (Swift doesn't currently have a closed/open distinction for enums, so treat any C enum with enum_extensibility as a proper closed Swift enum, like we do with NS_ENUM.) Enums with neither attribute will continue to be imported as unique types. rdar://problem/28476618
1 parent f6b8b7d commit a03c40c

File tree

8 files changed

+45
-15
lines changed

8 files changed

+45
-15
lines changed

lib/ClangImporter/ImportEnumInfo.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,20 @@ void EnumInfo::classifyEnum(ASTContext &ctx, const clang::EnumDecl *decl,
5050
nsErrorDomain = ctx.AllocateCopy(domainAttr->getErrorDomain()->getName());
5151
return;
5252
}
53+
if (decl->hasAttr<clang::FlagEnumAttr>()) {
54+
kind = EnumKind::Options;
55+
return;
56+
}
57+
if (decl->hasAttr<clang::EnumExtensibilityAttr>()) {
58+
// FIXME: Distinguish between open and closed enums.
59+
kind = EnumKind::Enum;
60+
return;
61+
}
5362

5463
// Was the enum declared using *_ENUM or *_OPTIONS?
55-
// FIXME: Use Clang attributes instead of groveling the macro expansion loc.
64+
// FIXME: Stop using these once flag_enum and enum_extensibility
65+
// have been adopted everywhere, or at least relegate them to Swift 3 mode
66+
// only.
5667
auto loc = decl->getLocStart();
5768
if (loc.isMacroID()) {
5869
StringRef MacroName = pp.getImmediateMacroName(loc);

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,15 +2451,25 @@ class ModuleWriter {
24512451
"# define OBJC_DESIGNATED_INITIALIZER\n"
24522452
"# endif\n"
24532453
"#endif\n"
2454+
"#if !defined(SWIFT_ENUM_ATTR)\n"
2455+
"# if defined(__has_attribute) && "
2456+
"__has_attribute(enum_extensibility)\n"
2457+
"# define SWIFT_ENUM_ATTR "
2458+
"__attribute__((enum_extensibility(open)))\n"
2459+
"# else\n"
2460+
"# define SWIFT_ENUM_ATTR\n"
2461+
"# endif\n"
2462+
"#endif\n"
24542463
"#if !defined(SWIFT_ENUM)\n"
24552464
"# define SWIFT_ENUM(_type, _name) "
24562465
"enum _name : _type _name; "
2457-
"enum SWIFT_ENUM_EXTRA _name : _type\n"
2466+
"enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type\n"
24582467
"# if defined(__has_feature) && "
24592468
"__has_feature(generalized_swift_name)\n"
24602469
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
24612470
"enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); "
2462-
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type\n"
2471+
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR "
2472+
"SWIFT_ENUM_EXTRA _name : _type\n"
24632473
"# else\n"
24642474
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
24652475
"SWIFT_ENUM(_type, _name)\n"

test/ClangImporter/Inputs/custom-modules/SwiftName.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#define SWIFT_NAME(X) __attribute__((swift_name(#X)))
22

3-
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
3+
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum __attribute__((enum_extensibility(open))) _name : _type
44

55
void drawString(const char *, int x, int y) SWIFT_NAME(drawString(_:x:y:));
66

test/ClangImporter/Inputs/enum-objc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@import Foundation;
22

33
#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
4-
#define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type
4+
#define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
55

66
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") {
77
ObjCEnumOne = 1,

test/ClangImporter/enum.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ var qualifiedName = NSRuncingMode.mince
148148
var topLevelCaseName = RuncingMince // expected-error{{}}
149149
#endif
150150

151+
let _: EnumViaAttribute = .first
152+
151153
// NS_OPTIONS
152154
var withMince: NSRuncingOptions = .enableMince
153155
var withQuince: NSRuncingOptions = .enableQuince
@@ -193,6 +195,7 @@ let audioComponentFlags2: FakeAudioComponentFlags = [.loadOutOfProcess]
193195
let objcFlags: objc_flags = [.taggedPointer, .swiftRefcount]
194196

195197
let optionsWithSwiftName: NSOptionsAlsoGetSwiftName = .Case
198+
let optionsViaAttribute: OptionsViaAttribute = [.first, .second]
196199

197200
// <rdar://problem/25168818> Don't import None members in NS_OPTIONS types
198201
#if !IRGEN

test/IDE/Inputs/print_clang_header_swift_name.h

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,23 @@
22

33
#define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
44

5-
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type
5+
#define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
66

77
typedef SWIFT_ENUM(NSInteger, Normal) {
88
NormalOne = 0,
99
NormalTwo,
1010
NormalThree
1111
};
1212

13-
// FIXME (#618): Use SWIFT_ENUM_NAMED() when support for that lands
14-
#undef SWIFT_ENUM
15-
#define SWIFT_ENUM(_type, _name) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME); enum SWIFT_COMPILE_NAME(SWIFT_ENUM_NAME) SWIFT_ENUM_EXTRA _name : _type
13+
#define SWIFT_ENUM_NAMED(_type, _name, _swiftName) enum _name : _type _name SWIFT_COMPILE_NAME(_swiftName); enum SWIFT_COMPILE_NAME(_swiftName) __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
1614

17-
#define SWIFT_ENUM_NAME "SwiftEnum"
18-
typedef SWIFT_ENUM(NSInteger, ObjCEnum) {
15+
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnum, "SwiftEnum") {
1916
ObjCEnumOne = 0,
2017
ObjCEnumTwo,
2118
ObjCEnumThree
2219
};
2320

24-
#undef SWIFT_ENUM_NAME
25-
#define SWIFT_ENUM_NAME "SwiftEnumTwo"
26-
typedef SWIFT_ENUM(NSInteger, ObjCEnumTwo) {
21+
typedef SWIFT_ENUM_NAMED(NSInteger, ObjCEnumTwo, "SwiftEnumTwo") {
2722
// the following shouldn't have their prefixes stripped
2823
SwiftEnumTwoA,
2924
SwiftEnumTwoB,

test/IDE/Inputs/swift_name.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#ifndef SWIFT_ENUM
88
# define SWIFT_ENUM(_type, _name) \
99
enum _name : _type _name; \
10-
enum SWIFT_ENUM_EXTRA _name : _type
10+
enum __attribute__((enum_extensibility(open))) SWIFT_ENUM_EXTRA _name : _type
1111
#endif
1212

1313
// Renaming global variables.

test/Inputs/clang-importer-sdk/usr/include/user_objc.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ typedef NS_ENUM(NSInteger, EnumWithAwkwardDeprecations) {
2929
EnumWithAwkward2BitProblems __attribute__((deprecated)) = EnumWithAwkwardNormalCase1,
3030
};
3131

32+
enum __attribute__((enum_extensibility(open))) EnumViaAttribute {
33+
EnumViaAttributeFirst = 1,
34+
EnumViaAttributeSecond = 2
35+
};
36+
37+
3238
// From <AudioUnit/AudioComponent.h>
3339
// The interesting feature of this enum is that the common prefix before
3440
// taking the enum name itself into account extends past the underscore.
@@ -68,3 +74,8 @@ typedef CF_OPTIONS(UInt32, EmptySet2) {
6874
typedef CF_OPTIONS(UInt32, EmptySet3) {
6975
kEmptySet3None __attribute__((swift_name("None")))
7076
};
77+
78+
enum __attribute__((flag_enum)) OptionsViaAttribute {
79+
OptionsViaAttributeFirst = 1,
80+
OptionsViaAttributeSecond = 2
81+
};

0 commit comments

Comments
 (0)