-
Notifications
You must be signed in to change notification settings - Fork 577
add c-variadic function definitions #2177
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
|
||
| ```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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. copied from 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
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
let mut ap: VaList<'_> = /* ... */; // Initializes the VaList.the |
||
| ``` | ||
|
|
||
| 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 | ||
|
|
||
|
|
@@ -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 | ||
There was a problem hiding this comment.
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, thevarargs_without_patternlint 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....