Skip to content

Commit 0ee5b91

Browse files
authored
Merge pull request #81020 from atrick/62-rdar149784450-localvar-assert
[6.2] Fix LifetimeDependenceDiagnostics: handle drop_deinit unsafeAddress
2 parents 95bd860 + bb6b5b3 commit 0ee5b91

File tree

3 files changed

+78
-6
lines changed

3 files changed

+78
-6
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/LocalVariableUtils.swift

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -424,12 +424,17 @@ extension LocalVariableAccessWalker: AddressUseVisitor {
424424
// temporaries do not have access scopes, so we need to walk down any projection that may be used to initialize the
425425
// temporary.
426426
mutating func projectedAddressUse(of operand: Operand, into value: Value) -> WalkResult {
427-
// Intercept mark_dependence destination to record an access point which can be used like a store when finding all
428-
// uses that affect the base after the point that the dependence was marked.
429427
if let md = value as? MarkDependenceInst {
430-
assert(operand == md.valueOperand)
431-
visit(LocalVariableAccess(.dependenceDest, operand))
432-
// walk down the forwarded address as usual...
428+
if operand == md.valueOperand {
429+
// Intercept mark_dependence destination to record an access point which can be used like a store when finding
430+
// all uses that affect the base after the point that the dependence was marked.
431+
visit(LocalVariableAccess(.dependenceDest, operand))
432+
// walk down the forwarded address as usual...
433+
} else {
434+
// A dependence is similar to loading from its source. Downstream uses are not accesses of the original local.
435+
visit(LocalVariableAccess(.dependenceSource, operand))
436+
return .continueWalk
437+
}
433438
}
434439
return walkDownAddressUses(address: value)
435440
}

test/SILOptimizer/lifetime_dependence/verify_diagnostics.sil

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,15 @@ public struct Holder {
3333
var c: C
3434
}
3535

36+
struct A {}
37+
38+
struct NCWrapper : ~Copyable, ~Escapable {
39+
@_hasStorage let a: NE { get }
40+
deinit
41+
}
42+
43+
sil @getNEPointer : $@convention(thin) (@guaranteed NE) -> Builtin.RawPointer
44+
sil @useA : $@convention(thin) (A) -> ()
3645
sil @makeNE : $@convention(thin) () -> @lifetime(immortal) @owned NE
3746
sil @makeNEObject : $@convention(thin) () -> @lifetime(immortal) @owned NEObject
3847
sil @useNE : $@convention(thin) (NE) -> ()
@@ -80,3 +89,29 @@ bb0(%0 : @owned $Holder):
8089
%99 = tuple ()
8190
return %99
8291
}
92+
93+
// Test that local variable analysis can handle an address-type mark_dependence on an address base. The drop_deinit
94+
// also creates an an unknown address scope, preventing diagnostics from promoting the mark_dependence to noescape.
95+
sil [ossa] @testMarkDepAddressProjection : $@convention(thin) (@owned NCWrapper) -> () {
96+
bb0(%0 : @owned $NCWrapper):
97+
%1 = alloc_stack $NCWrapper, let, name "self", argno 1
98+
store %0 to [init] %1
99+
%3 = drop_deinit %1
100+
%4 = struct_element_addr %3, #NCWrapper.a
101+
%5 = load_borrow %4
102+
103+
%6 = function_ref @getNEPointer : $@convention(thin) (@guaranteed NE) -> Builtin.RawPointer
104+
%7 = apply %6(%5) : $@convention(thin) (@guaranteed NE) -> Builtin.RawPointer
105+
%8 = pointer_to_address %7 to [strict] $*A
106+
%9 = mark_dependence [unresolved] %8 on %4
107+
%10 = begin_access [read] [unsafe] %9
108+
%11 = load [trivial] %10
109+
end_access %10
110+
111+
%13 = function_ref @useA : $@convention(thin) (A) -> ()
112+
%14 = apply %13(%11) : $@convention(thin) (A) -> ()
113+
end_borrow %5
114+
dealloc_stack %1
115+
%17 = tuple ()
116+
return %17
117+
}

test/SILOptimizer/lifetime_dependence/verify_diagnostics.swift

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,40 @@
22
// RUN: -o /dev/null \
33
// RUN: -verify \
44
// RUN: -sil-verify-all \
5+
// RUN: -enable-builtin-module \
56
// RUN: -module-name test \
67
// RUN: -define-availability "Span 0.1:macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, visionOS 9999" \
7-
// RUN: -enable-experimental-feature LifetimeDependence
8+
// RUN: -enable-experimental-feature LifetimeDependence \
9+
// RUN: -enable-experimental-feature AddressableParameters
810

911
// REQUIRES: swift_in_compiler
1012
// REQUIRES: swift_feature_LifetimeDependence
13+
// REQUIRES: swift_feature_AddressableParameters
1114

1215
// Test diagnostic output for interesting corner cases. Similar to semantics.swift, but this tests corner cases in the
1316
// implementation as opposed to basic language rules.
1417

18+
import Builtin
19+
20+
struct Borrow<T: ~Copyable>: Copyable, ~Escapable {
21+
let pointer: UnsafePointer<T>
22+
23+
@lifetime(borrow value)
24+
init(_ value: borrowing @_addressable T) {
25+
pointer = UnsafePointer(Builtin.unprotectedAddressOfBorrow(value))
26+
}
27+
28+
subscript() -> T {
29+
unsafeAddress {
30+
pointer
31+
}
32+
}
33+
}
34+
35+
struct A {}
36+
37+
func useA(_:A){}
38+
1539
// Test that conditionally returning an Optional succeeds.
1640
//
1741
// See scope_fixup.sil: testReturnPhi.
@@ -35,3 +59,11 @@ extension Array {
3559
func getImmutableSpan(_ array: inout [Int]) -> Span<Int> {
3660
return array.span
3761
}
62+
63+
struct TestDeinitCallsAddressor: ~Copyable, ~Escapable {
64+
let a: Borrow<A>
65+
66+
deinit {
67+
useA(a[])
68+
}
69+
}

0 commit comments

Comments
 (0)