Skip to content

Commit 9ba1d8a

Browse files
authored
[ModuleInterface] Include the raw values of @objc enums (#24487)
...since they're part of the run-time representation. Not having this meant that someone compiling against an interface would miscompile uses of @objc enums defined in that interface! rdar://problem/50410541
1 parent 164f25e commit 9ba1d8a

File tree

5 files changed

+99
-4
lines changed

5 files changed

+99
-4
lines changed

include/swift/AST/PrintOptions.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,15 @@ struct PrintOptions {
170170
/// Whether to print variable initializers.
171171
bool VarInitializers = false;
172172

173+
/// Choices for how to print enum raw values.
174+
enum class EnumRawValueMode {
175+
Skip,
176+
PrintObjCOnly,
177+
Print
178+
};
179+
173180
/// Whether to print enum raw value expressions.
174-
bool EnumRawValues = false;
181+
EnumRawValueMode EnumRawValues = EnumRawValueMode::Skip;
175182

176183
/// Whether to prefer printing TypeReprs instead of Types,
177184
/// if a TypeRepr is available. This allows us to print the original
@@ -565,7 +572,7 @@ struct PrintOptions {
565572
static PrintOptions printQuickHelpDeclaration() {
566573
PrintOptions PO;
567574
PO.SkipUnderscoredKeywords = true;
568-
PO.EnumRawValues = true;
575+
PO.EnumRawValues = EnumRawValueMode::Print;
569576
PO.PrintImplicitAttrs = false;
570577
PO.PrintFunctionRepresentationAttrs = false;
571578
PO.PrintDocumentationComments = false;

lib/AST/ASTPrinter.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ PrintOptions PrintOptions::printParseableInterfaceFile() {
107107
result.FunctionDefinitions = true;
108108
result.CollapseSingleGetterProperty = false;
109109
result.VarInitializers = true;
110+
result.EnumRawValues = EnumRawValueMode::PrintObjCOnly;
110111
result.OpaqueReturnTypePrinting =
111112
OpaqueReturnTypePrintingMode::StableReference;
112113

@@ -2872,8 +2873,19 @@ void PrintAST::printEnumElement(EnumElementDecl *elt) {
28722873
Options.ExcludeAttrList.pop_back();
28732874
}
28742875

2876+
switch (Options.EnumRawValues) {
2877+
case PrintOptions::EnumRawValueMode::Skip:
2878+
return;
2879+
case PrintOptions::EnumRawValueMode::PrintObjCOnly:
2880+
if (!elt->isObjC())
2881+
return;
2882+
break;
2883+
case PrintOptions::EnumRawValueMode::Print:
2884+
break;
2885+
}
2886+
28752887
auto *raw = elt->getRawValueExpr();
2876-
if (!Options.EnumRawValues || !raw || raw->isImplicit())
2888+
if (!raw || raw->isImplicit())
28772889
return;
28782890

28792891
// Print the explicit raw value expression.
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// CHECK-LABEL: public enum FutureproofEnum : Int
2+
public enum FutureproofEnum: Int {
3+
// CHECK-NEXT: case a{{$}}
4+
case a = 1
5+
// CHECK-NEXT: case b{{$}}
6+
case b = 10
7+
// CHECK-NEXT: case c{{$}}
8+
case c = 100
9+
}
10+
11+
// CHECK-LABEL: public enum FrozenEnum : Int
12+
@_frozen public enum FrozenEnum: Int {
13+
// CHECK-NEXT: case a{{$}}
14+
case a = 1
15+
// CHECK-NEXT: case b{{$}}
16+
case b = 10
17+
// CHECK-NEXT: case c{{$}}
18+
case c = 100
19+
}
20+
21+
// CHECK-LABEL: public enum FutureproofObjCEnum : Int
22+
@objc public enum FutureproofObjCEnum: Int {
23+
// CHECK-NEXT: case a = 1{{$}}
24+
case a = 1
25+
// CHECK-NEXT: case b = 10{{$}}
26+
case b = 10
27+
// CHECK-NEXT: case c = 100{{$}}
28+
case c = 100
29+
}
30+
31+
// CHECK-LABEL: public enum FrozenObjCEnum : Int
32+
@_frozen @objc public enum FrozenObjCEnum: Int {
33+
// CHECK-NEXT: case a = 1{{$}}
34+
case a = 1
35+
// CHECK-NEXT: case b = 10{{$}}
36+
case b = 10
37+
// CHECK-NEXT: case c = 100{{$}}
38+
case c = 100
39+
}
40+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-module-interface-path %t/Lib.swiftinterface -typecheck -enable-library-evolution -enable-objc-interop -disable-objc-attr-requires-foundation-module -swift-version 5 %S/Inputs/enums-layout-helper.swift
3+
// RUN: %FileCheck %S/Inputs/enums-layout-helper.swift < %t/Lib.swiftinterface
4+
// RUN: %target-swift-frontend -enable-objc-interop -O -emit-ir -primary-file %s -I %t | %FileCheck %s
5+
6+
import Lib
7+
8+
// CHECK-LABEL: define{{.+}}testFutureproofEnum
9+
func testFutureproofEnum() -> FutureproofEnum {
10+
// Check a few things in the function to make sure it's getting the case
11+
// representation dynamically.
12+
// CHECK: [[CASE:%.+]] = load i32, i32* @"$s3Lib15FutureproofEnumO1byA2CmFWC"
13+
// CHECK: [[METADATA_RESPONSE:%.+]] = tail call swiftcc %swift.metadata_response @"$s3Lib15FutureproofEnumOMa"
14+
// CHECK: [[METADATA:%.+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
15+
// CHECK: tail call void {{%.+}}(%swift.opaque* noalias %0, i32 [[CASE]], %swift.type* [[METADATA]])
16+
// CHECK-NEXT: ret void
17+
return .b
18+
} // CHECK-NEXT: {{^}$}}
19+
20+
// CHECK-LABEL: define{{.+}}testFrozenEnum
21+
func testFrozenEnum() -> FrozenEnum {
22+
// CHECK: ret i8 1
23+
return .b
24+
} // CHECK-NEXT: {{^}$}}
25+
26+
// CHECK-LABEL: define{{.+}}testFutureproofObjCEnum
27+
func testFutureproofObjCEnum() -> FutureproofObjCEnum {
28+
// CHECK: ret i{{32|64}} 10
29+
return .b
30+
} // CHECK-NEXT: {{^}$}}
31+
32+
// CHECK-LABEL: define{{.+}}testFrozenObjCEnum
33+
func testFrozenObjCEnum() -> FrozenObjCEnum {
34+
// CHECK: ret i{{32|64}} 10
35+
return .b
36+
} // CHECK-NEXT: {{^}$}}

test/ParseableInterface/synthesized.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public enum HasRawValue: Int {
1616
}
1717

1818
// CHECK-LABEL: @objc public enum ObjCEnum : Int32 {
19-
// CHECK-NEXT: case a, b, c
19+
// CHECK-NEXT: case a, b = 5, c
2020
// CHECK-DAG: public typealias RawValue = Swift.Int32
2121
// CHECK-DAG: @inlinable public init?(rawValue: Swift.Int32)
2222
// CHECK-DAG: public var rawValue: Swift.Int32 {

0 commit comments

Comments
 (0)