Skip to content

Commit fe90ad5

Browse files
committed
Let indirect enum cases export spare bits
To determine the correct enum layout, we first count various categories of cases. Before, we counted indirect generic cases as "generic", but regular "generic" cases can't export spare bits. Change this to count "indirect" cases as a separate category. In particular, this ensures that fully-indirect enums use spare bits from the pointers even when some or all of the cases are generic. Resolves rdar://133890406
1 parent d1a26d0 commit fe90ad5

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

stdlib/public/RemoteInspection/TypeLowering.cpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -1960,6 +1960,7 @@ class EnumTypeInfoBuilder {
19601960
unsigned NonPayloadCases = 0; // `case a`
19611961
unsigned NonGenericEmptyPayloadCases = 0; // `case a(Void)` or `case b(Never)`
19621962
unsigned NonGenericNonEmptyPayloadCases = 0; // `case a(Int)` or `case d([Int?])`
1963+
unsigned IndirectPayloadCases = 0; // `indirect case a(T)` or `indirect case a(Int)`
19631964
unsigned GenericPayloadCases = 0; // `case a(T)` or `case a([String : (Int, T)])`
19641965

19651966
// For a single-payload enum, this is the only payload
@@ -1984,6 +1985,8 @@ class EnumTypeInfoBuilder {
19841985
// We don't have typeinfo; something is very broken.
19851986
Invalid = true;
19861987
return nullptr;
1988+
} else if (Case.Indirect) {
1989+
++IndirectPayloadCases;
19871990
} else if (Case.Generic) {
19881991
++GenericPayloadCases;
19891992
LastPayloadCaseTR = CaseTR;
@@ -2000,7 +2003,7 @@ class EnumTypeInfoBuilder {
20002003
// same as cases with no payload, and generic cases are always considered
20012004
// non-empty.
20022005
unsigned EffectiveNoPayloadCases = NonPayloadCases + NonGenericEmptyPayloadCases;
2003-
unsigned EffectivePayloadCases = GenericPayloadCases + NonGenericNonEmptyPayloadCases;
2006+
unsigned EffectivePayloadCases = IndirectPayloadCases + GenericPayloadCases + NonGenericNonEmptyPayloadCases;
20042007

20052008
if (Cases.empty()) {
20062009
return TC.makeTypeInfo<EmptyEnumTypeInfo>(Cases);
@@ -2012,7 +2015,7 @@ class EnumTypeInfoBuilder {
20122015
// with zero-sized payloads get treated for layout purposes as non-payload
20132016
// cases.
20142017
EnumKind Kind;
2015-
switch (GenericPayloadCases + NonGenericEmptyPayloadCases + NonGenericNonEmptyPayloadCases) {
2018+
switch (IndirectPayloadCases + GenericPayloadCases + NonGenericEmptyPayloadCases + NonGenericNonEmptyPayloadCases) {
20162019
case 0: Kind = EnumKind::NoPayloadEnum; break;
20172020
case 1: Kind = EnumKind::SinglePayloadEnum; break;
20182021
default: Kind = EnumKind::MultiPayloadEnum; break;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -lswiftSwiftReflectionTest %s -o %t/reflect_Enum_values12
3+
// RUN: %target-codesign %t/reflect_Enum_values12
4+
5+
// RUN: %target-run %target-swift-reflection-test %t/reflect_Enum_values12 | tee /dev/stderr | %FileCheck %s --check-prefix=CHECK%target-ptrsize --check-prefix=CHECKALL --dump-input=fail %add_num_extra_inhabitants
6+
7+
// REQUIRES: objc_interop
8+
// REQUIRES: executable_test
9+
// REQUIRES: reflection_test_support
10+
// UNSUPPORTED: use_os_stdlib
11+
// UNSUPPORTED: asan
12+
13+
import SwiftReflectionTest
14+
15+
indirect enum Outer<T> {
16+
case a(T)
17+
case b(T)
18+
}
19+
20+
class C {
21+
var outer: Outer<Int>
22+
init() { outer = .a(99) }
23+
}
24+
25+
reflect(enumValue: Outer<Int>.a(12))
26+
27+
// CHECKALL: Reflecting an enum value.
28+
// CHECKALL-NEXT: Type reference:
29+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values12.Outer
30+
// CHECKALL-NEXT: (struct Swift.Int))
31+
// CHECKALL-NEXT: Value: .a(_)
32+
33+
reflect(enumValue: Outer<Int>.b(7))
34+
35+
// CHECKALL: Reflecting an enum value.
36+
// CHECKALL-NEXT: Type reference:
37+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values12.Outer
38+
// CHECKALL-NEXT: (struct Swift.Int))
39+
// CHECKALL-NEXT: Value: .b(_)
40+
41+
reflect(enumValue: Optional<Outer<Int>>.some(.a(12)))
42+
43+
// CHECKALL: Reflecting an enum value.
44+
// CHECKALL-NEXT: Type reference:
45+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
46+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values12.Outer
47+
// CHECKALL-NEXT: (struct Swift.Int)))
48+
// CHECKALL-NEXT: Value: .some(.a(_))
49+
50+
reflect(enumValue: Optional<Outer<Int>>.some(.b(7)))
51+
52+
// CHECKALL: Reflecting an enum value.
53+
// CHECKALL-NEXT: Type reference:
54+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
55+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values12.Outer
56+
// CHECKALL-NEXT: (struct Swift.Int)))
57+
// CHECKALL-NEXT: Value: .some(.b(_))
58+
59+
reflect(enumValue: Optional<Outer<Int>>.none)
60+
61+
// CHECKALL: Reflecting an enum value.
62+
// CHECKALL-NEXT: Type reference:
63+
// CHECKALL-NEXT: (bound_generic_enum Swift.Optional
64+
// CHECKALL-NEXT: (bound_generic_enum reflect_Enum_values12.Outer
65+
// CHECKALL-NEXT: (struct Swift.Int)))
66+
// CHECKALL-NEXT: Value: .none
67+
68+
reflect(object: C())
69+
70+
// CHECKALL: Reflecting an object.
71+
// CHECKALL-NEXT: Instance pointer in child address space: 0x{{[0-9a-fA-F]+}}
72+
// CHECKALL-NEXT: Type reference:
73+
// CHECKALL-NEXT: (class reflect_Enum_values12.C)
74+
75+
// CHECKALL: Type info:
76+
77+
// CHECK64-NEXT: (class_instance size=24 alignment=8 stride=24 num_extra_inhabitants=0 bitwise_takable=1
78+
// CHECK64-NEXT: (field name=outer offset=16
79+
// CHECK64-NEXT: (multi_payload_enum size=8 alignment=8 stride=8 num_extra_inhabitants=126 bitwise_takable=1
80+
81+
// CHECK32-NEXT: (class_instance size=12 alignment=4 stride=12 num_extra_inhabitants=0 bitwise_takable=1
82+
// CHECK32-NEXT: (field name=outer offset=8
83+
// CHECK32-NEXT: (multi_payload_enum size=4 alignment=4 stride=4 num_extra_inhabitants=2 bitwise_takable=1
84+
85+
// CHECKALL-NEXT: (case name=a index=0 offset=0
86+
// CHECKALL-NEXT: (reference kind=strong refcounting=native))
87+
// CHECKALL-NEXT: (case name=b index=1 offset=0
88+
// CHECKALL-NEXT: (reference kind=strong refcounting=native)))))
89+
90+
91+
doneReflecting()
92+
93+
// CHECKALL: Done.
94+

0 commit comments

Comments
 (0)