Skip to content

Commit 1b1a4cb

Browse files
committed
[PrintAsObjC] Use enum_extensibility to represent @_frozen
Previously (a03c40c) we assumed all Swift enums were non-frozen in ObjC, a weird choice in retrospect. Now that we actually distinguish frozen and non-frozen enums in Swift, we can use the 'enum_extensibility' attribute to mark them as open or closed in ObjC. Note that this only matters for Swift libraries compiled with -enable-resilience, i.e. those that might get a new implementation at runtime. Everyone else is now declaring a "closed" enum, matching the behavior in Swift.
1 parent 6ea47bd commit 1b1a4cb

File tree

5 files changed

+52
-21
lines changed

5 files changed

+52
-21
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3116,6 +3116,11 @@ bool EnumDecl::isExhaustive(const DeclContext *useDC) const {
31163116
if (!accessScope.isPublic())
31173117
return true;
31183118

3119+
// All other checks are use-site specific; with no further information, the
3120+
// enum must be treated non-exhaustively.
3121+
if (!useDC)
3122+
return false;
3123+
31193124
// Enums in the same module as the use site are exhaustive /unless/ the use
31203125
// site is inlinable.
31213126
if (useDC->getParentModule() == containingModule)

lib/PrintAsObjC/PrintAsObjC.cpp

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,9 @@ class ObjCPrinter : private DeclVisitor<ObjCPrinter>,
421421
os << ", " << customName
422422
<< ", \"" << ED->getName() << "\"";
423423
}
424-
os << ") {\n";
424+
os << ", " << (ED->isExhaustive(/*useDC*/nullptr) ? "closed" : "open")
425+
<< ") {\n";
426+
425427
for (auto Elt : ED->getAllElements()) {
426428
printDocumentationComment(Elt);
427429

@@ -2569,24 +2571,26 @@ class ModuleWriter {
25692571
"#if !defined(SWIFT_ENUM_ATTR)\n"
25702572
"# if defined(__has_attribute) && "
25712573
"__has_attribute(enum_extensibility)\n"
2572-
"# define SWIFT_ENUM_ATTR "
2573-
"__attribute__((enum_extensibility(open)))\n"
2574+
"# define SWIFT_ENUM_ATTR(_extensibility) "
2575+
"__attribute__((enum_extensibility(_extensibility)))\n"
25742576
"# else\n"
2575-
"# define SWIFT_ENUM_ATTR\n"
2577+
"# define SWIFT_ENUM_ATTR(_extensibility)\n"
25762578
"# endif\n"
25772579
"#endif\n"
25782580
"#if !defined(SWIFT_ENUM)\n"
2579-
"# define SWIFT_ENUM(_type, _name) "
2581+
"# define SWIFT_ENUM(_type, _name, _extensibility) "
25802582
"enum _name : _type _name; "
2581-
"enum SWIFT_ENUM_ATTR SWIFT_ENUM_EXTRA _name : _type\n"
2583+
"enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA "
2584+
"_name : _type\n"
25822585
"# if __has_feature(generalized_swift_name)\n"
2583-
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
2586+
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, "
2587+
"_extensibility) "
25842588
"enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); "
2585-
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR "
2586-
"SWIFT_ENUM_EXTRA _name : _type\n"
2589+
"enum SWIFT_COMPILE_NAME(SWIFT_NAME) "
2590+
"SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type\n"
25872591
"# else\n"
2588-
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) "
2589-
"SWIFT_ENUM(_type, _name)\n"
2592+
"# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, "
2593+
"_extensibility) SWIFT_ENUM(_type, _name, _extensibility)\n"
25902594
"# endif\n"
25912595
"#endif\n"
25922596
"#if !defined(SWIFT_UNAVAILABLE)\n"

test/PrintAsObjC/enums-frozen.swift

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -enable-source-import -emit-module -emit-module-doc -o %t %s -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module -enable-resilience -module-name enums
3+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -parse-as-library %t/enums.swiftmodule -typecheck -emit-objc-header-path %t/enums.h -import-objc-header %S/Inputs/enums.h -disable-objc-attr-requires-foundation-module -enable-resilience
4+
// RUN: %FileCheck %s < %t/enums.h
5+
// RUN: %check-in-clang %t/enums.h
6+
// RUN: %check-in-clang -fno-modules -Qunused-arguments %t/enums.h -include Foundation.h -include ctypes.h -include CoreFoundation.h
7+
8+
// REQUIRES: objc_interop
9+
10+
import Foundation
11+
12+
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, FrozenEnum, closed) {
13+
@objc @_frozen public enum FrozenEnum: Int {
14+
case yes
15+
case no
16+
}
17+
18+
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, NonFrozenEnum, open) {
19+
@objc public enum NonFrozenEnum: Int {
20+
case yes
21+
case no
22+
case fileNotFound
23+
}

test/PrintAsObjC/enums.swift

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import Foundation
3636
@objc func acceptMemberImported(a: Wrapper.Raw, b: Wrapper.Enum, c: Wrapper.Options, d: Wrapper.Typedef, e: Wrapper.Anon, ee: Wrapper.Anon2) {}
3737
}
3838

39-
// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcEnumNamed, "EnumNamed") {
39+
// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcEnumNamed, "EnumNamed", closed) {
4040
// CHECK-NEXT: ObjcEnumNamedA = 0,
4141
// CHECK-NEXT: ObjcEnumNamedB = 1,
4242
// CHECK-NEXT: ObjcEnumNamedC = 2,
@@ -48,7 +48,7 @@ import Foundation
4848
case A, B, C, d, helloDolly
4949
}
5050

51-
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, EnumWithNamedConstants) {
51+
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, EnumWithNamedConstants, closed) {
5252
// CHECK-NEXT: kEnumA SWIFT_COMPILE_NAME("A") = 0,
5353
// CHECK-NEXT: kEnumB SWIFT_COMPILE_NAME("B") = 1,
5454
// CHECK-NEXT: kEnumC SWIFT_COMPILE_NAME("C") = 2,
@@ -60,7 +60,7 @@ import Foundation
6060
@objc(kEnumC) case C
6161
}
6262

63-
// CHECK-LABEL: typedef SWIFT_ENUM(unsigned int, ExplicitValues) {
63+
// CHECK-LABEL: typedef SWIFT_ENUM(unsigned int, ExplicitValues, closed) {
6464
// CHECK-NEXT: ExplicitValuesZim = 0,
6565
// CHECK-NEXT: ExplicitValuesZang = 219,
6666
// CHECK-NEXT: ExplicitValuesZung = 220,
@@ -74,7 +74,7 @@ import Foundation
7474
}
7575

7676
// CHECK: /// Foo: A feer, a female feer.
77-
// CHECK-NEXT: typedef SWIFT_ENUM(NSInteger, FooComments) {
77+
// CHECK-NEXT: typedef SWIFT_ENUM(NSInteger, FooComments, closed) {
7878
// CHECK: /// Zim: A zeer, a female zeer.
7979
// CHECK-NEXT: FooCommentsZim = 0,
8080
// CHECK-NEXT: FooCommentsZang = 1,
@@ -88,7 +88,7 @@ import Foundation
8888
case Zang, Zung
8989
}
9090

91-
// CHECK-LABEL: typedef SWIFT_ENUM(int16_t, NegativeValues) {
91+
// CHECK-LABEL: typedef SWIFT_ENUM(int16_t, NegativeValues, closed) {
9292
// CHECK-NEXT: Zang = -219,
9393
// CHECK-NEXT: Zung = -218,
9494
// CHECK-NEXT: };
@@ -98,7 +98,7 @@ import Foundation
9898
func methodNotExportedToObjC() {}
9999
}
100100

101-
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, SomeError) {
101+
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, SomeError, closed) {
102102
// CHECK-NEXT: SomeErrorBadness = 9001,
103103
// CHECK-NEXT: SomeErrorWorseness = 9002,
104104
// CHECK-NEXT: };
@@ -108,15 +108,15 @@ import Foundation
108108
case Worseness
109109
}
110110

111-
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, SomeOtherError) {
111+
// CHECK-LABEL: typedef SWIFT_ENUM(NSInteger, SomeOtherError, closed) {
112112
// CHECK-NEXT: SomeOtherErrorDomain = 0,
113113
// CHECK-NEXT: };
114114
// NEGATIVE-NOT: NSString * _Nonnull const SomeOtherErrorDomain
115115
@objc enum SomeOtherError: Int, Error {
116116
case Domain // collision!
117117
}
118118

119-
// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcErrorType, "SomeRenamedErrorType") {
119+
// CHECK-LABEL: typedef SWIFT_ENUM_NAMED(NSInteger, ObjcErrorType, "SomeRenamedErrorType", closed) {
120120
// CHECK-NEXT: ObjcErrorTypeBadStuff = 0,
121121
// CHECK-NEXT: };
122122
// CHECK-NEXT: static NSString * _Nonnull const ObjcErrorTypeDomain = @"enums.SomeRenamedErrorType";
@@ -133,4 +133,3 @@ import Foundation
133133
return .Zung
134134
}
135135
}
136-

test/PrintAsObjC/swift_name.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@ public enum TestE : Int{
3838
case A1
3939
case B1
4040
}
41-
// CHECK: typedef SWIFT_ENUM(NSInteger, TestE)
41+
// CHECK: typedef SWIFT_ENUM(NSInteger, TestE, closed)
4242
// CHECK-NEXT: {{^}} A2 SWIFT_COMPILE_NAME("A1") = 0,
4343
// CHECK-NEXT: {{^}} TestEB1 = 1,

0 commit comments

Comments
 (0)