Skip to content

Commit 085553a

Browse files
committed
[Swiftify] Add tests that verify __counted_by with constant count (NFC)
We used to not emit bounds checks for things like `__counted_by(4)`, but we do now - likely fixed by #81585 These regression tests verify that behaviour. rdar://151038254
1 parent 9e943fd commit 085553a

File tree

3 files changed

+250
-0
lines changed

3 files changed

+250
-0
lines changed

test/Interop/C/swiftify-import/Inputs/counted-by-lifetimebound.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,5 @@ typedef struct foo opaque_t;
1919
opaque_t * __counted_by(len) opaque(int len, int len2, opaque_t * __counted_by(len2) __lifetimebound p);
2020

2121
int * __counted_by(len) noncountedLifetime(int len, int * __lifetimebound p);
22+
23+
int * __counted_by(13) _Nullable constant(int * __counted_by(13) __lifetimebound _Nullable p);

test/Interop/C/swiftify-import/counted-by-lifetimebound.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ import CountedByLifetimeboundClang
1717
// CHECK-NEXT: @lifetime(p: copy p)
1818
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func complexExpr(_ len: Int32, _ offset: Int32, _ p: inout MutableSpan<Int32>) -> MutableSpan<Int32>
1919

20+
// CHECK: /// This is an auto-generated wrapper for safer interop
21+
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
22+
// CHECK-NEXT: @lifetime(copy p)
23+
// CHECK-NEXT: @lifetime(p: copy p)
24+
// CHECK-NEXT: @_alwaysEmitIntoClient @_disfavoredOverload public func constant(_ p: inout MutableSpan<Int32>?) -> MutableSpan<Int32>?
25+
2026
// CHECK-NEXT: /// This is an auto-generated wrapper for safer interop
2127
// CHECK-NEXT: @available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
2228
// CHECK-NEXT: @lifetime(borrow p)
@@ -94,3 +100,9 @@ public func callSimple(_ p: inout MutableSpan<CInt>) {
94100
public func callNoncountedLifetime(_ p: UnsafeMutablePointer<CInt>) {
95101
let _: MutableSpan<CInt> = noncountedLifetime(73, p)
96102
}
103+
104+
@available(visionOS 1.1, tvOS 12.2, watchOS 5.2, iOS 12.2, macOS 10.14.4, *)
105+
@inlinable
106+
public func callConstant(_ p: inout MutableSpan<CInt>?) {
107+
let _: MutableSpan<CInt>? = constant(&p)
108+
}
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
// REQUIRES: swift_swift_parser
2+
3+
// RUN: %target-swift-frontend %s -swift-version 5 -module-name main -disable-availability-checking -typecheck -plugin-path %swift-plugin-dir -strict-memory-safety -warnings-as-errors -dump-macro-expansions 2>&1 | %FileCheck --match-full-lines %s
4+
5+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"))
6+
func plain(_ ptr: UnsafePointer<CInt>) {}
7+
8+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"))
9+
func opt(_ ptr: UnsafePointer<CInt>?) {}
10+
11+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"))
12+
func mut(_ ptr: UnsafeMutablePointer<CInt>) {}
13+
14+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"))
15+
func mutOpt(_ ptr: UnsafeMutablePointer<CInt>?) {}
16+
17+
18+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .nonescaping(pointer: .param(1)))
19+
func noescape(_ ptr: UnsafePointer<CInt>) {}
20+
21+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .nonescaping(pointer: .param(1)))
22+
func noescapeOpt(_ ptr: UnsafePointer<CInt>?) {}
23+
24+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .nonescaping(pointer: .param(1)))
25+
func noescapeMut(_ ptr: UnsafeMutablePointer<CInt>) {}
26+
27+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .nonescaping(pointer: .param(1)))
28+
func noescapeMutOpt(_ ptr: UnsafeMutablePointer<CInt>?) {}
29+
30+
31+
@_SwiftifyImport(.countedBy(pointer: .return, count: "37"))
32+
func plainReturn() -> UnsafePointer<CInt> {}
33+
34+
@_SwiftifyImport(.countedBy(pointer: .return, count: "37"))
35+
func optReturn() -> UnsafePointer<CInt>? {}
36+
37+
@_SwiftifyImport(.countedBy(pointer: .return, count: "37"))
38+
func mutReturn() -> UnsafeMutablePointer<CInt> {}
39+
40+
@_SwiftifyImport(.countedBy(pointer: .return, count: "37"))
41+
func mutOptReturn() -> UnsafeMutablePointer<CInt>? {}
42+
43+
44+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
45+
func noescape(_ ptr: UnsafePointer<CInt>) -> UnsafePointer<CInt> {}
46+
47+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
48+
func noescapeOpt(_ ptr: UnsafePointer<CInt>?) -> UnsafePointer<CInt>? {}
49+
50+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
51+
func noescapeMut(_ ptr: UnsafeMutablePointer<CInt>) -> UnsafeMutablePointer<CInt> {}
52+
53+
@_SwiftifyImport(.countedBy(pointer: .param(1), count: "37"), .lifetimeDependence(dependsOn: .param(1), pointer: .return, type: .copy))
54+
func noescapeMutOpt(_ ptr: UnsafeMutablePointer<CInt>?) -> UnsafeMutablePointer<CInt>? {}
55+
56+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
57+
// CHECK-NEXT: func plain(_ ptr: UnsafeBufferPointer<CInt>) {
58+
// CHECK-NEXT: let _ptrCount = unsafe ptr.count
59+
// CHECK-NEXT: if _ptrCount != 37 {
60+
// CHECK-NEXT: fatalError("bounds check failure in plain: expected \(37) but got \(_ptrCount)")
61+
// CHECK-NEXT: }
62+
// CHECK-NEXT: return unsafe plain(ptr.baseAddress!)
63+
// CHECK-NEXT: }
64+
65+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
66+
// CHECK-NEXT: func opt(_ ptr: UnsafeBufferPointer<CInt>?) {
67+
// CHECK-NEXT: let _ptrCount = unsafe ptr?.count ?? 0
68+
// CHECK-NEXT: if _ptrCount != 37 {
69+
// CHECK-NEXT: fatalError("bounds check failure in opt: expected \(37) but got \(_ptrCount)")
70+
// CHECK-NEXT: }
71+
// CHECK-NEXT: return unsafe opt(ptr?.baseAddress)
72+
// CHECK-NEXT: }
73+
74+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
75+
// CHECK-NEXT: func mut(_ ptr: UnsafeMutableBufferPointer<CInt>) {
76+
// CHECK-NEXT: let _ptrCount = unsafe ptr.count
77+
// CHECK-NEXT: if _ptrCount != 37 {
78+
// CHECK-NEXT: fatalError("bounds check failure in mut: expected \(37) but got \(_ptrCount)")
79+
// CHECK-NEXT: }
80+
// CHECK-NEXT: return unsafe mut(ptr.baseAddress!)
81+
// CHECK-NEXT: }
82+
83+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
84+
// CHECK-NEXT: func mutOpt(_ ptr: UnsafeMutableBufferPointer<CInt>?) {
85+
// CHECK-NEXT: let _ptrCount = unsafe ptr?.count ?? 0
86+
// CHECK-NEXT: if _ptrCount != 37 {
87+
// CHECK-NEXT: fatalError("bounds check failure in mutOpt: expected \(37) but got \(_ptrCount)")
88+
// CHECK-NEXT: }
89+
// CHECK-NEXT: return unsafe mutOpt(ptr?.baseAddress)
90+
// CHECK-NEXT: }
91+
92+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
93+
// CHECK-NEXT: func noescape(_ ptr: Span<CInt>) {
94+
// CHECK-NEXT: let _ptrCount = ptr.count
95+
// CHECK-NEXT: if _ptrCount != 37 {
96+
// CHECK-NEXT: fatalError("bounds check failure in noescape: expected \(37) but got \(_ptrCount)")
97+
// CHECK-NEXT: }
98+
// CHECK-NEXT: return unsafe ptr.withUnsafeBufferPointer { _ptrPtr in
99+
// CHECK-NEXT: return unsafe noescape(_ptrPtr.baseAddress!)
100+
// CHECK-NEXT: }
101+
// CHECK-NEXT: }
102+
103+
// CHECK: @_alwaysEmitIntoClient @lifetime(copy ptr) @_disfavoredOverload
104+
// CHECK-NEXT: func noescape(_ ptr: Span<CInt>) -> UnsafePointer<CInt> {
105+
// CHECK-NEXT: let _ptrCount = ptr.count
106+
// CHECK-NEXT: if _ptrCount != 37 {
107+
// CHECK-NEXT: fatalError("bounds check failure in noescape: expected \(37) but got \(_ptrCount)")
108+
// CHECK-NEXT: }
109+
// CHECK-NEXT: return unsafe ptr.withUnsafeBufferPointer { _ptrPtr in
110+
// CHECK-NEXT: return unsafe noescape(_ptrPtr.baseAddress!)
111+
// CHECK-NEXT: }
112+
// CHECK-NEXT: }
113+
114+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
115+
// CHECK-NEXT: func noescapeOpt(_ ptr: Span<CInt>?) {
116+
// CHECK-NEXT: let _ptrCount = ptr?.count ?? 0
117+
// CHECK-NEXT: if _ptrCount != 37 {
118+
// CHECK-NEXT: fatalError("bounds check failure in noescapeOpt: expected \(37) but got \(_ptrCount)")
119+
// CHECK-NEXT: }
120+
// CHECK-NEXT: return { () in
121+
// CHECK-NEXT: return if ptr == nil {
122+
// CHECK-NEXT: unsafe noescapeOpt(nil)
123+
// CHECK-NEXT: } else {
124+
// CHECK-NEXT: unsafe ptr!.withUnsafeBufferPointer { _ptrPtr in
125+
// CHECK-NEXT: return unsafe noescapeOpt(_ptrPtr.baseAddress)
126+
// CHECK-NEXT: }
127+
// CHECK-NEXT: }
128+
// CHECK-NEXT: }()
129+
// CHECK-NEXT: }
130+
131+
// CHECK: @_alwaysEmitIntoClient @lifetime(copy ptr) @_disfavoredOverload
132+
// CHECK-NEXT: func noescapeOpt(_ ptr: Span<CInt>?) -> UnsafePointer<CInt>? {
133+
// CHECK-NEXT: let _ptrCount = ptr?.count ?? 0
134+
// CHECK-NEXT: if _ptrCount != 37 {
135+
// CHECK-NEXT: fatalError("bounds check failure in noescapeOpt: expected \(37) but got \(_ptrCount)")
136+
// CHECK-NEXT: }
137+
// CHECK-NEXT: return { () in
138+
// CHECK-NEXT: return if ptr == nil {
139+
// CHECK-NEXT: unsafe noescapeOpt(nil)
140+
// CHECK-NEXT: } else {
141+
// CHECK-NEXT: unsafe ptr!.withUnsafeBufferPointer { _ptrPtr in
142+
// CHECK-NEXT: return unsafe noescapeOpt(_ptrPtr.baseAddress)
143+
// CHECK-NEXT: }
144+
// CHECK-NEXT: }
145+
// CHECK-NEXT: }()
146+
// CHECK-NEXT: }
147+
148+
// CHECK: @_alwaysEmitIntoClient @lifetime(ptr: copy ptr) @_disfavoredOverload
149+
// CHECK-NEXT: func noescapeMut(_ ptr: inout MutableSpan<CInt>) {
150+
// CHECK-NEXT: let _ptrCount = ptr.count
151+
// CHECK-NEXT: if _ptrCount != 37 {
152+
// CHECK-NEXT: fatalError("bounds check failure in noescapeMut: expected \(37) but got \(_ptrCount)")
153+
// CHECK-NEXT: }
154+
// CHECK-NEXT: return unsafe ptr.withUnsafeMutableBufferPointer { _ptrPtr in
155+
// CHECK-NEXT: return unsafe noescapeMut(_ptrPtr.baseAddress!)
156+
// CHECK-NEXT: }
157+
// CHECK-NEXT: }
158+
159+
// CHECK: @_alwaysEmitIntoClient @lifetime(copy ptr) @lifetime(ptr: copy ptr) @_disfavoredOverload
160+
// CHECK-NEXT: func noescapeMut(_ ptr: inout MutableSpan<CInt>) -> UnsafeMutablePointer<CInt> {
161+
// CHECK-NEXT: let _ptrCount = ptr.count
162+
// CHECK-NEXT: if _ptrCount != 37 {
163+
// CHECK-NEXT: fatalError("bounds check failure in noescapeMut: expected \(37) but got \(_ptrCount)")
164+
// CHECK-NEXT: }
165+
// CHECK-NEXT: return unsafe ptr.withUnsafeMutableBufferPointer { _ptrPtr in
166+
// CHECK-NEXT: return unsafe noescapeMut(_ptrPtr.baseAddress!)
167+
// CHECK-NEXT: }
168+
// CHECK-NEXT: }
169+
170+
// CHECK: @_alwaysEmitIntoClient @lifetime(ptr: copy ptr) @_disfavoredOverload
171+
// CHECK-NEXT: func noescapeMutOpt(_ ptr: inout MutableSpan<CInt>?) {
172+
// CHECK-NEXT: let _ptrCount = ptr?.count ?? 0
173+
// CHECK-NEXT: if _ptrCount != 37 {
174+
// CHECK-NEXT: fatalError("bounds check failure in noescapeMutOpt: expected \(37) but got \(_ptrCount)")
175+
// CHECK-NEXT: }
176+
// CHECK-NEXT: return { () in
177+
// CHECK-NEXT: return if ptr == nil {
178+
// CHECK-NEXT: unsafe noescapeMutOpt(nil)
179+
// CHECK-NEXT: } else {
180+
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBufferPointer { _ptrPtr in
181+
// CHECK-NEXT: return unsafe noescapeMutOpt(_ptrPtr.baseAddress)
182+
// CHECK-NEXT: }
183+
// CHECK-NEXT: }
184+
// CHECK-NEXT: }()
185+
// CHECK-NEXT: }
186+
187+
// CHECK: @_alwaysEmitIntoClient @lifetime(copy ptr) @lifetime(ptr: copy ptr) @_disfavoredOverload
188+
// CHECK-NEXT: func noescapeMutOpt(_ ptr: inout MutableSpan<CInt>?) -> UnsafeMutablePointer<CInt>? {
189+
// CHECK-NEXT: let _ptrCount = ptr?.count ?? 0
190+
// CHECK-NEXT: if _ptrCount != 37 {
191+
// CHECK-NEXT: fatalError("bounds check failure in noescapeMutOpt: expected \(37) but got \(_ptrCount)")
192+
// CHECK-NEXT: }
193+
// CHECK-NEXT: return { () in
194+
// CHECK-NEXT: return if ptr == nil {
195+
// CHECK-NEXT: unsafe noescapeMutOpt(nil)
196+
// CHECK-NEXT: } else {
197+
// CHECK-NEXT: unsafe ptr!.withUnsafeMutableBufferPointer { _ptrPtr in
198+
// CHECK-NEXT: return unsafe noescapeMutOpt(_ptrPtr.baseAddress)
199+
// CHECK-NEXT: }
200+
// CHECK-NEXT: }
201+
// CHECK-NEXT: }()
202+
// CHECK-NEXT: }
203+
204+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
205+
// CHECK-NEXT: func plainReturn() -> UnsafeBufferPointer<CInt> {
206+
// CHECK-NEXT: return unsafe UnsafeBufferPointer<CInt> (start: unsafe plainReturn(), count: Int(37))
207+
// CHECK-NEXT: }
208+
209+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
210+
// CHECK-NEXT: func optReturn() -> UnsafeBufferPointer<CInt>? {
211+
// CHECK-NEXT: return unsafe { () in
212+
// CHECK-NEXT: let _resultValue = unsafe optReturn()
213+
// CHECK-NEXT: if unsafe _resultValue == nil {
214+
// CHECK-NEXT: return nil
215+
// CHECK-NEXT: } else {
216+
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(UnsafeBufferPointer<CInt>(start: _resultValue!, count: Int(37)), copying: ())
217+
// CHECK-NEXT: }
218+
// CHECK-NEXT: }()
219+
// CHECK-NEXT: }
220+
221+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
222+
// CHECK-NEXT: func mutReturn() -> UnsafeMutableBufferPointer<CInt> {
223+
// CHECK-NEXT: return unsafe UnsafeMutableBufferPointer<CInt> (start: unsafe mutReturn(), count: Int(37))
224+
// CHECK-NEXT: }
225+
226+
// CHECK: @_alwaysEmitIntoClient @_disfavoredOverload
227+
// CHECK-NEXT: func mutOptReturn() -> UnsafeMutableBufferPointer<CInt>? {
228+
// CHECK-NEXT: return unsafe { () in
229+
// CHECK-NEXT: let _resultValue = unsafe mutOptReturn()
230+
// CHECK-NEXT: if unsafe _resultValue == nil {
231+
// CHECK-NEXT: return nil
232+
// CHECK-NEXT: } else {
233+
// CHECK-NEXT: return unsafe _swiftifyOverrideLifetime(UnsafeMutableBufferPointer<CInt>(start: _resultValue!, count: Int(37)), copying: ())
234+
// CHECK-NEXT: }
235+
// CHECK-NEXT: }()
236+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)