// RUN: %empty-directory(%t) // RUN: %target-swift-frontend %S/../Inputs/resilient_struct.swift -enable-library-evolution -emit-module -emit-module-path %t/resilient_struct.swiftmodule // RUN: %target-swift-frontend %S/../Inputs/resilient_enum.swift -I %t -enable-library-evolution -emit-module -emit-module-path %t/resilient_enum.swiftmodule // RUN: %target-swift-frontend %s -sil-verify-all -Xllvm -sil-print-types -emit-sil -enable-copy-propagation=false -I %t -o - | %FileCheck %s // Using -enable-copy-propagation=false to pattern match against older SIL // output. At least until -enable-copy-propagation has been around // long enough in the same form to be worth rewriting CHECK lines. import resilient_struct import resilient_enum func use_closure(_ c : () -> () ) { c() } func use_closureGeneric(_ c : () -> T ) { _ = c() } public class C { func doIt() {} func returnInt() -> Int { return 0 } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup10testSimple1cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () { // CHECK: bb0([[ARG:%.*]] : $C): // CHECK: [[F:%.*]] = function_ref @$s22closure_lifetime_fixup10testSimple1cyAA1CC_tFyyXEfU_ // CHECK-NEXT: strong_retain [[ARG]] : $C // CHECK-NEXT: [[PA:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[F]]([[ARG]]) : $@convention(thin) (@guaranteed C) -> () // CHECK-NEXT: [[CL:%.*]] = mark_dependence [[PA]] : $@noescape @callee_guaranteed () -> () on [[ARG]] : $C // CHECK-NEXT: // function_ref use_closure(_:) // CHECK-NEXT: [[F2:%.*]] = function_ref @$s22closure_lifetime_fixup04use_A0yyyyXEF : // CHECK-NEXT: apply [[F2]]([[CL]]) : // CHECK-NEXT: dealloc_stack [[PA]] : $@noescape @callee_guaranteed () -> () // CHECK-NEXT: strong_release [[ARG]] : $C // CHECK-NEXT: tuple () // CHECK-NEXT: return {{.*}} : $() public func testSimple(c: C) { use_closure { c.doIt() } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup11testGeneric1cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () { // CHECK:bb0([[ARG:%.*]] : $C): // CHECK: [[F:%.*]] = function_ref @$s22closure_lifetime_fixup11testGeneric1cyAA1CC_tFSiyXEfU_ : $@convention(thin) @substituted <τ_0_0> (@guaranteed C) -> @out τ_0_0 for // CHECK-NEXT: strong_retain [[ARG]] : $C // CHECK-NEXT: [[PA:%.*]] = partial_apply [callee_guaranteed] [on_stack] [[F]]([[ARG]]) : // CHECK-NEXT: [[MD:%.*]] = mark_dependence [[PA]] : $@noescape @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for on [[ARG]] : $C // CHECK-NEXT: // function_ref use_closureGeneric(_:) // CHECK-NEXT: [[F2:%.*]] = function_ref @$s22closure_lifetime_fixup04use_A7GenericyyxyXElF : // CHECK-NEXT: apply [[F2]]([[MD]]) : // CHECK-NEXT: dealloc_stack [[PA]] // CHECK-NEXT: strong_release [[ARG]] // CHECK-NEXT: tuple () // CHECK-NEXT: return {{.*}} : $() public func testGeneric(c: C) { use_closureGeneric { return c.returnInt() } } public protocol P { associatedtype Element subscript(a: (Element) -> U, b: (U) -> Element) -> U { get set } } // Make sure we keep the closure alive up until after the write back. // CHECK-LABEL: sil @$s22closure_lifetime_fixup10testModify1pyxz_tAA1PRzSS7ElementRtzlF : $@convention(thin) (@inout T) -> () { // CHECK: bb0 // CHECK: [[PA1:%.*]] = partial_apply [callee_guaranteed] // CHECK: [[CF1:%.*]] = convert_function [[PA1]] // CHECK: [[CVT1:%.*]] = convert_escape_to_noescape [[CF1]] // CHECK: [[PA2:%.*]] = partial_apply [callee_guaranteed] // CHECK: [[CF2:%.*]] = convert_function [[PA2]] // CHECK: [[CVT2:%.*]] = convert_escape_to_noescape [[CF2]] // CHECK: [[W:%.*]] = witness_method $T, #P.subscript!modify // CHECK: ([[BUFFER:%.*]], [[TOKEN:%.*]]) = begin_apply [[W]]([[CVT1]], [[CVT2]], {{.*}}) // CHECK: end_apply [[TOKEN]] // CHECK: strong_release [[CF1]] // CHECK: strong_release [[CF2]] public func testModify(p: inout T) where T.Element == String { p[{Int($0)!}, {String($0)}] += 1 } public func dontCrash(test: Bool, body: @escaping ((In) -> Out, In) -> Out ) -> (In) -> Out { var result: ((In) -> Out)! result = { (x: In) in if test { return body(result, x) } let r = body(result, x) return r } return result } // CHECK-LABEL: sil @$s22closure_lifetime_fixup28to_stack_of_convert_function1pySvSg_tF // CHECK: [[FN:%.*]] = function_ref @$s22closure_lifetime_fixup28to_stack_of_convert_function1pySvSg_tFSSSvcfu_ : // CHECK: [[PA:%.*]] = thin_to_thick_function [[FN]] // CHECK: [[MAP:%.*]] = function_ref @$sSq3mapyqd_0_Sgqd_0_xqd__YKXEqd__YKs5ErrorRd__Ri_d_0_r0_lF // CHECK: try_apply [[MAP]]({{.*}}, [[PA]], {{.*}}) public func to_stack_of_convert_function(p: UnsafeMutableRawPointer?) { _ = p.map(String.init(describing:)) } public func no_dealloc_stack_before_unreachable(_ message: String, fileName: StaticString = #file, lineNumber: Int = #line) -> Never { Swift.fatalError(message, file: fileName, line: UInt(lineNumber)) } // Make sure closures are allocated on the stack. func useClosure(_ c: () -> ()) { } func useClosureThrowing(_ c: () throws -> ()) throws { } func useGenericClosure(_ c : (T) -> V) { } func useGenericClosureThrowing(_ c: (T) throws -> V) throws { } // CHECK-LABEL: sil @$s22closure_lifetime_fixup12captureClass1c1dyAA1CC_AFtKF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup10useClosureyyyyXEF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup18useClosureThrowingyyyyKXEKF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytytIegnr_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup17useGenericClosureyyq_xXEr0_lF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytyts5Error_pIegnrzo_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup25useGenericClosureThrowingyyq_xKXEKr0_l public func captureClass(c: C, d: C) throws { useClosure { c.doIt() d.doIt() } try useClosureThrowing { c.doIt() d.doIt() } useGenericClosure { c.doIt() d.doIt() } try useGenericClosureThrowing { c.doIt() d.doIt() } } public protocol DoIt { func doIt() } // CHECK-LABEL: sil @$s22closure_lifetime_fixup14captureGeneric1c1dyx_q_tKAA4DoItRzAaER_r0_lF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup10useClosureyyyyXEF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup18useClosureThrowingyyyyKXEKF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytytIegnr_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup17useGenericClosureyyq_xXEr0_lF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytyts5Error_pIegnrzo_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup25useGenericClosureThrowingyyq_xKXEKr0_lF public func captureGeneric(c: C, d: D) throws { useClosure { c.doIt() d.doIt() } try useClosureThrowing { c.doIt() d.doIt() } useGenericClosure { c.doIt() d.doIt() } try useGenericClosureThrowing { c.doIt() d.doIt() } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup14captureClosure1c1d1tyq_xXE_q_xXExtKr0_lF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup10useClosureyyyyXEF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup18useClosureThrowingyyyyKXEKF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytytIegnr_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup17useGenericClosureyyq_xXEr0_lF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$sIg_ytyts5Error_pIegnrzo_TR // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: function_ref @$s22closure_lifetime_fixup25useGenericClosureThrowingyyq_xKXEKr0_lF public func captureClosure(c : (T) ->V, d: (T) -> V, t: T) throws { useClosure { c(t) d(t) } try useClosureThrowing { c(t) d(t) } useGenericClosure { c(t) d(t) } try useGenericClosureThrowing { c(t) d(t) } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup16captureResilient // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func captureResilient(c: Size) throws { useClosure { c.method() } try useClosureThrowing { c.method() } useGenericClosure { c.method() } try useGenericClosureThrowing { c.method() } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup10capturePOD1cy16resilient_struct5PointV_tKF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func capturePOD(c: Point) throws { useClosure { c.method() } try useClosureThrowing { c.method() } useGenericClosure { c.method() } try useGenericClosureThrowing { c.method() } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup11captureEnum // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func captureEnum(c: FullyFixedLayout, d: CustomColor) throws { useClosure { _ = c _ = d } try useClosureThrowing { _ = c _ = d } useGenericClosure { _ = c _ = d } try useGenericClosureThrowing { _ = c _ = d } } public protocol EmptyP {} public struct AddressOnlyStruct : EmptyP {} public enum AddressOnlyEnum { case nought case mere(EmptyP) case phantom(AddressOnlyStruct) } // CHECK-LABEL: sil @$s22closure_lifetime_fixup22captureAddressOnlyEnum // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func captureAddressOnlyEnum(c: AddressOnlyEnum, d: AddressOnlyEnum) throws { useClosure { _ = c _ = d } try useClosureThrowing { _ = c _ = d } useGenericClosure { _ = c _ = d } try useGenericClosureThrowing { _ = c _ = d } } // CHECK-LABEL: sil @$s22closure_lifetime_fixup15captureProtocol // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func captureProtocol(c: EmptyP, d: EmptyP) throws { useClosure { _ = c _ = d } try useClosureThrowing { _ = c _ = d } useGenericClosure { () -> Int in _ = c _ = d return 0 } try useGenericClosureThrowing { () -> Int in _ = c _ = d return 0 } } public protocol Q { associatedtype Element func test(_ c: (Element) -> U) throws } // CHECK-LABEL: sil @$s22closure_lifetime_fixup0A18WithAssociatedType1c1eyx_7ElementQztKAA1QRzlF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: try_apply public func closureWithAssociatedType (c: C, e: C.Element) throws { try c.test( { _ in _ = e }) } public class F { func test(_ c: (V) throws -> T) {} let t : T? = nil } // CHECK-LABEL: s22closure_lifetime_fixup22testClosureMethodParam1fyAA1FCyxG_tKlF // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: partial_apply [callee_guaranteed] [on_stack] // CHECK: apply public func testClosureMethodParam(f: F) throws { try f.test { return f.t! } } struct AddressOnlyNoncopyableStruct: ~Copyable { let x: Any = 123 borrowing func hello() {} } func simpleNonescapingClosure(with body: () -> ()) { body() } // CHECK-LABEL: s22closure_lifetime_fixup27trySimpleNonescapingClosure // CHECK: [[FIRST:%.*]] = alloc_stack [var_decl] $AddressOnlyNoncopyableStruct, let, name "foo" // CHECK: [[SECOND:%.*]] = alloc_stack [var_decl] $AddressOnlyNoncopyableStruct, let, name "bar" // CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [on_stack] %{{.*}}([[FIRST]], [[SECOND]]) // CHECK: [[MD_ONE:%.*]] = mark_dependence [nonescaping] [[PA]] : $@noescape @callee_guaranteed () -> () on [[FIRST]] : $*AddressOnlyNoncopyableStruct // CHECK: [[MD_TWO:%.*]] = mark_dependence [nonescaping] [[MD_ONE]] : $@noescape @callee_guaranteed () -> () on [[SECOND]] : $*AddressOnlyNoncopyableStruct func trySimpleNonescapingClosure() { let foo = AddressOnlyNoncopyableStruct() let bar = AddressOnlyNoncopyableStruct() simpleNonescapingClosure { foo.hello() // OK bar.hello() // OK } }