@@ -150,9 +150,7 @@ the `SWIFT_NONESCAPABLE` annotation:
150
150
151
151
``` c++
152
152
struct SWIFT_NONESCAPABLE View {
153
- View() : member(nullptr) {}
154
153
View(const int * p) : member(p) {}
155
- View(const View&) = default;
156
154
private:
157
155
const int * member;
158
156
};
@@ -162,9 +160,7 @@ Moreover, we can explicitly mark types as `Escapable` using the `SWIFT_ESCAPABLE
162
160
annotation:
163
161
164
162
```c++
165
- struct SWIFT_ESCAPABLE Owner {
166
- ...
167
- };
163
+ struct SWIFT_ESCAPABLE Owner { ... };
168
164
```
169
165
170
166
The main reason for explicitly annotating a type as ` SWIFT_ESCAPABLE ` is to make sure
@@ -193,28 +189,63 @@ In this example, `MyList<View>` should be imported as `~Escapable` while `MyList
193
189
should be imported as ` Escapable ` . This can be achieved via conditional escapability
194
190
annotations:
195
191
196
- ```
192
+ ``` c++
197
193
template <typename T>
198
194
struct SWIFT_ESCAPABLE_IF (T) MyList {
199
195
...
200
196
};
201
197
```
202
198
199
+ Here, instantiations of ` MyList ` are imported as ` Escapable ` when ` T ` is substituted
200
+ with an ` Escapable ` type.
201
+
202
+ The ` SWIFT_ESCAPABLE_IF ` macro can take multiple template parameters:
203
+
204
+ ``` c++
205
+ template <typename F, typename S>
206
+ struct SWIFT_ESCAPABLE_IF (F, S) MyPair {
207
+ F first;
208
+ S second;
209
+ };
210
+ ```
211
+
212
+ ` MyPair ` instantiations are only imported as ` Escapable ` if both template arguments
213
+ are ` Escapable ` .
214
+
215
+ ` Escapable ` types cannot have ` ~Escapable ` fields. The following code snippet will
216
+ trigger a compiler error:
217
+
218
+ ``` c++
219
+ struct SWIFT_NONESCAPABLE View { ... };
220
+ struct SWIFT_ESCAPABLE Owner {
221
+ View v;
222
+ };
223
+ ```
224
+
225
+ Escapability annotations will not only help the Swift compiler to import C++ types
226
+ safely, it will also help discover missing lifetime annotations as all `~Escapable`
227
+ parameters and return values need to be annotated in an API to make its use safe in
228
+ Swift.
229
+
203
230
## Lifetime annotations in detail
204
231
205
- The ` lifetimebound ` attribute can be used to annotate code in various scenarios.
206
- On a constructor, it describes the lifetime of the created object:
232
+ The `lifetimebound` attribute on a function parameter or implicit object parameter
233
+ indicates that the returned object's lifetime could end when any of the `lifetimebound`
234
+ annotated parameters' lifetime ended.
235
+ This annotation a constructor describes the lifetime of the created object:
207
236
208
237
```c++
209
238
struct SWIFT_NONESCAPABLE View {
210
239
View(const int *p [[clang::lifetimebound]]) : member(p) {}
211
- private:
212
- const int * member;
240
+ ...
213
241
};
214
242
```
215
243
244
+ In this example, the object initialized by the ` View ` constructor has the same
245
+ lifetime as the input argument of the constructor.
246
+
216
247
In case the attribute is after the method signature, the returned object has
217
- the same lifetime as the `this` object .
248
+ the same lifetime as the implicit ` this ` parameter .
218
249
219
250
``` c++
220
251
struct Owner {
@@ -226,27 +257,28 @@ struct Owner {
226
257
};
227
258
```
228
259
229
- In case the attribute is applied to a subset of the formal parameters, the return
260
+ Consider a call site like ` View v = o.handOutView() ` . The ` v ` object has the same lifetime
261
+ as ` o ` .
262
+
263
+ In case the attribute is applied to a subset of the parameters, the return
230
264
value might depend on the corresponding arguments:
231
265
232
266
``` c++
233
- View getView (const Owner& owner [[ clang::lifetimebound]] ) {
234
- return View(&owner.data);
235
- }
236
-
237
- View getViewFromFirst(const Owner& owner [[ clang::lifetimebound]] , const Owner& owner2) {
238
- return View(&owner.data);
239
- }
240
-
241
- View getViewFromEither(View view1 [[ clang::lifetimebound]] , View view2 [[ clang::lifetimebound]] ) {
267
+ View getOneOfTheViews (const Owner& owner1 [[ clang::lifetimebound]] , const Owner& owner2
268
+ View view1 [[ clang::lifetimebound]] , View view2 [[ clang::lifetimebound]] ) {
269
+ if (coinFlip)
270
+ return View(&owner1.data);
242
271
if (coinFlip)
243
272
return view1;
244
273
else
245
274
return view2;
246
275
}
247
276
```
248
277
249
- Occasionally, a function might return a non-escapable type that in fact has no dependency on any other values.
278
+ Here, the returned `View`'s lifetime depends on `owner`, `view1`, and `view2` but it cannot
279
+ depend on `owner2`.
280
+
281
+ Occasionally, a function might return a non-escapable type that has no dependency on any other values.
250
282
These types might point to static data or might represent an empty sequence or lack of data.
251
283
Such functions need to be annotated with `SWIFT_RETURNS_INDEPENDENT_VALUE`:
252
284
@@ -276,17 +308,25 @@ Tags:
276
308
277
309
Note that APINotes have some limitations around C++, they do not support overloaded functions.
278
310
279
- We can use ` lifetime_capture_by ` annotations for output arguments.
311
+ While ` lifetimebound ` always describes the lifetime dependencies of the return value (or
312
+ the constructed object in case of constructors), we can use can use ` lifetime_capture_by `
313
+ annotation to descibe the lifetime of other output values, like output/inout arguments
314
+ or globals.
280
315
281
316
``` c++
282
317
void copyView (View view1 [[ clang::lifetime_capture_by(view2)]] , View &view2) {
283
318
view2 = view1;
284
319
}
320
+ ```
285
321
286
- struct SWIFT_NONESCAPABLE CaptureView {
287
- CaptureView() : view(nullptr) {}
288
- CaptureView(View p [[ clang::lifetimebound]] ) : view(p) {}
322
+ In this example, `view2` will have get all of the lifetime dependencies of `view1`
323
+ after a call to `copyView`. a
324
+
325
+ We can annotate dependency captured by the implicit `this` object, or
326
+ an inout argument capturing `this`:
289
327
328
+ ```c++
329
+ struct SWIFT_NONESCAPABLE CaptureView {
290
330
void captureView(View v [[clang::lifetime_capture_by(this)]]) {
291
331
view = v;
292
332
}
@@ -301,11 +341,49 @@ struct SWIFT_NONESCAPABLE CaptureView {
301
341
302
342
All of the non-escapable inputs need lifetime annotations for a function to be
303
343
considered safe. If an input never escapes from the called function we can use
304
- the `noescape` annotation.
344
+ the ` noescape ` annotation:
305
345
306
346
``` c++
307
347
void is_palindrome (std::span<int > s [[ clang::noescape]] );
308
348
```
309
349
350
+ While the annotations in this section are powerful, they cannot express all of
351
+ the lifetime contracts. APIs with inexpressible contracts can be used from Swift,
352
+ but they are imported as unsafe APIs and need extra care from the developers
353
+ to manually guarantee safety.
354
+
310
355
## Convenience overloads for annotated spans and pointers
311
356
357
+ C++ APIs often using standard library types or other constructs like a
358
+ pointer and a size to represent buffers that have Swift equivalents like
359
+ Swift's `Span` type. These Swift types have additional requirements and
360
+ guarantees. When these properties are properly annotated on the C++ side,
361
+ the Swift compiler can introduce safe convenience functions to make
362
+ interacting with the C++ APIs as effortless as if they were written in Swift.
363
+
364
+ ### C++ span support
365
+
366
+ APIs taking/returning C++'s `std::span` with sufficient lifetime
367
+ annotations will automatically get overloads taking/returning Swift
368
+ `Span`.
369
+
370
+ The following table summarizes the generated convenience overloads:
371
+
372
+ ```c++
373
+ using IntSpan = std::span<const int>;
374
+ using IntVec = std::vector<int>;
375
+ ```
376
+
377
+ | C++ API | Generated Swift overload |
378
+ | ------------------------------------------------------- | ------------------------------------------------------------------ |
379
+ | void takeSpan(IntSpan x [[ clang::noescape]] ); | func takeSpan(_ x: Span<Int32 >) |
380
+ | IntSpan changeSpan(IntSpan x [[ clang::lifetimebound]] ); | @lifetime (x) func changeSpan(_ x: Span<Int32 >) -> Span<Int32 > |
381
+ | IntSpan changeSpan(IntVec& x [[ clang::lifetimebound]] ); | @lifetime (x) func changeSpan(_ x: borrowing IntVec) -> Span<Int32 > |
382
+ | IntSpan Owner::getSpan() [[ clang::lifetimebound]] ; | @lifetime (self) func getSpan() -> Span<Int32 > |
383
+
384
+ These transformations only support top level ` std::span ` s, we do not
385
+ transform the nested cases. A ` std::span ` of a non-const type ` T ` will
386
+ be transformed to ` MutableSpan<T> ` on the Swift wide.
387
+
388
+ ### Annotated pointers
389
+
0 commit comments