Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d312589

Browse files
Merge pull request swiftlang#66585 from nate-chandler/rdar99681073
[MoveOnlyAddressChecker] Maximize lifetimes.
2 parents 91ee824 + 2bfa723 commit d312589

File tree

9 files changed

+1861
-53
lines changed

9 files changed

+1861
-53
lines changed

‎lib/SILOptimizer/Mandatory/MoveOnlyAddressCheckerUtils.cpp‎

Lines changed: 334 additions & 1 deletion
Large diffs are not rendered by default.

‎lib/SILOptimizer/Mandatory/MoveOnlyDiagnostics.cpp‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "MoveOnlyDiagnostics.h"
1616

17+
#include "swift/AST/Decl.h"
1718
#include "swift/AST/DiagnosticsSIL.h"
1819
#include "swift/AST/Stmt.h"
1920
#include "swift/Basic/Defer.h"
@@ -226,6 +227,12 @@ void DiagnosticEmitter::emitMissingConsumeInDiscardingContext(
226227
return true;
227228

228229
case SILLocation::RegularKind: {
230+
Decl *decl = loc.getAsASTNode<Decl>();
231+
if (decl && isa<AbstractFunctionDecl>(decl)) {
232+
// Having the function itself as a location results in a location at the
233+
// first line of the function. Find another location.
234+
return false;
235+
}
229236
Stmt *stmt = loc.getAsASTNode<Stmt>();
230237
if (!stmt)
231238
return true; // For non-statements, assume it is exiting the func.
Lines changed: 307 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,307 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) | %FileCheck %s
3+
4+
struct S : ~Copyable {
5+
let s: String
6+
init(_ s: String) { self.s = s }
7+
deinit {
8+
print("destroying \(s)")
9+
}
10+
}
11+
struct S2 : ~Copyable {
12+
var s1: S
13+
var s2: S
14+
init(_ s: String) {
15+
self.s1 = S("\(s).s1")
16+
self.s2 = S("\(s).s2")
17+
}
18+
}
19+
struct S3 : ~Copyable {
20+
var s1: S
21+
var s2: S
22+
var s3: S
23+
init(_ s: String) {
24+
self.s1 = S("\(s).s1")
25+
self.s2 = S("\(s).s2")
26+
self.s3 = S("\(s).s3")
27+
}
28+
}
29+
30+
func consumeVal(_ s: consuming S) {}
31+
func consumeVal(_ s: consuming S2) {}
32+
func borrowVal(_ s: borrowing S) {}
33+
func borrowVal(_ s: borrowing S2) {}
34+
35+
func marker(_ s: String) {
36+
print("\(#function): \(s)")
37+
}
38+
39+
// Simple test that makes sure that we still after we consume have the lifetime
40+
// of s be completely consumed by consumeVal.
41+
// CHECK: destroying simpleTestVar().first.s1
42+
// CHECK: destroying simpleTestVar().first.s2
43+
// CHECK: destroying simpleTestVar().second.s1
44+
// CHECK: destroying simpleTestVar().second.s2
45+
// CHECK: marker(_:): simpleTestVar().1
46+
@_silgen_name("simpleTestVar")
47+
func simpleTestVar() {
48+
var s = S2("\(#function).first")
49+
s = S2("\(#function).second")
50+
consumeVal(s) // Lifetime of s should end here before end of scope.
51+
marker("\(#function).1")
52+
}
53+
54+
// Simple test that proves that we can maximize lifetimes in a field sensitive
55+
// manner. Since we only consume s.s1, s.s2's lifetime should still be maximized
56+
// and be at end of scope.
57+
// CHECK: destroying simpleTestVar2().first.s1
58+
// CHECK: destroying simpleTestVar2().first.s2
59+
// CHECK: destroying simpleTestVar2().second.s1
60+
// CHECK: marker(_:): simpleTestVar2().1
61+
// CHECK: destroying simpleTestVar2().second.s2
62+
func simpleTestVar2() {
63+
var s = S2("\(#function).first")
64+
s = S2("\(#function).second")
65+
consumeVal(s.s1) // Lifetime of s1 should end here.
66+
marker("\(#function).1")
67+
// Lifetime of s2 should end at end of scope after marker.
68+
}
69+
70+
// In this case, we consume all of s by consuming s.s1 and s.s2 separately, so
71+
// all lifetimes should be done before marker.
72+
// CHECK: destroying simpleTestVar3().first.s1
73+
// CHECK: destroying simpleTestVar3().first.s2
74+
// CHECK: destroying simpleTestVar3().second.s1
75+
// CHECK: destroying simpleTestVar3().second.s2
76+
// CHECK: marker(_:): simpleTestVar3().1
77+
func simpleTestVar3() {
78+
var s = S2("\(#function).first")
79+
s = S2("\(#function).second")
80+
consumeVal(s.s1)
81+
consumeVal(s.s2)
82+
marker("\(#function).1") // Lifetimes should end before marker.
83+
}
84+
85+
// In this case, we completely consume s and then reinitialize s implying we
86+
// need to deal with two disjoint lifetimes. The second lifetime of s should end
87+
// after marker.
88+
// CHECK: destroying simpleTestVar3a().first.s1
89+
// CHECK: destroying simpleTestVar3a().first.s2
90+
// CHECK: destroying simpleTestVar3a().second.s1
91+
// CHECK: destroying simpleTestVar3a().second.s2
92+
// CHECK: marker(_:): simpleTestVar3a().1
93+
// CHECK: marker(_:): simpleTestVar3a().2
94+
// CHECK: destroying simpleTestVar3a().third.s1
95+
// CHECK: destroying simpleTestVar3a().third.s2
96+
func simpleTestVar3a() {
97+
var s = S2("\(#function).first")
98+
s = S2("\(#function).second")
99+
consumeVal(s.s1)
100+
consumeVal(s.s2)
101+
102+
marker("\(#function).1")
103+
104+
s = S2("\(#function).third")
105+
marker("\(#function).2")
106+
}
107+
108+
// In this case, we have another borrowVal of s.s2. That should still let s.s2's
109+
// lifetime end after marker.
110+
// CHECK: destroying simpleTestVar3b().first.s1
111+
// CHECK: destroying simpleTestVar3b().first.s2
112+
// CHECK: destroying simpleTestVar3b().second.s1
113+
// CHECK: marker(_:): simpleTestVar3b().1
114+
// CHECK: destroying simpleTestVar3b().second.s2
115+
func simpleTestVar3b() {
116+
var s = S2("\(#function).first")
117+
s = S2("\(#function).second")
118+
consumeVal(s.s1)
119+
borrowVal(s.s2)
120+
marker("\(#function).1") // s2 should end its lifetime after marker.
121+
}
122+
123+
// In this case, we are testing reinitialization and making sure that we can
124+
// handle two initializations properly. We also are testing conditional merge
125+
// logic. Since in both cases below s is completely consumed in b, s's lifetime
126+
// would end at marker.
127+
128+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].first.s1
129+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].first.s2
130+
// CHECK: marker(_:): simpleTestVar4(_:_:)[false, false)].1
131+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].second.s1
132+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].second.s2
133+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].third.s1
134+
// CHECK: destroying simpleTestVar4(_:_:)[false, false)].third.s2
135+
// CHECK: marker(_:): simpleTestVar4(_:_:)[false, false)].2
136+
137+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].first.s1
138+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].first.s2
139+
// CHECK: marker(_:): simpleTestVar4(_:_:)[false, true)].1
140+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].second.s1
141+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].second.s2
142+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].third.s1
143+
// CHECK: destroying simpleTestVar4(_:_:)[false, true)].third.s2
144+
145+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].first.s1
146+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].first.s2
147+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].second.s1
148+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].second.s2
149+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].third.s1
150+
// CHECK: destroying simpleTestVar4(_:_:)[true, false)].third.s2
151+
// CHECK: marker(_:): simpleTestVar4(_:_:)[true, false)].2
152+
153+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].first.s1
154+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].first.s2
155+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].second.s1
156+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].second.s2
157+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].third.s1
158+
// CHECK: destroying simpleTestVar4(_:_:)[true, true)].third.s2
159+
func simpleTestVar4(_ b1: Bool, _ b2: Bool) {
160+
var s = S2("\(#function)[\(b1), \(b2))].first")
161+
s = S2("\(#function)[\(b1), \(b2))].second")
162+
163+
if b1 {
164+
consumeVal(s)
165+
} else {
166+
marker("\(#function)[\(b1), \(b2))].1")
167+
// S's lifetime should end after marker in this block.
168+
}
169+
170+
s = S2("\(#function)[\(b1), \(b2))].third")
171+
172+
if b2 {
173+
consumeVal(s)
174+
} else {
175+
marker("\(#function)[\(b1), \(b2))].2")
176+
// S's 2nd lifetime should end after marker in this block.
177+
}
178+
}
179+
180+
// This test is similar to the previous, except we are consuming different
181+
// values along the if/else branch that completely covers the value. As a result
182+
// of this, we need to end the lifetime of s in the branches.
183+
// CHECK: destroying simpleTestVar6(_:)[false].first.s1
184+
// CHECK: destroying simpleTestVar6(_:)[false].first.s2
185+
// CHECK: destroying simpleTestVar6(_:)[false].second.s2
186+
// CHECK: marker(_:): simpleTestVar6(_:)[false].2
187+
// CHECK: destroying simpleTestVar6(_:)[false].second.s1
188+
// CHECK: destroying simpleTestVar6(_:)[false].third.s1
189+
// CHECK: destroying simpleTestVar6(_:)[false].third.s2
190+
191+
// CHECK: destroying simpleTestVar6(_:)[true].first.s1
192+
// CHECK: destroying simpleTestVar6(_:)[true].first.s2
193+
// CHECK: destroying simpleTestVar6(_:)[true].second.s1
194+
// CHECK: marker(_:): simpleTestVar6(_:)[true].1
195+
// CHECK: destroying simpleTestVar6(_:)[true].second.s2
196+
// CHECK: destroying simpleTestVar6(_:)[true].third.s1
197+
// CHECK: destroying simpleTestVar6(_:)[true].third.s2
198+
func simpleTestVar6(_ b: Bool) {
199+
var s = S2("\(#function)[\(b)].first")
200+
s = S2("\(#function)[\(b)].second")
201+
202+
if b {
203+
consumeVal(s.s1) // end of s.s1's lifetime.
204+
marker("\(#function)[\(b)].1")
205+
// s.s2 should end here.
206+
} else {
207+
consumeVal(s.s2) // end of s.s2's lifetime
208+
marker("\(#function)[\(b)].2")
209+
// end of s.s1's lifetime should end after marker.
210+
}
211+
212+
s = S2("\(#function)[\(b)].third")
213+
}
214+
215+
// In this case, we are using S3 implying we have three fields. So despite the
216+
// fact that we are deleting these two values in the if-else branches, s3's
217+
// lifetime needs to end at end of scope.
218+
// CHECK: destroying simpleTestVar6a(_:)[false].first.s1
219+
// CHECK: destroying simpleTestVar6a(_:)[false].first.s2
220+
// CHECK: destroying simpleTestVar6a(_:)[false].first.s3
221+
// CHECK: destroying simpleTestVar6a(_:)[false].second.s2
222+
// CHECK: marker(_:): simpleTestVar6a(_:)[false].2
223+
// CHECK: destroying simpleTestVar6a(_:)[false].second.s1
224+
// CHECK: marker(_:): simpleTestVar6a(_:)[false].3
225+
// CHECK: destroying simpleTestVar6a(_:)[false].second.s3
226+
227+
// CHECK: destroying simpleTestVar6a(_:)[true].first.s1
228+
// CHECK: destroying simpleTestVar6a(_:)[true].first.s2
229+
// CHECK: destroying simpleTestVar6a(_:)[true].first.s3
230+
// CHECK: destroying simpleTestVar6a(_:)[true].second.s1
231+
// CHECK: marker(_:): simpleTestVar6a(_:)[true].1
232+
// CHECK: destroying simpleTestVar6a(_:)[true].second.s2
233+
// CHECK: marker(_:): simpleTestVar6a(_:)[true].3
234+
// CHECK: destroying simpleTestVar6a(_:)[true].second.s3
235+
func simpleTestVar6a(_ b: Bool) {
236+
var s = S3("\(#function)[\(b)].first")
237+
s = S3("\(#function)[\(b)].second")
238+
239+
if b {
240+
consumeVal(s.s1) // end of s.s1's lifetime.
241+
marker("\(#function)[\(b)].1")
242+
// s.s2 should end here.
243+
} else {
244+
consumeVal(s.s2) // end of s.s2's lifetime
245+
marker("\(#function)[\(b)].2")
246+
// end of s.s1's lifetime should end after marker.
247+
}
248+
249+
marker("\(#function)[\(b)].3")
250+
// s.s3's lifetime should end here.
251+
}
252+
253+
// In this case, we are using S3, but we are consuming two disjoint parts of S
254+
// in the if statement so we cover again completely.
255+
// CHECK: destroying simpleTestVar6b(_:)[false].first.s1
256+
// CHECK: destroying simpleTestVar6b(_:)[false].first.s2
257+
// CHECK: destroying simpleTestVar6b(_:)[false].first.s3
258+
// CHECK: destroying simpleTestVar6b(_:)[false].second.s2
259+
// CHECK: marker(_:): simpleTestVar6b(_:)[false].2
260+
// CHECK: destroying simpleTestVar6b(_:)[false].second.s3
261+
// CHECK: destroying simpleTestVar6b(_:)[false].second.s1
262+
// CHECK: marker(_:): simpleTestVar6b(_:)[false].3
263+
264+
// CHECK: destroying simpleTestVar6b(_:)[true].first.s1
265+
// CHECK: destroying simpleTestVar6b(_:)[true].first.s2
266+
// CHECK: destroying simpleTestVar6b(_:)[true].first.s3
267+
// CHECK: destroying simpleTestVar6b(_:)[true].second.s1
268+
// CHECK: destroying simpleTestVar6b(_:)[true].second.s3
269+
// CHECK: marker(_:): simpleTestVar6b(_:)[true].1
270+
// CHECK: destroying simpleTestVar6b(_:)[true].second.s2
271+
// CHECK: marker(_:): simpleTestVar6b(_:)[true].3
272+
func simpleTestVar6b(_ b: Bool) {
273+
var s = S3("\(#function)[\(b)].first")
274+
s = S3("\(#function)[\(b)].second")
275+
276+
if b {
277+
consumeVal(s.s1) // end of s.s1's lifetime.
278+
consumeVal(s.s3) // end of s.s3's lifetime
279+
marker("\(#function)[\(b)].1")
280+
// s.s2 should end here.
281+
} else {
282+
consumeVal(s.s2) // end of s.s2's lifetime
283+
marker("\(#function)[\(b)].2")
284+
// end of s.s1's lifetime should end after marker.
285+
// end of s.s3's lifetime should end after marker.
286+
}
287+
288+
marker("\(#function)[\(b)].3")
289+
}
290+
291+
292+
simpleTestVar()
293+
simpleTestVar2()
294+
simpleTestVar3()
295+
simpleTestVar3a()
296+
simpleTestVar3b()
297+
simpleTestVar4(false, false)
298+
simpleTestVar4(false, true)
299+
simpleTestVar4(true, false)
300+
simpleTestVar4(true, true)
301+
simpleTestVar6(false)
302+
simpleTestVar6(true)
303+
simpleTestVar6a(false)
304+
simpleTestVar6a(true)
305+
simpleTestVar6b(false)
306+
simpleTestVar6b(true)
307+
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-run-simple-swift(-Xfrontend -sil-verify-all) | %FileCheck %s
2+
// RUN: %target-run-simple-swift(-O -Xfrontend -sil-verify-all) | %FileCheck %s
3+
4+
// REQUIRES: executable_test
5+
struct Alice: ~Copyable {
6+
var age: Int
7+
8+
init(age: Int) {
9+
print("INIT");
10+
self.age = age
11+
}
12+
13+
deinit { print("DEINIT") }
14+
}
15+
16+
func eatMe(_ alice: consuming Alice) {
17+
print(" start")
18+
print(" age:", alice.age)
19+
print(" end")
20+
}
21+
22+
func doit() {
23+
let alice = Alice(age: 10)
24+
eatMe(alice)
25+
}
26+
27+
doit()
28+
29+
// CHECK: INIT
30+
// CHECK: start
31+
// CHECK: age: 10
32+
// CHECK: end
33+
// CHECK: DEINIT

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /