Skip to content

add c-variadic function definitions#2177

Open
folkertdev wants to merge 11 commits into
rust-lang:masterfrom
folkertdev:c-variadic
Open

add c-variadic function definitions#2177
folkertdev wants to merge 11 commits into
rust-lang:masterfrom
folkertdev:c-variadic

Conversation

@folkertdev

@folkertdev folkertdev commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

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
Comment thread src/items/functions.md
Comment thread src/items/functions.md Outdated
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
Copy Markdown
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 thread src/items/functions.md
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
Copy Markdown
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.

@ehuss ehuss left a comment

Copy link
Copy Markdown
Contributor

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

Comment thread src/items/functions.md Outdated
Comment thread src/items/functions.md
> 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
Copy Markdown
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
Copy Markdown
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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking at it again, I'm not sure this desugaring answers more questions than it raises? Because really it is not a desugaring, we're hooking into a bunch of custom compiler magic to make this work. We could provide an equivalent C function perhaps to illustrate what parts the rust compiler handles automatically in comparison.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i.e. it is equivalent to

// Assuming C23, so `...` as the only argument is accepted.
int example(...) {
    va_list ap; 
    va_start(ap);

    int x = va_arg(ap, int);

    va_end(ap);
    return x;
}

Comment thread src/items/functions.md Outdated
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Apr 15, 2026
…-in-deps, r=mati865

report the `varargs_without_pattern` lint in deps

tracking issue: rust-lang#44930

After discussion in rust-lang/reference#2177 (comment).

Based on rust-lang#143619 (comment) there was only one actual impacted crate https://crates.io/crates/binrw. The issue was fixed in jam1garner/binrw#342, and has since been released jam1garner/binrw#342 (comment).

Hence we may as well report this loudly.

r? @ghost
jhpratt added a commit to jhpratt/rust that referenced this pull request Apr 16, 2026
…-in-deps, r=mati865

report the `varargs_without_pattern` lint in deps

tracking issue: rust-lang#44930

After discussion in rust-lang/reference#2177 (comment).

Based on rust-lang#143619 (comment) there was only one actual impacted crate https://crates.io/crates/binrw. The issue was fixed in jam1garner/binrw#342, and has since been released jam1garner/binrw#342 (comment).

Hence we may as well report this loudly.

r? @ghost
jhpratt added a commit to jhpratt/rust that referenced this pull request Apr 16, 2026
…-in-deps, r=mati865

report the `varargs_without_pattern` lint in deps

tracking issue: rust-lang#44930

After discussion in rust-lang/reference#2177 (comment).

Based on rust-lang#143619 (comment) there was only one actual impacted crate https://crates.io/crates/binrw. The issue was fixed in jam1garner/binrw#342, and has since been released jam1garner/binrw#342 (comment).

Hence we may as well report this loudly.

r? @ghost
rust-timer added a commit to rust-lang/rust that referenced this pull request Apr 16, 2026
Rollup merge of #154599 - folkertdev:varargs-without-pattern-in-deps, r=mati865

report the `varargs_without_pattern` lint in deps

tracking issue: #44930

After discussion in rust-lang/reference#2177 (comment).

Based on #143619 (comment) there was only one actual impacted crate https://crates.io/crates/binrw. The issue was fixed in jam1garner/binrw#342, and has since been released jam1garner/binrw#342 (comment).

Hence we may as well report this loudly.

r? @ghost
@folkertdev

Copy link
Copy Markdown
Contributor Author

The varargs_without_pattern is now reported in dependencies (on nightly).

I've pushed some tweaks, I'm now planning to submit a stabilization PR in coming days, so if you could look at this again that would be helpful.

@ehuss

ehuss commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

It looks like from rust-lang/rust#155974 that there is an intent to make this unavailable on certain targets. I don't think we've ever done something like that, and I'm not sure how we're going to document that. I suppose there will be a rule. It will need to be careful to distinguish that it is a compile error during validation. Unfortunately we don't define that as a specific phase in the reference, so I'm not sure how we should approach that.

@folkertdev

folkertdev commented Apr 30, 2026

Copy link
Copy Markdown
Contributor Author

I don't think this is very different from https://doc.rust-lang.org/beta/unstable-book/language-features/asm-experimental-arch.html. Consequently the page on inline assembly specifies https://doc.rust-lang.org/nightly/reference/inline-assembly.html?highlight=assemb#r-asm.stable-targets.

So we could have

Support for c-variadic function definitions is stable on the following architectures:

  • x86 and x86-64
  • arm
  • aarch64 and arm64ec
  • ...

The compiler will emit an error if ... is used in a function definition on an unsupported target.

Also spirv and bpf just fundamentally do not support this feature, so there you'd always get an error.

Comment thread src/items/functions.md Outdated
@rustbot

This comment has been minimized.

@rustbot

rustbot commented May 13, 2026

Copy link
Copy Markdown
Collaborator

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

Comment thread src/items/functions.md Outdated
Comment thread src/items/functions.md
Comment thread src/items/functions.md Outdated
Comment thread src/items/functions.md Outdated
Comment on lines +352 to +365
- x86 and x86-64
- ARM
- AArch64 and Arm64EC
- RISC-V (except when using the ilp32e ABI)
- LoongArch
- s390x
- PowerPC and PowerPC64
- AmdGpu and Nvptx64
- wasm32 and wasm64
- csky
- xtensa
- hexagon
- sparc64
- mips

@tgross35 tgross35 Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Nit: This mixes lowercase with the arches' name casing (C-SKY, Xtensa, Hexagon, SPARC64, MIPS, Wasm). Also some platforms are explicit about both 32- and 64-bit (x86, ppc) while others aren't (loongarch, mips)

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is based on the list of stable architectures for asm!, I've tried to correct the names.

Comment thread src/items/functions.md

@tgross35 tgross35 Jul 10, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there somewhere it should be mentioned that variadics are allowed in traits?

View changes since the review

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I get the sense that this sort of thing is usually left implicit , but up to our reference maintainers.

Comment thread src/items/functions.md

@folkertdev folkertdev left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The merge of the stabilization PR is now only blocked on the additions to the reference here (I'm not sure that is really needed, previously features have been merged with a reference PR that was "far enough along").

I've tried to address comments here as much possible now.

I'd be happy to look at this together in the reference office hours if they are at a somewhat european-friendly time.

View changes since this review

Comment thread src/items/functions.md
> 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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Looking at it again, I'm not sure this desugaring answers more questions than it raises? Because really it is not a desugaring, we're hooking into a bunch of custom compiler magic to make this work. We could provide an equivalent C function perhaps to illustrate what parts the rust compiler handles automatically in comparison.

Comment thread src/items/functions.md Outdated
Comment on lines +352 to +365
- x86 and x86-64
- ARM
- AArch64 and Arm64EC
- RISC-V (except when using the ilp32e ABI)
- LoongArch
- s390x
- PowerPC and PowerPC64
- AmdGpu and Nvptx64
- wasm32 and wasm64
- csky
- xtensa
- hexagon
- sparc64
- mips

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is based on the list of stable architectures for asm!, I've tried to correct the names.

Comment thread src/items/functions.md
> 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
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i.e. it is equivalent to

// Assuming C23, so `...` as the only argument is accepted.
int example(...) {
    va_list ap; 
    va_start(ap);

    int x = va_arg(ap, int);

    va_end(ap);
    return x;
}

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.

10 participants