Skip to content

Commit 1d09c06

Browse files
committed
LifetimeDependenceDiagnostics: diagnose indirect closure results.
Add support for diagnosing calls to closures that return a generic non-Escapable result. Closures do not yet model lifetime dependencies. The diagnostics have a special case for handling nonescaple result with no lifetime dependence, but it previously only handled direct results. This fix handles cases like the following: func callIndirectClosure<T>(f: () -> NE<T>) -> NE<T> { f() } Fixes rdar://134318846 ([nonescapable] diagnose function types with nonescapable results)
1 parent dd57d4d commit 1d09c06

File tree

2 files changed

+16
-15
lines changed

2 files changed

+16
-15
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,16 @@ let lifetimeDependenceDiagnosticsPass = FunctionPass(
7272
markDep.settleToEscaping(context)
7373
continue
7474
}
75-
if let apply = instruction as? FullApplySite {
76-
// Handle ~Escapable results that do not have a lifetime dependence. This includes implicit initializers and
77-
// @_unsafeNonescapableResult.
75+
if let apply = instruction as? FullApplySite, !apply.hasResultDependence {
76+
// Handle ~Escapable results that do not have a lifetime dependence. This includes implicit initializers, calls to
77+
// closures, and @_unsafeNonescapableResult.
7878
apply.resultOrYields.forEach {
79-
if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0,
80-
context) {
79+
if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0, apply: apply, context) {
80+
_ = analyze(dependence: lifetimeDep, context)
81+
}
82+
}
83+
apply.indirectResultOperands.forEach {
84+
if let lifetimeDep = LifetimeDependence(unsafeApplyResult: $0.value, apply: apply, context) {
8185
_ = analyze(dependence: lifetimeDep, context)
8286
}
8387
}

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -165,16 +165,12 @@ extension LifetimeDependence {
165165
//
166166
// This is necessary because inserting a mark_dependence placeholder for such an unsafe dependence would illegally
167167
// have the same base and value operand.
168-
//
169-
// TODO: handle indirect results
170-
init?(unsafeApplyResult value: Value, _ context: some Context) {
168+
init?(unsafeApplyResult value: Value, apply: FullApplySite, _ context: some Context) {
171169
if value.isEscapable {
172170
return nil
173171
}
174-
if (value.definingInstructionOrTerminator as! FullApplySite).hasResultDependence {
175-
return nil
176-
}
177-
assert(value.ownership == .owned, "unsafe apply result must be owned")
172+
assert(!apply.hasResultDependence, "mark_dependence should be used instead")
173+
assert(value.ownership == .owned || value.type.isAddress, "unsafe apply result must be owned")
178174
self.scope = Scope(base: value, context)
179175
self.dependentValue = value
180176
self.markDepInst = nil
@@ -578,8 +574,8 @@ extension LifetimeDependenceDefUseWalker {
578574
}
579575
let root = dependence.dependentValue
580576
if root.type.isAddress {
581-
// The root address may be an escapable mark_dependence that guards its address uses (unsafeAddress), or an
582-
// allocation or incoming argument. In all these cases, it is sufficient to walk down the address uses.
577+
// The root address may be an escapable mark_dependence that guards its address uses (unsafeAddress), an
578+
// allocation, an incoming argument, or an outgoing argument. In all these cases, walk down the address uses.
583579
return walkDownAddressUses(of: root)
584580
}
585581
return walkDownUses(of: root, using: nil)
@@ -974,7 +970,8 @@ extension LifetimeDependenceDefUseWalker {
974970

975971
private mutating func visitAppliedUse(of operand: Operand, by apply: FullApplySite) -> WalkResult {
976972
if let conv = apply.convention(of: operand), conv.isIndirectOut {
977-
return leafUse(of: operand)
973+
// This apply initializes an allocation.
974+
return dependentUse(of: operand, dependentAddress: operand.value)
978975
}
979976
if apply.isCallee(operand: operand) {
980977
return leafUse(of: operand)

0 commit comments

Comments
 (0)