Skip to content

Commit 2871aa2

Browse files
committed
Add tests for SILGen support of @_addressable annotations.
Motivates: rdar://152280207 (@_addressable annotations should support address projections into copyable types)
1 parent 49e35aa commit 2871aa2

File tree

1 file changed

+192
-0
lines changed

1 file changed

+192
-0
lines changed
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
// RUN: %target-swift-frontend %s -emit-sil \
2+
// RUN: -o /dev/null \
3+
// RUN: -verify \
4+
// RUN: -sil-verify-all \
5+
// RUN: -enable-builtin-module \
6+
// RUN: -module-name test \
7+
// RUN: -enable-experimental-feature Lifetimes \
8+
// RUN: -enable-experimental-feature AddressableTypes \
9+
// RUN: -enable-experimental-feature AddressableParameters
10+
11+
// RUN: %target-swift-frontend %s -emit-silgen \
12+
// RUN: -sil-verify-all \
13+
// RUN: -enable-builtin-module \
14+
// RUN: -module-name test \
15+
// RUN: -enable-experimental-feature Lifetimes \
16+
// RUN: -enable-experimental-feature AddressableTypes \
17+
// RUN: -enable-experimental-feature AddressableParameters \
18+
// RUN: 2>&1 | %FileCheck %s
19+
20+
// REQUIRES: swift_in_compiler
21+
// REQUIRES: swift_feature_LifetimeDependence
22+
23+
import Builtin
24+
25+
class C {
26+
var p: Builtin.RawPointer
27+
init(p: Builtin.RawPointer) { self.p = p }
28+
29+
// unsupported annotation
30+
@_addressableSelf
31+
func method() {}
32+
}
33+
34+
struct NE: ~Escapable {
35+
var p: Builtin.RawPointer
36+
}
37+
38+
struct PtrHolder {
39+
var field: Builtin.RawPointer
40+
}
41+
42+
struct CHolder {
43+
var field: C
44+
}
45+
46+
struct IHolder {
47+
var field: Int
48+
}
49+
50+
@_lifetime(borrow ptr)
51+
func depends(onPtr ptr: Builtin.RawPointer) -> NE {
52+
NE(p: ptr)
53+
}
54+
55+
// FIXME: Allowed now, but should be prohibited if projection dependence carries exclusivity.
56+
// !!! need radar
57+
@_lifetime(&holder)
58+
func testTrivialField(holder: inout PtrHolder, other: Builtin.RawPointer) -> NE {
59+
// copy holder.field
60+
// end_access holder.field
61+
let ne = depends(onPtr: holder.field)
62+
// mark_dependence ne on holder
63+
holder.field = other
64+
return ne
65+
}
66+
67+
@_lifetime(borrow c)
68+
func depends(onC c: C) -> NE {
69+
let ne = NE(p: c.p)
70+
return _overrideLifetime(ne, borrowing: c)
71+
}
72+
73+
// OK: Correctly diagnoses the exclusivity violation.
74+
@_lifetime(&holder)
75+
func testObjectField(holder: inout CHolder, other: C) -> NE {
76+
// copy holder.field
77+
// end_access holder.field
78+
let ne = depends(onC: holder.field) // expected-note{{conflicting access is here}}
79+
// mark_dependence ne on holder
80+
holder.field = other // expected-error{{overlapping accesses to 'holder.field', but modification requires exclusive access; consider copying to a local variable}}
81+
return ne
82+
}
83+
84+
// OK
85+
@_lifetime(&holder)
86+
func testAddress(holder: inout IHolder) -> NE {
87+
// Requires rdar://137608270 ([borrows] Add Builtin.addressof() support for @addressable arguments)
88+
depends(onPtr: Builtin.addressOfBorrow(holder))
89+
}
90+
91+
@_lifetime(borrow i)
92+
func depends(onInt i: @_addressable Int) -> NE {
93+
NE(p: Builtin.addressOfBorrow(i))
94+
}
95+
96+
// OK: no escape diagnostic because the addressable dependency is on the parameter address.
97+
@_lifetime(&holder)
98+
func testAddressableTrivialField(holder: inout IHolder) -> NE{
99+
// load holder.field
100+
// end_access holder.field
101+
// alloc_stack Int
102+
// store
103+
return depends(onInt: holder.field)
104+
// mark_dependence on alloc_stack
105+
// (the addressable dependence needs to be on the passed-in address)
106+
}
107+
108+
@_lifetime(borrow x)
109+
func depends(onCAddress x: @_addressable C) -> NE {
110+
let ne = NE(p: x.p)
111+
return _overrideLifetime(ne, borrowing: x)
112+
}
113+
114+
// OK: no escape diagnostic because the addressable dependency is on the parameter address.
115+
@_lifetime(&holder)
116+
func testAddressableObjectField(holder: inout CHolder) -> NE {
117+
// tmp = load [copy] holder.field
118+
// end_access holder.field
119+
// alloc_stack
120+
// store tmp
121+
return depends(onCAddress: holder.field)
122+
// mark_dependence ne on alloc_stack
123+
}
124+
125+
// Copyable to test the absence of temporaries.
126+
@_addressableForDependencies
127+
struct Cell<T> {
128+
var t: T
129+
}
130+
131+
struct CellHolder: ~Copyable {
132+
var field: Cell<Int>
133+
}
134+
135+
@_lifetime(borrow x)
136+
func depends(onCell x: borrowing Cell<Int>) -> NE {
137+
NE(p: Builtin.addressOfBorrow(x))
138+
}
139+
140+
// OK: no escape diagnostic because the addressable dependency is on the parameter address.
141+
@_lifetime(&holder)
142+
func testAddressableType(holder: inout CellHolder) -> NE {
143+
// tmp = load [copy] holder.field
144+
// end_access holder.field
145+
// alloc_stack
146+
// store tmp
147+
return depends(onCell: holder.field)
148+
// mark_dependence ne on alloc_stack
149+
}
150+
151+
/* FIXME: Invalid SIL: rdar://152273896 (SILGen: @_addressableSelf support for class methods)
152+
func testAddressableClass(c: C) {
153+
c.method()
154+
}
155+
*/
156+
157+
struct Object {
158+
var c: C
159+
160+
@_addressableSelf
161+
func method() {}
162+
}
163+
164+
struct UniquePointer<T>: ~Copyable {
165+
var _p: UnsafePointer<T>
166+
167+
var value: T { unsafeAddress { _p } }
168+
}
169+
170+
// No copy allowed. A copy would be invalid when class 'C' is imported from C++.
171+
//
172+
// CHECK-LABEL: sil hidden [ossa] @$s4test0A15AddressableSelf2upyAA13UniquePointerVyAA6ObjectVG_tF : $@convention(thin) (@guaranteed UniquePointer<Object>) -> () {
173+
// CHECK: bb0(%0 : @guaranteed $UniquePointer<Object>):
174+
// CHECK: [[CP:%[0-9]+]] = copy_value %0
175+
// CHECK: [[MNC:%[0-9]+]] = mark_unresolved_non_copyable_value [no_consume_or_assign] [[CP]]
176+
// CHECK: [[BB:%[0-9]+]] = begin_borrow [[MNC]]
177+
// CHECK: [[PTR:%[0-9]+]] = struct_extract %{{.*}}, #UnsafePointer._rawValue
178+
// CHECK: [[ADR:%[0-9]+]] = pointer_to_address [[PTR]] to [strict] $*Object
179+
// CHECK: [[MD:%[0-9]+]] = mark_dependence [unresolved] [[ADR]] on [[BB]]
180+
// CHECK-NOT: load
181+
// CHECK-NOT: alloc_stack
182+
// CHECK-NOT: store
183+
// CHECK: apply %{{.*}}([[MD]]) : $@convention(method) (@in_guaranteed Object) -> ()
184+
// CHECK-LABEL: } // end sil function '$s4test0A15AddressableSelf2upyAA13UniquePointerVyAA6ObjectVG_tF'
185+
func testAddressableSelf(up: borrowing UniquePointer<Object>) {
186+
// tmp = load [copy] up.value
187+
// end_access up.value
188+
// alloc_stack
189+
// store tmp
190+
// apply method(tmp)
191+
up.value.method()
192+
}

0 commit comments

Comments
 (0)