@@ -150,9 +150,7 @@ the `SWIFT_NONESCAPABLE` annotation:
150150
151151``` c++
152152struct SWIFT_NONESCAPABLE View {
153- View() : member(nullptr) {}
154153 View(const int * p) : member(p) {}
155- View(const View&) = default;
156154private:
157155 const int * member;
158156};
@@ -162,9 +160,7 @@ Moreover, we can explicitly mark types as `Escapable` using the `SWIFT_ESCAPABLE
162160annotation:
163161
164162```c++
165- struct SWIFT_ESCAPABLE Owner {
166- ...
167- };
163+ struct SWIFT_ESCAPABLE Owner { ... };
168164```
169165
170166The 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
193189should be imported as ` Escapable ` . This can be achieved via conditional escapability
194190annotations:
195191
196- ```
192+ ``` c++
197193template <typename T>
198194struct SWIFT_ESCAPABLE_IF (T) MyList {
199195 ...
200196};
201197```
202198
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+
203230## Lifetime annotations in detail
204231
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:
207236
208237```c++
209238struct SWIFT_NONESCAPABLE View {
210239 View(const int *p [[clang::lifetimebound]]) : member(p) {}
211- private:
212- const int * member;
240+ ...
213241};
214242```
215243
244+ In this example, the object initialized by the ` View ` constructor has the same
245+ lifetime as the input argument of the constructor.
246+
216247In 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 .
218249
219250``` c++
220251struct Owner {
@@ -226,27 +257,28 @@ struct Owner {
226257};
227258```
228259
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
230264value might depend on the corresponding arguments:
231265
232266``` 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);
242271 if (coinFlip)
243272 return view1;
244273 else
245274 return view2;
246275}
247276```
248277
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.
250282These types might point to static data or might represent an empty sequence or lack of data.
251283Such functions need to be annotated with `SWIFT_RETURNS_INDEPENDENT_VALUE`:
252284
@@ -276,17 +308,25 @@ Tags:
276308
277309Note that APINotes have some limitations around C++, they do not support overloaded functions.
278310
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.
280315
281316``` c++
282317void copyView (View view1 [[ clang::lifetime_capture_by(view2)]] , View &view2) {
283318 view2 = view1;
284319}
320+ ```
285321
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`:
289327
328+ ```c++
329+ struct SWIFT_NONESCAPABLE CaptureView {
290330 void captureView(View v [[clang::lifetime_capture_by(this)]]) {
291331 view = v;
292332 }
@@ -301,11 +341,49 @@ struct SWIFT_NONESCAPABLE CaptureView {
301341
302342All of the non-escapable inputs need lifetime annotations for a function to be
303343considered safe. If an input never escapes from the called function we can use
304- the `noescape` annotation.
344+ the ` noescape ` annotation:
305345
306346``` c++
307347void is_palindrome (std::span<int > s [[ clang::noescape]] );
308348```
309349
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+
310355## Convenience overloads for annotated spans and pointers
311356
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