@@ -119,7 +119,10 @@ let lifetimeDependenceScopeFixupPass = FunctionPass(
119
119
// Recursively sink enclosing end_access, end_borrow, end_apply, and destroy_value. If the scope can be extended
120
120
// into the caller, return the function arguments that are the dependency sources.
121
121
var scopeExtension = ScopeExtension ( localReachabilityCache, context)
122
- let args = scopeExtension. extendScopes ( dependence: newLifetimeDep)
122
+ guard scopeExtension. extendScopes ( dependence: newLifetimeDep) else {
123
+ continue
124
+ }
125
+ let args = scopeExtension. findArgumentDependencies ( )
123
126
124
127
// Redirect the dependence base to the function arguments. This may create additional mark_dependence instructions.
125
128
markDep. redirectFunctionReturn ( to: args, context)
@@ -246,28 +249,25 @@ private struct ScopeExtension {
246
249
// `mark_dependence` to the outer access `%0`. This ensures that exclusivity diagnostics correctly reports the
247
250
// violation, and that subsequent optimizations do not shrink the inner access `%a1`.
248
251
extension ScopeExtension {
249
- mutating func extendScopes( dependence: LifetimeDependence ) -> SingleInlineArray < FunctionArgument > {
252
+ mutating func extendScopes( dependence: LifetimeDependence ) -> Bool {
250
253
log ( " Scope fixup for lifetime dependent instructions: \( dependence) " )
251
254
252
255
gatherExtensions ( dependence: dependence)
253
256
254
- let noCallerScope = SingleInlineArray < FunctionArgument > ( )
255
-
256
257
// computeDependentUseRange initializes scopeExtension.dependsOnCaller.
257
258
guard var useRange = computeDependentUseRange ( of: dependence) else {
258
- return noCallerScope
259
+ return false
259
260
}
260
261
// tryExtendScopes deinitializes 'useRange'
261
262
var scopesToExtend = SingleInlineArray < ExtendableScope > ( )
262
263
guard canExtendScopes ( over: & useRange, scopesToExtend: & scopesToExtend) else {
263
264
useRange. deinitialize ( )
264
- return noCallerScope
265
+ return false
265
266
}
266
267
// extend(over:) must receive the original unmodified `useRange`, without intermediate scope ending instructions.
267
268
// This deinitializes `useRange` before erasing instructions.
268
269
extend ( scopesToExtend: scopesToExtend, over: & useRange, context)
269
-
270
- return dependsOnArgs
270
+ return true
271
271
}
272
272
}
273
273
@@ -448,10 +448,15 @@ extension ScopeExtension {
448
448
}
449
449
450
450
extension ScopeExtension {
451
- /// Return all scope owners as long as they are all function arguments and all nested accesses are compatible with
452
- /// their argument convention. Then, if all nested accesses were extended to the return statement, it is valid to
453
- /// logically combine them into a single access for the purpose of diagnostic lifetime dependence.
454
- var dependsOnArgs : SingleInlineArray < FunctionArgument > {
451
+ /// Check if the dependent value depends only on function arguments and can therefore be returned to caller. If so,
452
+ /// return the list of arguments that it depends on. If this returns an empty list, then the dependent value cannot be
453
+ /// returned.
454
+ ///
455
+ /// The conditions for returning a dependent value are:
456
+ /// - The dependent value is returned from this function.
457
+ /// - All nested scopes are access scopes that are redundant with the caller's exclusive access scope.
458
+ /// - All scope owners are function arguments.
459
+ func findArgumentDependencies( ) -> SingleInlineArray < FunctionArgument > {
455
460
let noCallerScope = SingleInlineArray < FunctionArgument > ( )
456
461
// Check that the dependent value is returned by this function.
457
462
if !dependsOnCaller! {
0 commit comments