Skip to content

Commit 285a6ce

Browse files
committed
Test noescape closure capture lifetimes
1 parent 78e64fa commit 285a6ce

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

test/SILOptimizer/lifetime_dependence/semantics.swift

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ struct MutableSpan<T>: ~Escapable, ~Copyable {
7474
}
7575
}
7676

77+
extension MutableSpan {
78+
mutating func update() {}
79+
}
80+
7781
extension Array {
7882
@_lifetime(borrow self)
7983
borrowing func span() -> Span<Element> {
@@ -516,6 +520,68 @@ func testReassignToBorrowBad(span: inout Span<Int>, array: [Int]) { // expected-
516520
reassign(dest: &span, source: array.span())
517521
} // expected-note{{this use causes the lifetime-dependent value to escape}}
518522

523+
// =============================================================================
524+
// Copied dependence on mutable captures
525+
// =============================================================================
526+
527+
func runClosure(_ body: ()->()) {}
528+
529+
func testNoEscapeClosureCaptureMutation(spanArg: consuming MutableSpan<Int>) {
530+
var spanCapture = spanArg
531+
runClosure {
532+
spanCapture.update()
533+
}
534+
_ = spanCapture
535+
}
536+
537+
func testNoEscapeClosureCaptureMutationDirect(spanArg: consuming MutableSpan<Int>) {
538+
var spanCapture = spanArg;
539+
{
540+
spanCapture.update()
541+
}()
542+
_ = spanCapture
543+
}
544+
545+
func testNoEscapClosureCaptureUnsupported(spanArg: Span<Int>, array: consuming [Int]) {
546+
var spanCapture = spanArg // expected-error{{lifetime-dependent variable 'spanCapture' escapes its scope}}
547+
// expected-note@-2{{it depends on a closure capture; this is not yet supported}}
548+
_ = spanCapture;
549+
runClosure {
550+
spanCapture = array.span()
551+
} // expected-note{{this use causes the lifetime-dependent value to escape}}
552+
}
553+
554+
func testNoEscapClosureCaptureUnsupportedDirect(spanArg: Span<Int>, array: consuming [Int]) {
555+
var spanCapture = spanArg // expected-error{{lifetime-dependent variable 'spanCapture' escapes its scope}}
556+
// expected-note@-2{{it depends on a closure capture; this is not yet supported}}
557+
_ = spanCapture;
558+
{
559+
spanCapture = array.span()
560+
}() // expected-note{{this use causes the lifetime-dependent value to escape}}
561+
}
562+
563+
// 'spanBox' escapes to 'closure' before it is captured by 'escapedSpan'. The 'inout_aliasable' capture is considered
564+
// escaping because the closure contains a 'begin_access [dynamic]'.
565+
func testNoEscapClosureCaptureHasEscaped(spanArg: Span<Int>, array: consuming [Int]) {
566+
// expected-error@-1{{lifetime-dependent variable 'spanArg' escapes its scope}}
567+
// expected-note@-2{{it depends on the lifetime of argument 'spanArg'}}
568+
// expected-note@-3{{it depends on a closure capture; this is not yet supported}}
569+
var spanBox = spanArg // expected-error{{lifetime-dependent variable 'spanBox' escapes its scope}}
570+
// expected-note@-1{{it depends on a closure capture; this is not yet supported}}
571+
// expected-note@-2{{this use causes the lifetime-dependent value to escape}}
572+
let closure = { spanBox } // expected-note{{this use causes the lifetime-dependent value to escape}}
573+
574+
let escapedSpan = {
575+
spanBox = array.span() // expected-error{{lifetime-dependent value escapes its scope}}
576+
// expected-note@-1{{this use causes the lifetime-dependent value to escape}}
577+
return closure() // expected-error{{lifetime-dependent value escapes its scope}}
578+
// expected-note@-1{{it depends on the lifetime of this parent value}}
579+
// expected-note@-2{{this use causes the lifetime-dependent value to escape}}
580+
}()
581+
_ = consume array
582+
_ = escapedSpan
583+
}
584+
519585
// =============================================================================
520586
// Scoped dependence on property access
521587
// =============================================================================

test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,3 +409,23 @@ func returnTempBorrow() -> Borrow<Int> {
409409
func test(inline: InlineInt) {
410410
inline.span.withUnsafeBytes { _ = $0 }
411411
}
412+
413+
// =============================================================================
414+
// Closures
415+
// =============================================================================
416+
417+
/// Test an autoclosure that invokes a mutable method where `Self: ~Escapable`.
418+
/// The @inout_aliasable argument has an implicit @_lifetime(capture: copy capture),
419+
/// and no begin_access [dynamic] is present in the closure.
420+
extension MutableSpan {
421+
@_lifetime(self: copy self)
422+
public mutating func canUpdate() -> Bool { return true }
423+
424+
@_lifetime(self: copy self)
425+
public mutating func testAutoclosure(z: Bool) -> Bool {
426+
if z && canUpdate() {
427+
return true
428+
}
429+
return false
430+
}
431+
}

0 commit comments

Comments
 (0)