Skip to content

add c-variadic function definitions#2177

Open
folkertdev wants to merge 2 commits intorust-lang:masterfrom
folkertdev:c-variadic
Open

add c-variadic function definitions#2177
folkertdev wants to merge 2 commits intorust-lang:masterfrom
folkertdev:c-variadic

Conversation

@folkertdev
Copy link
Contributor

@folkertdev folkertdev commented Feb 17, 2026

I think this has all of the raw material, but needs polishing.

Here is a draft of the stabilization report, for additional context: https://hackmd.io/@Q66MPiW4T7yNTKOCaEb-Lw/S1iI3WIwZg

Tracking issue: rust-lang/rust#44930

@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Feb 17, 2026
## 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 ....

Copy link
Contributor

Choose a reason for hiding this comment

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

Is anything holding back changing varargs_without_pattern to report_in_deps: true?

Comment on lines +347 to +348
> [!WARNING]
> Passing an unexpected number of arguments or arguments of unexpected type to a variadic function may lead to [undefined behavior][undefined].
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.

Comment on lines +369 to +377
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)
}
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.

Copy link
Contributor

@ehuss ehuss left a comment

Choose a reason for hiding this comment

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

I think the rule items.fn.params.varargs will need to be updated, since it says it can only be used in an external block.

View changes since this review


> [!WARNING]
> Passing an unexpected number of arguments or arguments of unexpected type to a variadic function may lead to [undefined behavior][undefined].

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it would be good to have a rule near the top here that explains the type of the variadic parameter is a VaList?

> Passing an unexpected number of arguments or arguments of unexpected type to a variadic function may lead to [undefined behavior][undefined].

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

Choose a reason for hiding this comment

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

What is "roughly" about it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In how arguments are actually passed, these signatures are (very) different

fn foo(ap: ...) { /* ... */ }
fn bar(ap: VaList) { /* ... */ }

Those two functions could have exactly the same body though.

A *c-variadic* function accepts a variable argument list `pat: ...` as its final parameter.

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

Choose a reason for hiding this comment

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

It might be helpful for this initial example to show extracting a value from ap.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: The marked PR is awaiting review from a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants