Skip to content
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
78 changes: 78 additions & 0 deletions src/items/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,83 @@ Note that this behavior is a consequence of the desugaring to a function that re

Unsafe is used on an async function in precisely the same way that it is used on other functions: it indicates that the function imposes some additional obligations on its caller to ensure soundness. As in any other unsafe function, these conditions may extend beyond the initial call itself -- in the snippet above, for example, the `unsafe_example` function took a pointer `x` as argument, and then (when awaited) dereferenced that pointer. This implies that `x` would have to be valid until the future is finished executing, and it is the caller's responsibility to ensure that.

r[items.fn.c-variadic]
## C-variadic functions

r[items.fn.c-variadic.intro]
A *c-variadic* function accepts a variable argument list `pat: ...` as its final parameter.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

for c-variadic definitions only pat: ... is accepted semantically.

plain ... is currently parsed, the varargs_without_pattern lint is meant to eventually disallow it. This syntax can only be used as an input to macros, when a bare ... makes it past macro expansion, that will emit an error.

I didn't mention this here, but maybe we should: we follow C23 in that pat: ... may be the only argument. Earlier versions of C required at least one standard argument before the ....


```rust
unsafe extern "C" fn example(arg0: i32, ap: ...) { }
```

This parameter stands in for an arbitrary number of arguments that may be passed by the caller.

> [!WARNING]
> Passing an unexpected number of arguments or arguments of unexpected type to a variadic function may lead to [undefined behavior][undefined].
Comment on lines +347 to +348
Copy link
Contributor Author

Choose a reason for hiding this comment

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

copied from

https://doc.rust-lang.org/reference/items/external-blocks.html?highlight=variadic#r-items.extern.variadic

basically, the responsibility for passing valid arguments is on the caller.


r[items.fn.async.desugar-brief]
A c-variadic function definition is roughly equivalent to a function operating on a [`VaList`].



```rust
// Source
unsafe extern "C" fn example(mut ap: ...) -> i32 {
unsafe { ap.arg::<i32>() }
}
```

is roughly equivalent to:

```rust
# use std::ffi::VaList;
# use std::mem::MaybeUninit;
# fn va_start() {}
// Desugared
unsafe extern "C" fn example() -> i32 {
let mut storage = MaybeUninit::<VaList<'_>>::uninit();
va_start(storage.as_mut_ptr()); // Initializes the VaList.
let mut ap: &mut VaList<'_> = ap.assume_init_mut();

unsafe { ap.arg::<i32>() }

va_end(ap)
}
Comment on lines +369 to +377
Copy link
Contributor Author

Choose a reason for hiding this comment

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

va_start and va_end are C functions/concepts. We could instead handwave and say

let mut ap: VaList<'_> = /* ... */; // Initializes the VaList.

the va_end is called by the VaList Drop implementation.

```

r[items.fn.c-variadic.lifetime]
The lifetime of a `VaList` is that of the function that created it. Hence, the `VaList` value can never outlive the function that created it.

r[items.fn.c-variadic.ffi-compatibility]
The rust [`VaList`] is ABI-compatible with the C `va_list` type.

r[items.fn.c-variadic.abi]
Only `extern "C"` and `extern "C-unwind"` functions can accept a variable argument list.

r[items.fn.c-variadic.safety]
Only `unsafe` functions can accept a variable argument list.

r[items.fn.c-variadic.async]
A c-variadic functions cannot be `async`

r[items.fn.c-variadic.const]
A c-variadic functions cannot be `const`

r[items.fn.c-variadic.platform-support]
Some ABIs do not support c-variadic function definitions. The compiler errors in this case.

```
error: the `bpfel` target does not support c-variadic functions
--> $DIR/not-supported.rs:23:31
|
LL | unsafe extern "C" fn variadic(_: ...) {}
| ^^^^^^
```

r[items.fn.c-variadic.dyn-compat]
When a trait method is c-variadic, the trait is no longer dyn-compatible.

r[items.fn.attributes]
## Attributes on functions

Expand Down Expand Up @@ -426,3 +503,4 @@ fn foo_oof(#[some_inert_attribute] arg: u8) {
[value namespace]: ../names/namespaces.md
[variadic function]: external-blocks.md#variadic-functions
[`extern` block]: external-blocks.md
[`VaList`]: std::ffi::VaList
Loading