Skip to content

Commit 03da43d

Browse files
committed
ManualOwnership: check closures
1 parent 341d531 commit 03da43d

File tree

2 files changed

+77
-17
lines changed

2 files changed

+77
-17
lines changed

lib/SILGen/SILGen.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,6 +1360,24 @@ void SILGenModule::preEmitFunction(SILDeclRef constant, SILFunction *F,
13601360
// Set our actor isolation.
13611361
F->setActorIsolation(constant.getActorIsolation());
13621362

1363+
// Closures automatically infer [manual_ownership] based on outermost func.
1364+
//
1365+
// We need to add this constraint _prior_ to emitting the closure's body,
1366+
// because the output from SILGen slightly differs because of this constraint
1367+
// when it comes to the CopyExpr and SILMoveOnlyWrappedType usage.
1368+
//
1369+
// If ManualOwnership ends up subsuming those prior mechanisms for an
1370+
// explicit-copy mode, we can move this somewhere else, like postEmitFunction.
1371+
if (auto *ace = constant.getAbstractClosureExpr()) {
1372+
if (auto *dc = ace->getOutermostFunctionContext()) {
1373+
if (auto *decl = dc->getAsDecl()) {
1374+
if (decl->getAttrs().hasAttribute<ManualOwnershipAttr>()) {
1375+
F->setPerfConstraints(PerformanceConstraints::ManualOwnership);
1376+
}
1377+
}
1378+
}
1379+
}
1380+
13631381
LLVM_DEBUG(llvm::dbgs() << "lowering ";
13641382
F->printName(llvm::dbgs());
13651383
llvm::dbgs() << " : ";

test/SIL/manual_ownership.swift

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -252,35 +252,52 @@ return (copy ref_result)[2]
252252

253253
/// MARK: closures
254254

255-
// FIXME: (1) Closure capture lists need to support the short-hand [copy t] and produce explicit copies.
256-
// We also need a better error message for when this is missed for closure captures.
257-
// (2) Escaping closures need to be recursively checked by the PerformanceDiagnostics.
258-
// We might just need to widen the propagation of [manual_ownership]?
259-
// (3) Autoclosures have no ability to annotate captures. Is that OK?
260-
261255
@_manualOwnership
262256
func closure_basic(_ t: Triangle) -> () -> Triangle {
263-
return { return t } // expected-error {{ownership of 't' is demanded by a closure}}
257+
return { // expected-error {{ownership of 't' is demanded by a closure}}
258+
return t // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
259+
}
260+
}
261+
@_manualOwnership
262+
func closure_basic_almost_fixed_1(_ t: Triangle) -> () -> Triangle {
263+
// FIXME: Closure capture lists need to support the short-hand [copy t] that makes the
264+
// closure capture parameter @owned, rather than @guaranteed. Only can work for Copyable types!
265+
return { [x = copy t] in
266+
return x // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
267+
}
264268
}
269+
270+
@_manualOwnership
271+
func closure_basic_almost_fixed_2(_ t: Triangle) -> () -> Triangle {
272+
return { // expected-error {{ownership of 't' is demanded by a closure}}
273+
return copy t
274+
}
275+
}
276+
265277
@_manualOwnership
266278
func closure_basic_fixed(_ t: Triangle) -> () -> Triangle {
267-
return { [t = copy t] in return t }
279+
return { [x = copy t] in
280+
return copy x
281+
}
268282
}
269283

270284
@_manualOwnership
271285
func closure_copies_in_body(_ t: Triangle) -> () -> Triangle {
272-
return { [t = copy t] in
273-
eat(t) // FIXME: missing required copies
274-
eat(t)
275-
return t }
286+
return { [x = copy t] in
287+
eat(x) // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
288+
use(x)
289+
eat(x) // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
290+
return x // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
291+
}
276292
}
277293

278294
@_manualOwnership
279295
func closure_copies_in_body_noescape(_ t: Triangle) -> Triangle {
280-
let f = { [t = copy t] in
281-
eat(t) // FIXME: missing required copies
282-
eat(t)
283-
return t
296+
let f = { [x = copy t] in
297+
eat(x) // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
298+
use(x)
299+
eat(x) // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
300+
return x // expected-error {{ownership of 'x' is demanded and cannot not be consumed}}
284301
}
285302
return f()
286303
}
@@ -296,7 +313,32 @@ func try_to_assert(_ n: Int, _ names: [String]) {
296313

297314
@_manualOwnership
298315
func copy_in_autoclosure(_ t: Triangle) {
299-
simple_assert(consumingFunc(t)) // FIXME: missing required copies
316+
simple_assert(consumingFunc(t)) // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
317+
}
318+
@_manualOwnership
319+
func copy_in_autoclosure_fixed(_ t: Triangle) {
320+
simple_assert(consumingFunc(copy t))
321+
}
322+
323+
@_manualOwnership
324+
func nested_closures(_ t: Triangle) -> () -> (() -> Triangle) {
325+
return { // expected-error {{ownership of 't' is demanded by a closure}}
326+
{ eat(t) }() // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
327+
return { // expected-error {{ownership of 't' is demanded by a closure}}
328+
simple_assert(consumingFunc(t)) // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
329+
return t // expected-error {{ownership of 't' is demanded and cannot not be consumed}}
330+
}
331+
}
332+
}
333+
@_manualOwnership
334+
func nested_closures_fixed(_ t: Triangle) -> () -> (() -> Triangle) {
335+
return { [a = copy t] in
336+
{ eat(copy a) }()
337+
return { [b = copy a] in
338+
simple_assert(consumingFunc(copy b))
339+
return copy b
340+
}
341+
}
300342
}
301343

302344
/// MARK: generics

0 commit comments

Comments
 (0)