mirror of
https://github.com/apple/swift.git
synced 2026-10-22 19:15:50 +02:00
Tests require the compiler built with SwiftCompilerSources since a long time. So this lit feature was redundant anyway. We can remove it.
805 lines
26 KiB
Swift
805 lines
26 KiB
Swift
// RUN: %target-swift-frontend %s -emit-sil \
|
|
// RUN: -o /dev/null \
|
|
// RUN: -verify \
|
|
// RUN: -sil-verify-all \
|
|
// RUN: -module-name test \
|
|
// RUN: -enable-builtin-module \
|
|
// RUN: -enable-experimental-feature Lifetimes \
|
|
// RUN: -enable-experimental-feature AddressableParameters \
|
|
// RUN: -enable-experimental-feature AddressableTypes
|
|
|
|
// REQUIRES: swift_feature_Lifetimes
|
|
// REQUIRES: swift_feature_AddressableParameters
|
|
// REQUIRES: swift_feature_AddressableTypes
|
|
|
|
import Builtin
|
|
|
|
struct NotEscapable: ~Escapable {
|
|
let p: UnsafeRawPointer?
|
|
}
|
|
|
|
public struct NE: ~Escapable {
|
|
let p: UnsafeRawPointer?
|
|
}
|
|
|
|
func getLocalPointer() -> UnsafeRawPointer? {
|
|
return nil
|
|
}
|
|
|
|
// Lifetime dependence semantics by example.
|
|
public struct Span<T>: ~Escapable {
|
|
private var base: UnsafePointer<T>?
|
|
private var count: Int
|
|
|
|
@_lifetime(borrow base)
|
|
init(base: UnsafePointer<T>?, count: Int) {
|
|
self.base = base
|
|
self.count = count
|
|
}
|
|
|
|
@_lifetime(borrow generic)
|
|
init<S>(base: UnsafePointer<T>?, count: Int, generic: borrowing S) {
|
|
self.base = base
|
|
self.count = count
|
|
}
|
|
|
|
public subscript(_ position: Int) -> T {
|
|
unsafeAddress {
|
|
return base!.advanced(by: position)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Span {
|
|
@_lifetime(copy self)
|
|
consuming func dropFirst() -> Span<T> {
|
|
let nextPointer = self.base.flatMap { $0 + 1 }
|
|
let local = Span(base: nextPointer, count: self.count - 1)
|
|
return _overrideLifetime(local, copying: self)
|
|
}
|
|
}
|
|
|
|
extension Span {
|
|
@_lifetime(copy self)
|
|
mutating func droppingPrefix(length: Int) -> /* */ Span<T> {
|
|
let oldBase = base
|
|
let result = Span(base: oldBase, count: length)
|
|
if let base = self.base {
|
|
self.base = base + length
|
|
self.count -= length
|
|
}
|
|
return _overrideLifetime(result, copying: self)
|
|
}
|
|
}
|
|
|
|
struct MutableSpan<T>: ~Escapable, ~Copyable {
|
|
let base: UnsafeMutablePointer<T>
|
|
let count: Int
|
|
|
|
@_lifetime(borrow base)
|
|
init(base: UnsafeMutablePointer<T>, count: Int) {
|
|
self.base = base
|
|
self.count = count
|
|
}
|
|
}
|
|
|
|
extension MutableSpan {
|
|
mutating func update() {}
|
|
}
|
|
|
|
extension Array {
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<Element> {
|
|
/* not the real implementation */
|
|
let p = self.withUnsafeBufferPointer { $0.baseAddress! }
|
|
let span = Span(base: p, count: 1)
|
|
return _overrideLifetime(span, borrowing: self)
|
|
}
|
|
}
|
|
|
|
extension Array {
|
|
@_lifetime(&self)
|
|
mutating func mutableSpan() -> MutableSpan<Element> {
|
|
/* not the real implementation */
|
|
let p = self.withUnsafeMutableBufferPointer { $0.baseAddress! }
|
|
let span = MutableSpan<Element>(base: p, count: 1)
|
|
return _overrideLifetime(span, mutating: &self)
|
|
}
|
|
}
|
|
|
|
struct InnerTrivial {
|
|
var p: UnsafePointer<Int>
|
|
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<Int> {
|
|
Span(base: p, count: 1)
|
|
}
|
|
}
|
|
|
|
struct TrivialHolder {
|
|
var p: UnsafePointer<Int>
|
|
var pa: UnsafePointer<AddressableInt>
|
|
var mp: UnsafeMutablePointer<Int>
|
|
|
|
var addressableInt: AddressableInt { unsafeAddress { pa } }
|
|
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<Int> {
|
|
Span(base: p, count: 1)
|
|
}
|
|
|
|
@_lifetime(&self)
|
|
mutating func mutableSpan() -> MutableSpan<Int> {
|
|
MutableSpan(base: mp, count: 1)
|
|
}
|
|
|
|
mutating func modify() {}
|
|
}
|
|
|
|
struct Holder {
|
|
let object: AnyObject
|
|
var p: UnsafePointer<Int>
|
|
var pa: UnsafePointer<AddressableInt>
|
|
|
|
var addressableInt: AddressableInt { unsafeAddress { pa } }
|
|
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<Int> {
|
|
Span(base: p, count: 1)
|
|
}
|
|
}
|
|
|
|
@_addressableForDependencies
|
|
struct AddressableInt {
|
|
let value: Int
|
|
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<Int> {
|
|
// TODO: we actually want the address of self.value
|
|
let p = UnsafePointer<Int>(Builtin.unprotectedAddressOfBorrow(self))
|
|
let span = Span(base: p, count: 1)
|
|
return _overrideLifetime(span, borrowing: self)
|
|
}
|
|
}
|
|
|
|
@_addressableForDependencies
|
|
struct AddressableObject {
|
|
let object: AnyObject
|
|
|
|
@_lifetime(borrow self)
|
|
borrowing func span() -> Span<AnyObject> {
|
|
// TODO: we actually want the address of self.object
|
|
let p = UnsafePointer<AnyObject>(Builtin.unprotectedAddressOfBorrow(self))
|
|
let span = Span(base: p, count: 1)
|
|
return _overrideLifetime(span, borrowing: self)
|
|
}
|
|
}
|
|
|
|
struct Outer {
|
|
var _innerTrivial: InnerTrivial
|
|
var _innerObject: Holder
|
|
let trivialPointer: UnsafePointer<InnerTrivial>
|
|
let objectPointer: UnsafePointer<Holder>
|
|
|
|
var innerTrivialAddress: InnerTrivial {
|
|
unsafeAddress {
|
|
trivialPointer
|
|
}
|
|
}
|
|
|
|
var innerObjectAddress: Holder {
|
|
unsafeAddress {
|
|
objectPointer
|
|
}
|
|
}
|
|
|
|
var innerTrivialTemp: InnerTrivial {
|
|
get { _innerTrivial }
|
|
}
|
|
|
|
var innerObjectTemp: Holder {
|
|
get { _innerObject }
|
|
}
|
|
|
|
var innerAddress: InnerTrivial {
|
|
@_addressableSelf
|
|
unsafeAddress {
|
|
UnsafePointer<InnerTrivial>(Builtin.addressOfBorrow(_innerTrivial))
|
|
}
|
|
}
|
|
}
|
|
|
|
func parse(_ span: Span<Int>) {}
|
|
|
|
@_lifetime(copy arg)
|
|
func copySpan<T>(_ arg: Span<T>) -> /* */ Span<T> { arg }
|
|
|
|
@_lifetime(borrow arg)
|
|
func reborrowSpan<T>(_ arg: Span<T>) -> Span<T> { arg }
|
|
|
|
@_lifetime(&arg)
|
|
func reborrowGenericInout<T: ~Escapable>(_ arg: inout T) -> T { arg }
|
|
|
|
@_lifetime(copy arg)
|
|
func inheritSpan<T>(_ arg: Span<T>) -> Span<T> { arg }
|
|
|
|
@_lifetime(copy arg)
|
|
func inheritGeneric<T: ~Escapable>(_ arg: consuming T) -> T { arg }
|
|
|
|
@_lifetime(&ne)
|
|
func borrowNE<T: ~Escapable>(ne: inout T) -> T {
|
|
ne
|
|
}
|
|
|
|
// =============================================================================
|
|
// Initialization
|
|
// =============================================================================
|
|
|
|
struct View: ~Escapable {
|
|
let owner: AnyObject
|
|
|
|
@_lifetime(borrow owner)
|
|
init(owner: borrowing AnyObject) {
|
|
self.owner = copy owner // OK
|
|
}
|
|
}
|
|
|
|
struct MutableView: ~Escapable, ~Copyable {
|
|
let owner: AnyObject
|
|
|
|
// A copy of a borrow is indistinguishable with the borrow scope.
|
|
@_lifetime(borrow owner)
|
|
init(owner: borrowing AnyObject) {
|
|
self.owner = copy owner // OK
|
|
}
|
|
|
|
@_lifetime(&mutableOwner)
|
|
init(mutableOwner: inout AnyObject) {
|
|
// Initialization of a ~Escapable value is unenforced. So we can initialize
|
|
// the `owner` property without locally borrowing `mutableOwner`.
|
|
self.owner = mutableOwner // OK
|
|
}
|
|
}
|
|
|
|
struct Container<T> {
|
|
var owner: AnyObject
|
|
let pointer: UnsafeMutablePointer<T>
|
|
let count: Int
|
|
}
|
|
|
|
// Dependence on an empty initialized value should be scoped to variable decl.
|
|
@_lifetime(copy x)
|
|
func f(x: NotEscapable) -> NotEscapable {
|
|
let local = NotEscapable(p: getLocalPointer()) // expected-error {{lifetime-dependent variable 'local' escapes its scope}}
|
|
// expected-note @-1{{it depends on the lifetime of this parent value}}
|
|
return local // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
// Test Optional<~E> 'var' properties.
|
|
// The initializer expressions (which return 'nil') should be considered immortal.
|
|
struct OptionalVarInit<Element: ~Escapable>: ~Escapable {
|
|
var e1: Element? = nil
|
|
var e2: Element? = nil
|
|
|
|
@_lifetime(copy e)
|
|
init(e: Element) {
|
|
e1 = e
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on values
|
|
// =============================================================================
|
|
|
|
// The duration of a scoped dependence is the lexical scope of the variable.
|
|
func testScopedLet(_ arg: [Int] ) {
|
|
let a: Array<Int> = arg
|
|
let span: Span<Int> // expected-error {{lifetime-dependent variable 'span' escapes its scope}}
|
|
do {
|
|
let a2 = a // expected-note {{it depends on the lifetime of variable 'a2'}}
|
|
span = a2.span()
|
|
}
|
|
parse(span) // expected-note {{this use of the lifetime-dependent value is out of scope}}
|
|
}
|
|
|
|
func testScopedCopy(_ arg: [Int] ) {
|
|
let a: Array<Int> = arg
|
|
let span: Span<Int> // expected-error {{lifetime-dependent variable 'span' escapes its scope}}
|
|
do {
|
|
let a2 = a // expected-note {{it depends on the lifetime of variable 'a2'}}
|
|
span = a2.span()
|
|
}
|
|
parse(span) // expected-note {{this use of the lifetime-dependent value is out of scope}}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Inherited dependence on values
|
|
// =============================================================================
|
|
|
|
func testInheritedCopy(_ arg: [Int] ) {
|
|
let a: Array<Int> = arg
|
|
let result: Span<Int>
|
|
do {
|
|
let span = a.span()
|
|
let temp = span
|
|
result = copySpan(temp)
|
|
}
|
|
parse(result) // ✅ Safe: within lifetime of 'a'
|
|
}
|
|
|
|
func testInheritedCopyVar(_ arg: [Int] ) {
|
|
let a1: Array<Int> = arg
|
|
let a2: Array<Int> = arg
|
|
var span = a1.span()
|
|
var result: Span<Int>
|
|
do {
|
|
var temp = span
|
|
result = copySpan(temp)
|
|
span = a2.span()
|
|
temp = a2.span()
|
|
// 'result' still depends on 'a1', not 'a2'
|
|
}
|
|
parse(result) // ✅ Safe: within lifetime of 'a'
|
|
}
|
|
|
|
@_lifetime(copy span)
|
|
public func testBorrowInheritedArg<T>(_ span: Span<T>) -> Span<T> {
|
|
reborrowSpan(span) // expected-error {{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of argument 'span'}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
@_lifetime(copy t)
|
|
public func testBorrowInheritedInoutArg<T: ~Escapable>(_ t: inout T) -> T {
|
|
// expected-error @-1{{lifetime-dependent variable 't' escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of argument 't'}}
|
|
reborrowGenericInout(&t)
|
|
// expected-note @-1{{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
@_lifetime(copy span)
|
|
public func testCopyInheritedArg<T>(_ span: Span<T>) -> Span<T> {
|
|
inheritSpan(span)
|
|
}
|
|
|
|
@_lifetime(copy t)
|
|
public func testCopyInheritedGenericArg<T: ~Escapable>(_ t: consuming T) -> T {
|
|
inheritGeneric(t)
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on inherited dependence
|
|
// =============================================================================
|
|
|
|
func testScopedOfInheritedWithCall(_ arg: [Int] ) {
|
|
let a: Array<Int> = arg
|
|
let span = a.span()
|
|
// TODO: should be // ✅ Safe: 'copySpan' result should be borrowed over `parse`
|
|
// rdar://128821299 ([nonescaping] extend borrowed arguments that are the source of a scoped dependence)
|
|
parse(reborrowSpan(copySpan(span))) // expected-error {{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-1{{this use of the lifetime-dependent value is out of scope}}
|
|
// expected-note @-2{{it depends on the lifetime of this parent value}}
|
|
}
|
|
|
|
func testScopedOfInheritedWithLet(_ arg: [Int] ) {
|
|
let a: Array<Int> = arg
|
|
let span = a.span()
|
|
// TODO: should be // ✅ Safe: 'copySpan' result should be borrowed over `result`
|
|
// rdar://128821299 ([nonescaping] extend borrowed arguments that are the source of a scoped dependence)
|
|
let result = reborrowSpan(copySpan(span)) // expected-error {{lifetime-dependent variable 'result' escapes its scope}}
|
|
// expected-note @-1{{it depends on the lifetime of this parent value}}
|
|
_ = result
|
|
} // expected-note {{this use of the lifetime-dependent value is out of scope}}
|
|
|
|
// Test a scoped dependence on an inherited inout argument.
|
|
//
|
|
// If testScopedOfInheritedWithLet is not an error, then its result can outlive its borrowed value:
|
|
// let ne1 = NE()
|
|
// var ne2 = ne1
|
|
// let dep = foo(ne: &ne2)
|
|
// _ = consume ne2
|
|
// _ = dep
|
|
//
|
|
@_lifetime(copy ne)
|
|
public func testScopedOfInheritedInout<T: ~Escapable>(ne: inout T) -> T {
|
|
// expected-error @-1{{lifetime-dependent variable 'ne' escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of argument 'ne'}}
|
|
borrowNE(ne: &ne)
|
|
// expected-note @-1{{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on trivial values
|
|
// =============================================================================
|
|
|
|
@_lifetime(borrow a)
|
|
func testTrivialScope<T>(a: Array<T>) -> Span<T> {
|
|
let p = a.withUnsafeBufferPointer { $0.baseAddress! }
|
|
return Span(base: p, count: 1)
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-3{{it depends on the lifetime of variable 'p'}}
|
|
// expected-note @-3{{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
extension Span {
|
|
public func withThrowingClosure<E: Error>(_ body: () throws(E) -> ()) throws(E) -> () {
|
|
try body()
|
|
}
|
|
}
|
|
|
|
// Test dependence on an local variable that needs to be extended into the dead-end block of a never-throwing apply.
|
|
public func testTrivialLocalDeadEnd(p: UnsafePointer<Int>) {
|
|
let pointer = p
|
|
let span = Span(base: pointer, count: 1)
|
|
span.withThrowingClosure {}
|
|
}
|
|
|
|
// Test dependence on a borrow of a trivial inout. The access scope can be ignored since we don't care about the
|
|
// in-memory value.
|
|
@_lifetime(&p)
|
|
public func testTrivialInoutBorrow(p: inout UnsafePointer<Int>) -> Span<Int> {
|
|
return Span(base: p, count: 1)
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on global values
|
|
// =============================================================================
|
|
|
|
private let immortalInt = 0
|
|
|
|
private let immortalStrings: [String] = []
|
|
|
|
@_lifetime(immortal)
|
|
func testImmortalInt() -> Span<Int> {
|
|
let nilBasedBuffer = UnsafeBufferPointer<Int>(start: nil, count: 0)
|
|
let span = Span(base: nilBasedBuffer.baseAddress, count: nilBasedBuffer.count)
|
|
return _overrideLifetime(span, borrowing: immortalInt)
|
|
}
|
|
|
|
@_lifetime(immortal)
|
|
func testImmortalStrings() -> Span<[String]> {
|
|
let nilBasedBuffer = UnsafeBufferPointer<[String]>(start: nil, count: 0)
|
|
let span = Span(base: nilBasedBuffer.baseAddress, count: nilBasedBuffer.count)
|
|
return _overrideLifetime(span, borrowing: immortalStrings)
|
|
}
|
|
|
|
let ptr = UnsafePointer<Int>(bitPattern: 1)!
|
|
let globalTrivial = InnerTrivial(p: ptr)
|
|
|
|
// An immortal span can depend on a caller's local borrow scope even though the callee sees no such dependency.
|
|
@_lifetime(borrow local)
|
|
func testGlobal(local: InnerTrivial) -> Span<Int> {
|
|
globalTrivial.span()
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on mutable values
|
|
// =============================================================================
|
|
|
|
@_lifetime(&a)
|
|
func testInoutBorrow(a: inout [Int]) -> Span<Int> {
|
|
a.span() // OK
|
|
}
|
|
|
|
@_lifetime(&a)
|
|
func testInoutMutableBorrow(a: inout [Int]) -> MutableSpan<Int> {
|
|
a.mutableSpan()
|
|
}
|
|
|
|
@_lifetime(&h)
|
|
func testTrivialWriteConflict(h: inout TrivialHolder) -> MutableSpan<Int> {
|
|
let span = h.mutableSpan() // expected-error{{overlapping accesses to 'h', but modification requires exclusive access; consider copying to a local variable}}
|
|
h.modify() // expected-note{{conflicting access is here}}
|
|
return span
|
|
}
|
|
|
|
func makeMutableSpan(_ p: inout UnsafeMutablePointer<UInt8>) -> MutableSpan<UInt8> {
|
|
MutableSpan(base: p, count: 1)
|
|
}
|
|
|
|
struct TestInoutUnsafePointerExclusivity {
|
|
var pointer: UnsafeMutablePointer<UInt8>
|
|
|
|
@_lifetime(&self)
|
|
mutating func testInoutUnsafePointerExclusivity() -> MutableSpan<UInt8> {
|
|
let span1 = makeMutableSpan(&self.pointer) // expected-error{{overlapping accesses to 'self.pointer', but modification requires exclusive access; consider copying to a local variable}}
|
|
_ = makeMutableSpan(&self.pointer) // expected-note{{conflicting access is here}}
|
|
return span1
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Copied dependence on mutable values
|
|
// =============================================================================
|
|
|
|
@_lifetime(dest: copy source)
|
|
func reassign<T: ~Escapable>(dest: inout T, source: T) {
|
|
dest = source
|
|
}
|
|
|
|
@_lifetime(span: borrow array)
|
|
func testReassignToBorrowGood(span: inout Span<Int>, array: [Int]) {
|
|
reassign(dest: &span, source: array.span())
|
|
}
|
|
|
|
// Reassign from a local owned value
|
|
@_lifetime(span: copy span)
|
|
func testReassignToLocal(span: inout Span<Int>) { // expected-error{{lifetime-dependent variable 'span' escapes its scope}}
|
|
let array = [1, 2] // expected-note{{it depends on the lifetime of variable 'array'}}
|
|
reassign(dest: &span, source: array.span())
|
|
} // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
|
|
@_lifetime(span: copy span)
|
|
func testReassignToConsuming(span: inout Span<Int>, array: consuming [Int]) { // expected-error{{lifetime-dependent variable 'span' escapes its}}
|
|
reassign(dest: &span, source: array.span()) // expected-note{{it depends on this scoped access to variable 'array'}}
|
|
} // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
|
|
@_lifetime(span: copy span)
|
|
func testReassignToBorrowBad(span: inout Span<Int>, array: [Int]) { // expected-error{{lifetime-dependent variable 'span' escapes its scope}}
|
|
// expected-note@-1{{it depends on the lifetime of argument 'array'}}
|
|
reassign(dest: &span, source: array.span())
|
|
} // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
|
|
// 'dest' does not depend on the function input.
|
|
@_lifetime(dest: immortal)
|
|
func noMutation<T: ~Escapable>(dest: inout T) {
|
|
dest = _overrideLifetime(dest, copying: ())
|
|
}
|
|
|
|
// OK
|
|
@_lifetime(immortal)
|
|
func testNoMutation(calleeArray: consuming [Int]) -> Span<Int> {
|
|
var span = calleeArray.span()
|
|
noMutation(dest: &span)
|
|
return span
|
|
}
|
|
|
|
// 'dest' does not depend on itself.
|
|
@_lifetime(dest: immortal, copy source)
|
|
func fullReassign<T: ~Escapable>(dest: inout T, source: T) {
|
|
dest = source
|
|
}
|
|
|
|
@_lifetime(borrow callerArray)
|
|
func testFullReassignGood(callerArray: borrowing [Int], calleeArray: consuming [Int]) -> Span<Int> {
|
|
var span = calleeArray.span()
|
|
fullReassign(dest: &span, source: callerArray.span())
|
|
return span
|
|
}
|
|
|
|
@_lifetime(immortal)
|
|
func testFullReassignBad(callerArray: borrowing [Int], calleeArray: consuming [Int]) -> Span<Int> {
|
|
var span = calleeArray.span() // expected-error{{lifetime-dependent variable 'span' escapes its scope}}
|
|
fullReassign(dest: &span, source: callerArray.span())
|
|
return span // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
// expected-note@-4{{it depends on the lifetime of argument 'callerArray'}}
|
|
}
|
|
|
|
// =============================================================================
|
|
// Copied dependence on mutable captures
|
|
// =============================================================================
|
|
|
|
func runClosure(_ body: ()->()) {}
|
|
|
|
func testNoEscapeClosureCaptureMutation(spanArg: consuming MutableSpan<Int>) {
|
|
var spanCapture = spanArg
|
|
runClosure {
|
|
spanCapture.update()
|
|
}
|
|
_ = spanCapture
|
|
}
|
|
|
|
func testNoEscapeClosureCaptureMutationDirect(spanArg: consuming MutableSpan<Int>) {
|
|
var spanCapture = spanArg;
|
|
{
|
|
spanCapture.update()
|
|
}()
|
|
_ = spanCapture
|
|
}
|
|
|
|
func testNoEscapClosureCaptureUnsupported(spanArg: Span<Int>, array: consuming [Int]) {
|
|
var spanCapture = spanArg // expected-error{{lifetime-dependent variable 'spanCapture' escapes its scope}}
|
|
// expected-note@-2{{it depends on a closure capture; this is not yet supported}}
|
|
_ = spanCapture;
|
|
runClosure {
|
|
spanCapture = array.span()
|
|
} // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
func testNoEscapClosureCaptureUnsupportedDirect(spanArg: Span<Int>, array: consuming [Int]) {
|
|
var spanCapture = spanArg // expected-error{{lifetime-dependent variable 'spanCapture' escapes its scope}}
|
|
// expected-note@-2{{it depends on a closure capture; this is not yet supported}}
|
|
_ = spanCapture;
|
|
{
|
|
spanCapture = array.span()
|
|
}() // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
}
|
|
|
|
// 'spanBox' escapes to 'closure' before it is captured by 'escapedSpan'. The 'inout_aliasable' capture is considered
|
|
// escaping because the closure contains a 'begin_access [dynamic]'.
|
|
func testNoEscapClosureCaptureHasEscaped(spanArg: Span<Int>, array: consuming [Int]) {
|
|
// expected-error@-1{{lifetime-dependent variable 'spanArg' escapes its scope}}
|
|
// expected-note@-2{{it depends on the lifetime of argument 'spanArg'}}
|
|
// expected-note@-3{{it depends on a closure capture; this is not yet supported}}
|
|
var spanBox = spanArg // expected-error{{lifetime-dependent variable 'spanBox' escapes its scope}}
|
|
// expected-note@-1{{it depends on a closure capture; this is not yet supported}}
|
|
// expected-note@-2{{this use causes the lifetime-dependent value to escape}}
|
|
let closure = { spanBox } // expected-note{{this use causes the lifetime-dependent value to escape}}
|
|
|
|
let escapedSpan = {
|
|
spanBox = array.span() // expected-error{{lifetime-dependent value escapes its scope}}
|
|
// expected-note@-1{{this use causes the lifetime-dependent value to escape}}
|
|
return closure()
|
|
}()
|
|
_ = consume array
|
|
_ = escapedSpan
|
|
}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on property access
|
|
// =============================================================================
|
|
|
|
extension Container {
|
|
@_lifetime(borrow self)
|
|
func span() -> Span<T> {
|
|
// borrowing the 'pointer' member is allowed.
|
|
Span(base: self.pointer, count: self.count) // OK
|
|
}
|
|
|
|
@_lifetime(borrow self)
|
|
func view() -> View {
|
|
// borrowing the 'view' member is allowed.
|
|
View(owner: self.owner) // OK
|
|
}
|
|
|
|
@_lifetime(&self)
|
|
mutating func mutableView() -> MutableView {
|
|
// Reading 'self.owner' creates a local borrow scope. The caller's exclusive access on 'self' is sufficient for the
|
|
// result.
|
|
MutableView(owner: self.owner) // OK
|
|
}
|
|
|
|
@_lifetime(&self)
|
|
mutating func mutableViewModifiesOwner() -> MutableView {
|
|
// Passing '&self.owner' inout creates a nested exclusive access that must extend to all uses of the new
|
|
// MutableView. This is allowed because the nested access is logically extended to the end of the function (without
|
|
// violating exclusivity).
|
|
MutableView(mutableOwner: &self.owner)
|
|
}
|
|
|
|
@_lifetime(&self)
|
|
mutating func mutableSpan() -> MutableSpan<T> {
|
|
// Reading 'self.pointer' creates a local borrow scope. The local borrow
|
|
// scope is ignored because 'pointer' is a trivial value. Instead, the new
|
|
// MutableSpan depends directly on 'inout self'.
|
|
MutableSpan(base: self.pointer, count: self.count) // OK
|
|
}
|
|
}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testBorrowStoredTrivial(outer: Outer) -> Span<Int> {
|
|
outer._innerTrivial.span()
|
|
}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testBorrowStoredObject(outer: Outer) -> Span<Int> {
|
|
outer._innerObject.span()
|
|
}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testBorrowTrivialAddressProjection(outer: Outer) -> Span<Int> {
|
|
outer.innerTrivialAddress.span()
|
|
}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testBorrowObjectAddressProjection(outer: Outer) -> Span<Int> {
|
|
outer.innerObjectAddress.span()
|
|
}
|
|
|
|
func testExprExtendTrivialTemp(outer: Outer) {
|
|
parse(outer.innerTrivialTemp.span())
|
|
}
|
|
|
|
func testExprExtendObjectTemp(outer: Outer) {
|
|
parse(outer.innerObjectTemp.span())
|
|
}
|
|
|
|
func testLocalExtendTrivialTemp(outer: Outer) {
|
|
let span = outer.innerTrivialTemp.span()
|
|
parse(span)
|
|
}
|
|
|
|
func testLocalExtendObjectTemp(outer: Outer) {
|
|
let span = outer.innerObjectTemp.span()
|
|
parse(span)
|
|
}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testReturnTrivialTemp(outer: Outer) -> Span<Int> {
|
|
outer.innerTrivialTemp.span()
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of this parent value}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
@_lifetime(borrow outer)
|
|
func testReturnObjectTemp(outer: Outer) -> Span<Int> {
|
|
outer.innerObjectTemp.span()
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of this parent value}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
// =============================================================================
|
|
// Scoped dependence on addressable parameters
|
|
// =============================================================================
|
|
|
|
// @_addressableForDependencies supports returning a Span.
|
|
@_lifetime(borrow arg)
|
|
func testAddressableInt(arg: AddressableInt) -> Span<Int> {
|
|
arg.span()
|
|
}
|
|
|
|
// @_addressableForDependencies supports returning a Span.
|
|
@_lifetime(borrow arg)
|
|
func testAddressableObject(arg: AddressableObject) -> Span<AnyObject> {
|
|
arg.span()
|
|
}
|
|
|
|
// Helper: create a dependence on the argument's address.
|
|
@_lifetime(borrow arg)
|
|
func dependsOnTrivialAddressHelper(arg: @_addressable TrivialHolder) -> Span<Int> {
|
|
arg.span()
|
|
}
|
|
|
|
// Helper: create a dependence on the argument's address.
|
|
@_lifetime(borrow arg)
|
|
func dependsOnAddressHelper(arg: @_addressable Holder) -> Span<Int> {
|
|
arg.span()
|
|
}
|
|
|
|
// Non-addressable error returning a Span.
|
|
@_lifetime(borrow arg)
|
|
func testTrivialNonAddressable(arg: TrivialHolder) -> Span<Int> {
|
|
dependsOnTrivialAddressHelper(arg: arg)
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-3{{it depends on the lifetime of argument 'arg'}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
// Non-addressable error returning a Span.
|
|
@_lifetime(borrow arg)
|
|
func testNonAddressable(arg: Holder) -> Span<Int> {
|
|
dependsOnAddressHelper(arg: arg)
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-3{{it depends on the lifetime of argument 'arg'}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
@_lifetime(&arg)
|
|
func test(arg: inout AddressableInt) -> Span<Int> {
|
|
arg.span()
|
|
}
|
|
|
|
// unsafeAddress generates an addressable value with a local scope.
|
|
func testBorrowedAddressableInt(arg: Holder) -> Int {
|
|
let span = arg.addressableInt.span()
|
|
return span[0]
|
|
}
|
|
|
|
// unsafeAddress generates an addressable value.
|
|
// Error returning a dependence on its local scope.
|
|
@_lifetime(borrow arg)
|
|
func testBorrowedAddressableIntReturn(arg: Holder) -> Span<Int> {
|
|
arg.addressableInt.span()
|
|
// expected-error @-1{{lifetime-dependent value escapes its scope}}
|
|
// expected-note @-2{{it depends on the lifetime of this parent value}}
|
|
} // expected-note {{this use causes the lifetime-dependent value to escape}}
|
|
|
|
// =============================================================================
|
|
// Closures
|
|
// =============================================================================
|
|
|
|
// Implicit dependence on a nonescaping closure context.
|
|
//
|
|
// TODO: remove the _overrideLifetime
|
|
@_lifetime(borrow value)
|
|
func testBasicClosureDependency(value: AnyObject, body: () -> NE) -> NE {
|
|
return _overrideLifetime(body(), borrowing: value)
|
|
}
|