Skip to content

Commit f54c39b

Browse files
committed
Print attributes on enum cases correctly (like 'indirect')
Previously they were just skipped if enum elements weren't exploded into their own individual lines, since the ASTPrinter assumed they'd be present on the EnumCaseDecl. This led to miscompiles when using a module interface for an enum with indirect cases, since they'd be printed as non-indirect cases. rdar://problem/53329452
1 parent 10a4e3e commit f54c39b

File tree

4 files changed

+90
-3
lines changed

4 files changed

+90
-3
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -951,7 +951,8 @@ void PrintAST::printAttributes(const Decl *D) {
951951

952952
// If the declaration is implicitly @objc, print the attribute now.
953953
if (auto VD = dyn_cast<ValueDecl>(D)) {
954-
if (VD->isObjC() && !VD->getAttrs().hasAttribute<ObjCAttr>()) {
954+
if (VD->isObjC() && !isa<EnumElementDecl>(VD) &&
955+
!VD->getAttrs().hasAttribute<ObjCAttr>()) {
955956
Printer.printAttrName("@objc");
956957
Printer << " ";
957958
}
@@ -2927,8 +2928,8 @@ void PrintAST::visitEnumCaseDecl(EnumCaseDecl *decl) {
29272928
if (!elems.empty()) {
29282929
// Documentation comments over the case are attached to the enum elements.
29292930
printDocumentationComment(elems[0]);
2931+
printAttributes(elems[0]);
29302932
}
2931-
printAttributes(decl);
29322933
Printer << tok::kw_case << " ";
29332934

29342935
interleave(elems.begin(), elems.end(),

lib/AST/ASTVerifier.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2865,6 +2865,16 @@ class Verifier : public ASTWalker {
28652865
verifyParsedBase(UED);
28662866
}
28672867

2868+
void verifyParsed(EnumCaseDecl *D) {
2869+
PrettyStackTraceDecl debugStack("verifying EnumCaseDecl", D);
2870+
if (!D->getAttrs().isEmpty()) {
2871+
Out << "EnumCaseDecl should not have attributes";
2872+
abort();
2873+
}
2874+
2875+
verifyParsedBase(D);
2876+
}
2877+
28682878
void verifyParsed(AbstractFunctionDecl *AFD) {
28692879
PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD);
28702880

test/ParseableInterface/Inputs/enums-layout-helper.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,43 @@ public enum FutureproofEnum: Int {
3737
// CHECK-NEXT: case c = 100{{$}}
3838
case c = 100
3939
}
40+
41+
// CHECK-LABEL: indirect public enum FutureproofIndirectEnum
42+
public indirect enum FutureproofIndirectEnum {
43+
// CHECK-NEXT: case a{{$}}
44+
case a
45+
// CHECK-NEXT: case b(Swift.Int){{$}}
46+
case b(Int)
47+
// CHECK-NEXT: case c{{$}}
48+
case c
49+
}
50+
51+
// CHECK-LABEL: indirect public enum FrozenIndirectEnum
52+
@_frozen public indirect enum FrozenIndirectEnum {
53+
// CHECK-NEXT: case a{{$}}
54+
case a
55+
// CHECK-NEXT: case b(Swift.Int){{$}}
56+
case b(Int)
57+
// CHECK-NEXT: case c{{$}}
58+
case c
59+
}
60+
61+
// CHECK-LABEL: public enum FutureproofIndirectCaseEnum
62+
public enum FutureproofIndirectCaseEnum {
63+
// CHECK-NEXT: {{^}} case a{{$}}
64+
case a
65+
// CHECK-NEXT: indirect case b(Swift.Int){{$}}
66+
indirect case b(Int)
67+
// CHECK-NEXT: {{^}} case c{{$}}
68+
case c
69+
}
70+
71+
// CHECK-LABEL: public enum FrozenIndirectCaseEnum
72+
@_frozen public enum FrozenIndirectCaseEnum {
73+
// CHECK-NEXT: {{^}} case a{{$}}
74+
case a
75+
// CHECK-NEXT: indirect case b(Swift.Int){{$}}
76+
indirect case b(Int)
77+
// CHECK-NEXT: {{^}} case c{{$}}
78+
case c
79+
}

test/ParseableInterface/enums-layout.swift

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// RUN: %empty-directory(%t)
22
// 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 -module-name Lib
33
// 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
4+
// RUN: %target-swift-frontend -enable-objc-interop -O -emit-ir -primary-file %s -I %t -Xllvm -swiftmergefunc-threshold=0 | %FileCheck %s
55

66
import Lib
77

@@ -34,3 +34,39 @@ func testFrozenObjCEnum() -> FrozenObjCEnum {
3434
// CHECK: ret i{{32|64}} 10
3535
return .b
3636
} // CHECK-NEXT: {{^}$}}
37+
38+
// CHECK-LABEL: define{{.+}}testFutureproofIndirectEnum
39+
func testFutureproofIndirectEnum() -> FutureproofIndirectEnum {
40+
// CHECK: [[CASE:%.+]] = load i32, i32* @"$s3Lib23FutureproofIndirectEnumO1cyA2CmFWC"
41+
// CHECK: [[METADATA_RESPONSE:%.+]] = tail call swiftcc %swift.metadata_response @"$s3Lib23FutureproofIndirectEnumOMa"
42+
// CHECK: [[METADATA:%.+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
43+
// CHECK: call void {{%.+}}(%swift.opaque* noalias %0, i32 [[CASE]], %swift.type* [[METADATA]])
44+
// CHECK-NEXT: ret void
45+
return .c
46+
}
47+
48+
// CHECK-LABEL: define{{.+}}testFrozenIndirectEnum
49+
func testFrozenIndirectEnum() -> FrozenIndirectEnum {
50+
// Whether this is "1" or "2" depends on whether the reserved ObjC tagged
51+
// pointer bit is the top or bottom bit on this platform.
52+
// CHECK: ret i{{32|64}} {{1|2}}
53+
return .c
54+
}
55+
56+
// CHECK-LABEL: define{{.+}}testFutureproofIndirectCaseEnum
57+
func testFutureproofIndirectCaseEnum() -> FutureproofIndirectCaseEnum {
58+
// CHECK: [[CASE:%.+]] = load i32, i32* @"$s3Lib27FutureproofIndirectCaseEnumO1cyA2CmFWC"
59+
// CHECK: [[METADATA_RESPONSE:%.+]] = tail call swiftcc %swift.metadata_response @"$s3Lib27FutureproofIndirectCaseEnumOMa"
60+
// CHECK: [[METADATA:%.+]] = extractvalue %swift.metadata_response [[METADATA_RESPONSE]], 0
61+
// CHECK: call void {{%.+}}(%swift.opaque* noalias %0, i32 [[CASE]], %swift.type* [[METADATA]])
62+
// CHECK-NEXT: ret void
63+
return .c
64+
}
65+
66+
// CHECK-LABEL: define{{.+}}testFrozenIndirectCaseEnum
67+
func testFrozenIndirectCaseEnum() -> FrozenIndirectCaseEnum {
68+
// Whether this is "1" or "2" depends on whether the reserved ObjC tagged
69+
// pointer bit is the top or bottom bit on this platform.
70+
// CHECK: ret i{{32|64}} {{1|2}}
71+
return .c
72+
}

0 commit comments

Comments
 (0)