Skip to content

Commit 3baa54f

Browse files
authored
Print attributes on enum cases correctly (like 'indirect') (#26325)
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 (cherry picked from commit 3596df7)
1 parent ad9a453 commit 3baa54f

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
}
@@ -2920,8 +2921,8 @@ void PrintAST::visitEnumCaseDecl(EnumCaseDecl *decl) {
29202921
if (!elems.empty()) {
29212922
// Documentation comments over the case are attached to the enum elements.
29222923
printDocumentationComment(elems[0]);
2924+
printAttributes(elems[0]);
29232925
}
2924-
printAttributes(decl);
29252926
Printer << tok::kw_case << " ";
29262927

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

lib/AST/ASTVerifier.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2896,6 +2896,16 @@ class Verifier : public ASTWalker {
28962896
verifyParsedBase(UED);
28972897
}
28982898

2899+
void verifyParsed(EnumCaseDecl *D) {
2900+
PrettyStackTraceDecl debugStack("verifying EnumCaseDecl", D);
2901+
if (!D->getAttrs().isEmpty()) {
2902+
Out << "EnumCaseDecl should not have attributes";
2903+
abort();
2904+
}
2905+
2906+
verifyParsedBase(D);
2907+
}
2908+
28992909
void verifyParsed(AbstractFunctionDecl *AFD) {
29002910
PrettyStackTraceDecl debugStack("verifying AbstractFunctionDecl", AFD);
29012911

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)