Skip to content

Commit cfd157b

Browse files
committed
DI: Remove unnecessary assertion
It's totally fine to have a conditional destroy of 'self' because we now uniformly treat assignment to self and self.init delegation, both of which can appear multiple times in a value type initializer. This change removes the assertion and adds some tFileCheck tests to ensure that DI was already capable of inserting the correct memory management operations in this scenario. Fixes <rdar://problem/40417944>, <https://bugs.swift.org/browse/SR-7727>.
1 parent adad0f5 commit cfd157b

File tree

3 files changed

+158
-77
lines changed

3 files changed

+158
-77
lines changed

lib/SILOptimizer/Mandatory/DefiniteInitialization.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2176,9 +2176,6 @@ SILValue LifetimeChecker::handleConditionalInitAssign() {
21762176
continue;
21772177
}
21782178

2179-
assert(!TheMemory.isDelegatingInit() &&
2180-
"re-assignment of self in delegating init?");
2181-
21822179
// If this ambiguous store is only of trivial types, then we don't need to
21832180
// do anything special. We don't even need keep the init bit for the
21842181
// element precise.

test/SILOptimizer/definite_init_value_types.swift

Lines changed: 78 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,115 @@
1-
// RUN: %target-swift-frontend -emit-sil -enable-sil-ownership %s -o /dev/null -verify
1+
// RUN: %target-swift-frontend -emit-sil -enable-sil-ownership %s | %FileCheck %s
22

3-
struct EmptyStruct {}
4-
5-
struct ValueStruct {
6-
var ivar: EmptyStruct // expected-note {{'self.ivar' not initialized}}
7-
8-
init() { ivar = EmptyStruct() }
3+
enum ValueEnum {
4+
case a(String)
5+
case b
6+
case c
97

8+
init() { self = .b }
109

1110
init(a: Double) {
1211
self.init()
13-
_ = ivar // okay: ivar has been initialized by the delegation above
14-
}
15-
16-
init(a: Int) {
17-
_ = ivar // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
18-
self.init()
12+
_ = self // okay: self has been initialized by the delegation above
13+
self = .c
1914
}
2015

2116
init(a: Float) {
2217
self.init()
2318
self.init() // this is now OK
2419
}
2520

26-
init(c: Bool) {
27-
if c {
28-
return
21+
init(e: Bool) {
22+
if e {
23+
self = ValueEnum()
24+
} else {
25+
self.init()
2926
}
27+
}
3028

31-
self.init()
32-
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
33-
34-
init(d: Bool) {
35-
if d {
36-
return // expected-error {{return from initializer without initializing all stored properties}}
29+
// CHECK-LABEL: sil hidden @$S25definite_init_value_types9ValueEnumO1xACSb_tcfC : $@convention(method) (Bool, @thin ValueEnum.Type) -> @owned ValueEnum
30+
// CHECK: bb0(%0 : $Bool, %1 : $@thin ValueEnum.Type):
31+
// CHECK-NEXT: [[STATE:%.*]] = alloc_stack $Builtin.Int1
32+
// CHECK-NEXT: [[SELF_BOX:%.*]] = alloc_stack $ValueEnum
33+
// CHECK-NEXT: [[INIT_STATE:%.*]] = integer_literal $Builtin.Int1, 0
34+
// CHECK-NEXT: store [[INIT_STATE]] to [[STATE]]
35+
// CHECK: [[BOOL:%.*]] = struct_extract %0 : $Bool, #Bool._value
36+
// CHECK-NEXT: cond_br [[BOOL]], bb1, bb2
37+
// CHECK: bb1:
38+
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin ValueEnum.Type
39+
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $ValueEnum, #ValueEnum.b!enumelt
40+
// CHECK-NEXT: [[SELF_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_BOX]]
41+
// CHECK-NEXT: [[NEW_STATE:%.*]] = integer_literal $Builtin.Int1, -1
42+
// CHECK-NEXT: store [[NEW_STATE]] to [[STATE]]
43+
// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_ACCESS]]
44+
// CHECK-NEXT: end_access [[SELF_ACCESS]]
45+
// CHECK-NEXT: br bb2
46+
// CHECK: bb2:
47+
// CHECK-NEXT: [[METATYPE:%.*]] = metatype $@thin ValueEnum.Type
48+
// CHECK-NEXT: [[NEW_SELF:%.*]] = enum $ValueEnum, #ValueEnum.c!enumelt
49+
// CHECK-NEXT: [[SELF_ACCESS:%.*]] = begin_access [modify] [static] [[SELF_BOX]]
50+
// CHECK-NEXT: [[STATE_VALUE:%.*]] = load [[STATE]]
51+
// CHECK-NEXT: cond_br [[STATE_VALUE]], bb3, bb4
52+
// CHECK: bb3:
53+
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
54+
// CHECK-NEXT: br bb4
55+
// CHECK: bb4:
56+
// CHECK-NEXT: [[NEW_STATE:%.*]] = integer_literal $Builtin.Int1, -1
57+
// CHECK-NEXT: store [[NEW_STATE]] to [[STATE]]
58+
// CHECK-NEXT: store [[NEW_SELF]] to [[SELF_ACCESS]]
59+
// CHECK-NEXT: end_access [[SELF_ACCESS]]
60+
// CHECK-NEXT: retain_value [[NEW_SELF]]
61+
// CHECK-NEXT: destroy_addr [[SELF_BOX]]
62+
// CHECK-NEXT: dealloc_stack [[SELF_BOX]]
63+
// CHECK-NEXT: dealloc_stack [[STATE]]
64+
// CHECK-NEXT: return [[NEW_SELF]]
65+
init(x: Bool) {
66+
if x {
67+
self = .b
3768
}
38-
39-
self = ValueStruct()
69+
self = .c
4070
}
71+
}
72+
73+
enum AddressEnum {
74+
case a(Any)
75+
case b
76+
case c
77+
78+
init() { self = .b }
4179

4280
init(e: Bool) {
4381
if e {
44-
self.init()
82+
self = AddressEnum()
4583
} else {
46-
self = ValueStruct()
84+
self.init()
4785
}
4886
}
49-
}
5087

51-
enum ValueEnum {
52-
case Dinosaur, Train, Truck
88+
init(x: Bool) {
89+
if x {
90+
self = .b
91+
}
92+
self = .c
93+
}
94+
}
5395

54-
init() { self = .Train }
96+
struct EmptyStruct {}
5597

56-
init(a: Double) {
57-
self.init()
58-
_ = self // okay: self has been initialized by the delegation above
59-
self = .Dinosaur
60-
}
98+
struct ValueStruct {
99+
var ivar: EmptyStruct
61100

62-
init(a: Int) {
63-
_ = self // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
64-
self.init()
65-
}
101+
init() { ivar = EmptyStruct() }
66102

67103
init(a: Float) {
68104
self.init()
69-
self.init() // this is now OK
70-
}
71-
72-
init(c: Bool) {
73-
if c {
74-
return
75-
}
76-
77105
self.init()
78-
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
79-
80-
init(d: Bool) {
81-
if d {
82-
return
83-
}
84-
85-
self = ValueEnum()
86-
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
106+
}
87107

88108
init(e: Bool) {
89109
if e {
90-
self = ValueEnum()
91-
} else {
92110
self.init()
111+
} else {
112+
self = ValueStruct()
93113
}
94114
}
95115
}
@@ -100,22 +120,6 @@ struct AddressStruct {
100120

101121
init() { ivar = EmptyStruct(); any = nil }
102122

103-
init(c: Bool) {
104-
if c {
105-
return
106-
}
107-
108-
self.init()
109-
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
110-
111-
init(d: Bool) {
112-
if d {
113-
return
114-
}
115-
116-
self = AddressStruct()
117-
} // expected-error {{return from initializer without initializing all stored properties}}
118-
119123
init(e: Bool) {
120124
if e {
121125
self = AddressStruct()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// RUN: %target-swift-frontend -emit-sil -enable-sil-ownership %s -o /dev/null -verify
2+
3+
struct EmptyStruct {}
4+
5+
struct ValueStruct {
6+
var ivar: EmptyStruct // expected-note {{'self.ivar' not initialized}}
7+
8+
init() { ivar = EmptyStruct() }
9+
10+
init(a: Int) {
11+
_ = ivar // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
12+
self.init()
13+
}
14+
15+
init(c: Bool) {
16+
if c {
17+
return
18+
}
19+
20+
self.init()
21+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
22+
23+
init(d: Bool) {
24+
if d {
25+
return // expected-error {{return from initializer without initializing all stored properties}}
26+
}
27+
28+
self = ValueStruct()
29+
}
30+
}
31+
32+
enum ValueEnum {
33+
case Dinosaur, Train, Truck
34+
35+
init() { self = .Train }
36+
37+
init(a: Int) {
38+
_ = self // expected-error {{'self' used before 'self.init' call or assignment to 'self'}}
39+
self.init()
40+
}
41+
42+
init(c: Bool) {
43+
if c {
44+
return
45+
}
46+
47+
self.init()
48+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
49+
50+
init(d: Bool) {
51+
if d {
52+
return
53+
}
54+
55+
self = ValueEnum()
56+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
57+
}
58+
59+
struct AddressStruct {
60+
var ivar: EmptyStruct // expected-note {{'self.ivar' not initialized}}
61+
var any: Any?
62+
63+
init() { ivar = EmptyStruct(); any = nil }
64+
65+
init(c: Bool) {
66+
if c {
67+
return
68+
}
69+
70+
self.init()
71+
} // expected-error {{'self.init' isn't called on all paths before returning from initializer}}
72+
73+
init(d: Bool) {
74+
if d {
75+
return
76+
}
77+
78+
self = AddressStruct()
79+
} // expected-error {{return from initializer without initializing all stored properties}}
80+
}

0 commit comments

Comments
 (0)