Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cxx-interop] Document guarantees and assumptions for non-const C++ s… #816

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions documentation/cxx-interop/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -1271,6 +1271,20 @@ owned/guaranteed calling conventions. The C++ callers must guarantee that `x` is
Note that functions returning a shared reference type such as `returnSharedObject` transfer the ownership to the caller.
The C++ caller of this function is responsible for releasing the object.

If a C++ Shared Reference Type is passed as an argument to a C++ API from Swift, the Swift compiler *guarantees* that the passed value would be alive. Also Swift *assumes* that the C++ API is not consuming i.e., it returns with a valid object in the passed reference at the end of the C++ API call.
Copy link

@ravikandhadai ravikandhadai Sep 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fahadnayyar I would like to suggest these changes:

f a C++ Shared Reference Type is passed as an argument to a C++ API from Swift, the Swift compiler guarantees that the passed value would be alive.

Can we add the following after this sentence.
... guarantees that the passed value would be alive, and retains ownership of the value. In other words, the argument is passed as +0 and there is no transfer of ownership.

Also Swift assumes that the C++ API is not consuming i.e., it returns with a valid object in the passed reference at the end of the C++ API call.

Can we rephrase this as follows:
The C++ function is responsible for ensuring that the value pointed to by the parameter is alive during and at the end of the call. The C++ function should not assume it has ownership of the value and should do necessary retain operations if it is needs to take ownership.

If the argument is an inout (non-const reference) as shown below:

void takeSharedObjectAsInout(SharedObject *& x) { ... }

which would be imported in Swift as

func takeSharedObjectAsInout(_ x: inout SharedObject) { ... }

If the C++ function overwrites the value of the argument with the new value, it is responsible for releasing the old value, and ensuring that the new value is properly retained so that the Swift caller has ownership of the new value when the function returns. Adhering to these rules is necessary to safely and correctly pass around SWIFT_SHARED_REFERENCE between Swift and C++. These rules are also generally recommended conventions to manage shared objects that use reference counting.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a few comments on the wording and formatting:

  1. The rest of this document doesn't capitalize "C++ reference types", I think it's better to be consistent here.
  2. I think it's better not to use bold highlighting for *guarantees*/*assumes*, the rest of the document doesn't use it, and I feel that it attracts too much attention.
  3. Minor: the comma , usually goes before i.e., could you please swap them?
  4. I don't have a strong opinion, but to me "function call" sounds better than "API call", since to me API means a collection of functions, types, etc.


```swift
var obj = SharedObject.create()
receiveSharedObject(obj) // Swift gaurantees that obj is alive
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: guarantees

```

```c++
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for explicitly specifying the language for code blocks! 👍

void receiveSharedObject(SharedObject *sobj) {
...
// Swift assumes that sobj is valid, non-null object at the end of this function
}
```

### Unsafe Reference Types

The `SWIFT_UNSAFE_REFERENCE` annotation macro has the same effect as `SWIFT_IMMORTAL_REFERENCE`
Expand Down