Skip to content

Commit 135e02c

Browse files
committed
ManualOwnership: improve diagnostics & testing
1 parent 6b858b4 commit 135e02c

File tree

3 files changed

+133
-61
lines changed

3 files changed

+133
-61
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,17 +435,18 @@ NOTE(performance_called_from,none,
435435
"called from here", ())
436436

437437
// ManualOwnership diagnostics
438-
GROUPED_WARNING(manualownership_copy,SemanticCopies,none,
438+
GROUPED_WARNING(manualownership_copy,SemanticCopies,DefaultIgnore,
439439
"implicit 'copy' happens here; please report this vague diagnostic as a bug", ())
440-
GROUPED_WARNING(manualownership_copy_happened,SemanticCopies,none,
440+
GROUPED_WARNING(manualownership_copy_happened,SemanticCopies,DefaultIgnore,
441441
"accessing %0 may produce a copy; write 'copy' to acknowledge or 'consume' to elide", (Identifier))
442-
GROUPED_WARNING(manualownership_copy_demanded,SemanticCopies,none,
442+
GROUPED_WARNING(manualownership_copy_demanded,SemanticCopies,DefaultIgnore,
443443
"independent copy of %0 is required here; write 'copy' to acknowledge or 'consume' to elide", (Identifier))
444-
GROUPED_WARNING(manualownership_copy_captured,SemanticCopies,none,
444+
GROUPED_WARNING(manualownership_copy_captured,SemanticCopies,DefaultIgnore,
445445
"closure capture of '%0' requires independent copy of it; write [%0 = copy %0] in the closure's capture list to acknowledge", (StringRef))
446-
GROUPED_WARNING(manualownership_exclusivity,DynamicExclusivity,none,
447-
"exclusive access here will be checked at runtime", ())
448-
GROUPED_WARNING(manualownership_exclusivity_named,DynamicExclusivity,none,
446+
447+
GROUPED_WARNING(manualownership_exclusivity,DynamicExclusivity,DefaultIgnore,
448+
"exclusive access here will be checked at runtime; please report this vague diagnostic as a bug", ())
449+
GROUPED_WARNING(manualownership_exclusivity_named,DynamicExclusivity,DefaultIgnore,
449450
"accessing %0 here may incur runtime exclusivity check%1", (Identifier, StringRef))
450451

451452
// 'transparent' diagnostics

test/SIL/manual_ownership.swift

Lines changed: 53 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-swift-frontend %s -emit-sil -verify \
2-
// RUN: -Werror SemanticCopies \
3-
// RUN: -Werror DynamicExclusivity \
4-
// RUN: -enable-experimental-feature ManualOwnership
2+
// RUN: -enable-experimental-feature ManualOwnership \
3+
// RUN: -Wwarning SemanticCopies
54

65
// REQUIRES: swift_feature_ManualOwnership
76

@@ -53,7 +52,7 @@ public func basic_return1() -> Triangle {
5352

5453
@_manualOwnership
5554
public func basic_return2(t: Triangle) -> Triangle {
56-
return t // expected-error {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
55+
return t // expected-warning {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
5756
}
5857
@_manualOwnership
5958
public func basic_return2_fixed(t: Triangle) -> Triangle {
@@ -67,7 +66,7 @@ public func basic_return3() -> Triangle {
6766

6867
@_manualOwnership
6968
func return_borrowed(_ t: borrowing Triangle) -> Triangle {
70-
return t // expected-error {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
69+
return t // expected-warning {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
7170
}
7271
@_manualOwnership
7372
func return_borrowed_fixed(_ t: borrowing Triangle) -> Triangle {
@@ -77,7 +76,7 @@ func return_borrowed_fixed(_ t: borrowing Triangle) -> Triangle {
7776
// FIXME: there's no workaround to this; it acts like a var so it's the same class of problem (rdar://161359163)
7877
@_manualOwnership
7978
func return_consumingParam(_ t: consuming Triangle) -> Triangle {
80-
return t // expected-error {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
79+
return t // expected-warning {{independent copy of 't' is required here; write 'copy' to acknowledge or 'consume' to elide}}
8180
}
8281
@_manualOwnership
8382
func return_consumingParam_no_workaround(_ t: consuming Triangle) -> Triangle {
@@ -102,8 +101,8 @@ func renamed_return(_ cond: Bool, _ a: Triangle) -> Triangle {
102101
let b = a
103102
let c = b
104103
// FIXME: we say 'c' instead of 'b', because of the propagation. (rdar://161360537)
105-
if cond { return b } // expected-error {{independent copy of 'c' is required}}
106-
return c // expected-error {{independent copy of 'c' is required}}
104+
if cond { return b } // expected-warning {{independent copy of 'c' is required}}
105+
return c // expected-warning {{independent copy of 'c' is required}}
107106
}
108107

109108
@_manualOwnership
@@ -135,7 +134,7 @@ func basic_methods_borrowing(_ t1: Triangle) {
135134
@_manualOwnership
136135
func basic_methods_consuming(_ t1: Triangle) {
137136
let t2 = Triangle()
138-
t1.consuming() // expected-error {{independent copy of 't1' is required}}
137+
t1.consuming() // expected-warning {{independent copy of 't1' is required}}
139138
t2.consuming()
140139
}
141140
@_manualOwnership
@@ -163,7 +162,7 @@ func plainFunc(_ t0: Triangle) {}
163162

164163
@_manualOwnership
165164
func basic_function_call(_ t1: Triangle) {
166-
consumingFunc(t1) // expected-error {{independent copy of 't1' is required}}
165+
consumingFunc(t1) // expected-warning {{independent copy of 't1' is required}}
167166
consumingFunc(copy t1)
168167
plainFunc(t1)
169168
}
@@ -173,8 +172,8 @@ func basic_function_call(_ t1: Triangle) {
173172
@_manualOwnership
174173
func check_vars(_ t: Triangle, _ b: Bool) -> Triangle {
175174
var x = Triangle()
176-
if b { x = t } // expected-error {{independent copy of 't' is required}}
177-
return x // expected-error {{independent copy of 'x' is required}}
175+
if b { x = t } // expected-warning {{independent copy of 't' is required}}
176+
return x // expected-warning {{independent copy of 'x' is required}}
178177
}
179178
@_manualOwnership
180179
func check_vars_fixed(_ t: Triangle, _ b: Bool) -> Triangle {
@@ -190,7 +189,7 @@ func check_vars_fixed(_ t: Triangle, _ b: Bool) -> Triangle {
190189
func reassignments_0() -> Triangle {
191190
var t3 = Triangle()
192191
t3 = Triangle()
193-
return t3 // expected-error {{independent copy of 't3' is required}}
192+
return t3 // expected-warning {{independent copy of 't3' is required}}
194193
}
195194
@_manualOwnership
196195
func reassignments_0_fixed_1() -> Triangle {
@@ -209,7 +208,7 @@ func reassignments_0_fixed_2() -> Triangle {
209208
func reassignments_1() {
210209
var t3 = Triangle()
211210
t3 = Triangle()
212-
t3.borrowing() // expected-error {{accessing 't3' may produce a copy; write 'copy' to acknowledge or 'consume' to elide}}
211+
t3.borrowing() // expected-warning {{accessing 't3' may produce a copy; write 'copy' to acknowledge or 'consume' to elide}}
213212
}
214213
@_manualOwnership
215214
func reassignments_1_fixed_1() {
@@ -226,19 +225,19 @@ func reassignments_1_fixed_2() {
226225

227226
@_manualOwnership
228227
public func basic_loop_trivial_values(_ t: Triangle, _ xs: [Triangle]) {
229-
var p: Pair = t.a // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
230-
for x in xs { // expected-error {{independent copy of 'xs' is required}}
231-
p = p.midpoint(x.a) // expected-error {{accessing 'x.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
228+
var p: Pair = t.a
229+
for x in xs { // expected-warning {{independent copy of 'xs' is required}}
230+
p = p.midpoint(x.a)
232231
}
233-
t.a = p // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
232+
t.a = p
234233
}
235234
@_manualOwnership
236235
public func basic_loop_trivial_values_fixed(_ t: Triangle, _ xs: [Triangle]) {
237-
var p: Pair = t.a // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
236+
var p: Pair = t.a
238237
for x in copy xs {
239-
p = p.midpoint(x.a) // expected-error {{accessing 'x.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
238+
p = p.midpoint(x.a)
240239
}
241-
t.a = p // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
240+
t.a = p
242241
}
243242

244243
// FIXME: the only reason for so many copies below is because
@@ -249,11 +248,11 @@ public func basic_loop_trivial_values_fixed(_ t: Triangle, _ xs: [Triangle]) {
249248

250249
@_manualOwnership
251250
public func basic_loop_nontrivial_values(_ t: Triangle, _ xs: [Triangle]) {
252-
var p: Pair = t.nontrivial.a // expected-error {{accessing 't.nontrivial' may produce a copy}}
253-
for x in xs { // expected-error {{independent copy of 'xs' is required}}
254-
p = p.midpoint(x.nontrivial.a) // expected-error {{accessing 'x.nontrivial' may produce a copy}}
251+
var p: Pair = t.nontrivial.a // expected-warning {{accessing 't.nontrivial' may produce a copy}}
252+
for x in xs { // expected-warning {{independent copy of 'xs' is required}}
253+
p = p.midpoint(x.nontrivial.a) // expected-warning {{accessing 'x.nontrivial' may produce a copy}}
255254
}
256-
t.nontrivial.a = p // expected-error {{accessing 't.nontrivial' may produce a copy}}
255+
t.nontrivial.a = p // expected-warning {{accessing 't.nontrivial' may produce a copy}}
257256
}
258257

259258
@_manualOwnership
@@ -268,10 +267,10 @@ public func basic_loop_nontrivial_values_fixed(_ t: Triangle, _ xs: [Triangle])
268267
@_manualOwnership
269268
public func basic_loop_nontrivial_values_reduced_copies(_ t: Triangle, _ xs: [Triangle]) {
270269
// FIXME: confusing variable names are chosen (rdar://161360537)
271-
let nt = t.nontrivial // expected-error {{accessing 'nt' may produce a copy}}
270+
let nt = t.nontrivial // expected-warning {{accessing 'nt' may produce a copy}}
272271
var p: Pair = nt.a
273272
for x in copy xs {
274-
let xnt = x.nontrivial // expected-error {{accessing 'xnt' may produce a copy}}
273+
let xnt = x.nontrivial // expected-warning {{accessing 'xnt' may produce a copy}}
275274
p = p.midpoint(xnt.a)
276275
}
277276
nt.a = p
@@ -295,7 +294,7 @@ let ref_result = [5, 13, 29]
295294
// are present to avoid exclusivity issues. We'd need to start generating read coroutines.
296295
@_manualOwnership
297296
func access_global_1() -> Int {
298-
return ref_result[2] // expected-error {{accessing 'ref_result' may produce a copy}}
297+
return ref_result[2] // expected-warning {{accessing 'ref_result' may produce a copy}}
299298
}
300299
@_manualOwnership
301300
func access_global_1_fixed() -> Int {
@@ -306,22 +305,22 @@ return (copy ref_result)[2]
306305

307306
@_manualOwnership
308307
func closure_basic(_ t: Triangle) -> () -> Triangle {
309-
return { // expected-error {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
310-
return t // expected-error {{independent copy of 't' is required}}
308+
return { // expected-warning {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
309+
return t // expected-warning {{independent copy of 't' is required}}
311310
}
312311
}
313312
@_manualOwnership
314313
func closure_basic_almost_fixed_1(_ t: Triangle) -> () -> Triangle {
315314
// FIXME: Closure capture lists need to support the short-hand [copy t] that makes the
316315
// closure capture parameter @owned, rather than @guaranteed. Only can work for Copyable types!
317316
return { [x = copy t] in
318-
return x // expected-error {{independent copy of 'x' is required}}
317+
return x // expected-warning {{independent copy of 'x' is required}}
319318
}
320319
}
321320

322321
@_manualOwnership
323322
func closure_basic_almost_fixed_2(_ x: Triangle) -> () -> Triangle {
324-
return { // expected-error {{closure capture of 'x' requires independent copy of it; write [x = copy x]}}
323+
return { // expected-warning {{closure capture of 'x' requires independent copy of it; write [x = copy x]}}
325324
return copy x
326325
}
327326
}
@@ -336,20 +335,20 @@ func closure_basic_fixed(_ t: Triangle) -> () -> Triangle {
336335
@_manualOwnership
337336
func closure_copies_in_body(_ t: Triangle) -> () -> Triangle {
338337
return { [x = copy t] in
339-
eat(x) // expected-error {{independent copy of 'x' is required}}
338+
eat(x) // expected-warning {{independent copy of 'x' is required}}
340339
use(x)
341-
eat(x) // expected-error {{independent copy of 'x' is required}}
342-
return x // expected-error {{independent copy of 'x' is required}}
340+
eat(x) // expected-warning {{independent copy of 'x' is required}}
341+
return x // expected-warning {{independent copy of 'x' is required}}
343342
}
344343
}
345344

346345
@_manualOwnership
347346
func closure_copies_in_body_noescape(_ t: Triangle) -> Triangle {
348347
let f = { [x = copy t] in
349-
eat(x) // expected-error {{independent copy of 'x' is required}}
348+
eat(x) // expected-warning {{independent copy of 'x' is required}}
350349
use(x)
351-
eat(x) // expected-error {{independent copy of 'x' is required}}
352-
return x // expected-error {{independent copy of 'x' is required}}
350+
eat(x) // expected-warning {{independent copy of 'x' is required}}
351+
return x // expected-warning {{independent copy of 'x' is required}}
353352
}
354353
return f()
355354
}
@@ -365,7 +364,7 @@ func try_to_assert(_ n: Int, _ names: [String]) {
365364

366365
@_manualOwnership
367366
func copy_in_autoclosure(_ t: Triangle) {
368-
simple_assert(consumingFunc(t)) // expected-error {{independent copy of 't' is required}}
367+
simple_assert(consumingFunc(t)) // expected-warning {{independent copy of 't' is required}}
369368
}
370369
@_manualOwnership
371370
func copy_in_autoclosure_fixed(_ t: Triangle) {
@@ -374,11 +373,11 @@ func copy_in_autoclosure_fixed(_ t: Triangle) {
374373

375374
@_manualOwnership
376375
func nested_closures(_ t: Triangle) -> () -> (() -> Triangle) {
377-
return { // expected-error {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
378-
{ eat(t) }() // expected-error {{independent copy of 't' is required}}
379-
return { // expected-error {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
380-
simple_assert(consumingFunc(t)) // expected-error {{independent copy of 't' is required}}
381-
return t // expected-error {{independent copy of 't' is required}}
376+
return { // expected-warning {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
377+
{ eat(t) }() // expected-warning {{independent copy of 't' is required}}
378+
return { // expected-warning {{closure capture of 't' requires independent copy of it; write [t = copy t]}}
379+
simple_assert(consumingFunc(t)) // expected-warning {{independent copy of 't' is required}}
380+
return t // expected-warning {{independent copy of 't' is required}}
382381
}
383382
}
384383
}
@@ -397,7 +396,7 @@ func nested_closures_fixed(_ t: Triangle) -> () -> (() -> Triangle) {
397396

398397
@_manualOwnership
399398
func return_generic<T>(_ t: T) -> T {
400-
return t // expected-error {{accessing 't' may produce a copy}}
399+
return t // expected-warning {{accessing 't' may produce a copy}}
401400
}
402401
@_manualOwnership
403402
func return_generic_fixed<T>(_ t: T) -> T {
@@ -406,9 +405,9 @@ func return_generic_fixed<T>(_ t: T) -> T {
406405

407406
@_manualOwnership
408407
func reassign_with_lets<T>(_ t: T) -> T {
409-
let x = t // expected-error {{accessing 't' may produce a copy}}
410-
let y = x // expected-error {{accessing 'x' may produce a copy}}
411-
let z = y // expected-error {{accessing 'y' may produce a copy}}
408+
let x = t // expected-warning {{accessing 't' may produce a copy}}
409+
let y = x // expected-warning {{accessing 'x' may produce a copy}}
410+
let z = y // expected-warning {{accessing 'y' may produce a copy}}
412411
return copy z
413412
}
414413

@@ -423,9 +422,9 @@ func reassign_with_lets_fixed<T>(_ t: T) -> T {
423422

424423
@_manualOwnership
425424
func copy_generic<T>(_ t: T) {
426-
consume_generic(t) // expected-error {{accessing 't' may produce a copy}}
425+
consume_generic(t) // expected-warning {{accessing 't' may produce a copy}}
427426
borrow_generic(t)
428-
consume_generic(t) // expected-error {{accessing 't' may produce a copy}}
427+
consume_generic(t) // expected-warning {{accessing 't' may produce a copy}}
429428
}
430429

431430
@_manualOwnership
@@ -439,10 +438,10 @@ func copy_generic_fixed<T>(_ t: T) {
439438
func benchCaptureProp<S : Sequence>(
440439
_ s: S, _ f: (S.Element, S.Element) -> S.Element) -> S.Element {
441440

442-
var it = s.makeIterator() // expected-error {{accessing 's' may produce a copy}}
441+
var it = s.makeIterator() // expected-warning {{accessing 's' may produce a copy}}
443442
let initial = it.next()!
444443
return
445-
IteratorSequence(it) // expected-error {{accessing 'it' may produce a copy}}
444+
IteratorSequence(it) // expected-warning {{accessing 'it' may produce a copy}}
446445
.reduce(initial, f)
447446
}
448447
@_manualOwnership
@@ -474,8 +473,8 @@ struct CollectionOf32BitLittleEndianIntegers<BaseCollection: Collection> where B
474473
@_manualOwnership
475474
init(_ baseCollection: BaseCollection) {
476475
precondition(baseCollection.count % 4 == 0)
477-
self.baseCollection = baseCollection // expected-error {{accessing 'baseCollection' may produce a copy}}
478-
} // expected-error {{accessing 'self' may produce a copy}}
476+
self.baseCollection = baseCollection // expected-warning {{accessing 'baseCollection' may produce a copy}}
477+
} // expected-warning {{accessing 'self' may produce a copy}}
479478

480479
// FIXME: the above initializer shouldn't have any diagnostics
481480
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// RUN: %target-swift-frontend %s -emit-sil -verify \
2+
// RUN: -enable-experimental-feature ManualOwnership \
3+
// RUN: -Wwarning DynamicExclusivity
4+
5+
// REQUIRES: swift_feature_ManualOwnership
6+
7+
protocol NutritionInfo {
8+
var calories: Int { get }
9+
}
10+
11+
public class Food: NutritionInfo {
12+
var calories = 0
13+
}
14+
15+
public class Donut : Food {
16+
17+
let next: Donut? = nil
18+
19+
override init() {
20+
super.init()
21+
self.calories = 100
22+
}
23+
24+
convenience init(calories c: Int) {
25+
self.init()
26+
self.calories = c
27+
}
28+
}
29+
30+
extension Int { func greaterThanZero() -> Bool { self > 0 } }
31+
32+
var expectedCalories: Array<Int> = [120, 203, 1502]
33+
34+
@_manualOwnership
35+
func accessGlobal_map() -> Array<Donut> {
36+
return expectedCalories.map(Donut.init(calories:)) // expected-warning {{accessing 'expectedCalories' here may incur runtime exclusivity check, because it involves a global variable}}
37+
}
38+
39+
@_manualOwnership
40+
func accessGlobal_member() -> Int {
41+
return expectedCalories.count // expected-warning {{accessing 'expectedCalories' here may incur runtime exclusivity check, because it involves a global variable}}
42+
}
43+
44+
var globalDonut: Donut = Donut()
45+
46+
@_manualOwnership
47+
func accessGlobalClass() {
48+
let x = globalDonut.calories // expected-warning {{accessing 'globalDonut' here may incur runtime exclusivity check, because it involves a global variable}}
49+
// expected-warning@-1 {{exclusive access here will be checked at runtime}}
50+
51+
expectedCalories.append(x) // expected-warning {{accessing 'expectedCalories' here may incur runtime exclusivity check, because it involves a global variable}}
52+
}
53+
54+
@_manualOwnership
55+
func accessClassSimple(_ d2: Donut) -> Int {
56+
let d1 = Donut()
57+
return d1.calories // expected-warning {{exclusive access here will be checked at runtime}}
58+
+ d2.calories // expected-warning {{exclusive access here will be checked at runtime}}
59+
}
60+
61+
@_manualOwnership
62+
func accessClassParam_chain(_ donut: Donut) -> Int {
63+
return donut.next?.next?.calories ?? Int.max
64+
// expected-warning@-1 {{exclusive access here will be checked at runtime}}
65+
}
66+
67+
@_manualOwnership
68+
func accessClassLocal_chain() -> Int {
69+
let donut = Donut()
70+
return donut.next?.next?.calories ?? Int.max
71+
// expected-warning@-1 {{exclusive access here will be checked at runtime}}
72+
}

0 commit comments

Comments
 (0)