Skip to content

document naked c-variadic functions - #2321

Merged
traviscross merged 8 commits into
rust-lang:masterfrom
folkertdev:c-variadic-naked-functions
Aug 16, 2026
Merged

document naked c-variadic functions#2321
traviscross merged 8 commits into
rust-lang:masterfrom
folkertdev:c-variadic-naked-functions

Conversation

@folkertdev

@folkertdev folkertdev commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

A first draft. I'm not sure what the right way is to draw a distinction between function definition and naked function definition.

Stabilization:

@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Aug 8, 2026
@traviscross traviscross added S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository and removed S-waiting-on-review Status: The marked PR is awaiting review from a maintainer labels Aug 9, 2026
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 9, 2026
…ked-functions, r=tiif

stabilize `c_variadic_naked_functions`

tracking issue: rust-lang#148767
reference PR: rust-lang/reference#2321

# Stabilization report

## Summary

Stabilize the ability to use `#[unsafe(naked)]` functions to define c-variadic functions. These c-variadic naked functions accept the same set of ABIs as c-variadic foreign functions, this set is larger than what we currently accept for c-variadic definitions.

```rust
#[unsafe(naked)]
unsafe extern "aapcs" fn variadic_aapcs(_: f64, _: ...) -> f64 {
    core::arch::naked_asm!(
        r#"
        sub     sp, sp, rust-lang#12
        stmib   sp, {{r2, r3}}
        vmov    d0, r0, r1
        add     r0, sp, rust-lang#4
        vldr    d1, [sp, rust-lang#4]
        add     r0, r0, rust-lang#15
        bic     r0, r0, rust-lang#7
        vadd.f64        d0, d0, d1
        add     r1, r0, rust-lang#8
        str     r1, [sp]
        vldr    d1, [r0]
        vadd.f64        d0, d0, d1
        vmov    r0, r1, d0
        add     sp, sp, rust-lang#12
        bx      lr
    "#,
    )
}
```

## Accepted ABIs

The set of accepted ABIs is the same as for c-variadic foreign functions, defined as rule [`items.extern.variadic.conventions`](https://doc.rust-lang.org/nightly/reference/items/external-blocks.html?highlight=externblo#r-items.extern.variadic.conventions):

- `"aapcs"`
- `"C"`
- `"cdecl"`
- `"efiapi"`
- `"system"`
- `"sysv64"`
- `"win64"`

And their corresponding `-unwind` variants. Given that naked functions desugar to a block of module assembly and a foreign definition, it makes sense to support the same set as source-level foreign definitions.

For c-variadic definitions we only accept `"C"` and `"C-unwind"`.

## Multiple c-variadic ABIs in the same program

LLVM supports c-variadic calls of different ABIs in the same program. We test both an arm and x86 configuration

- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-arm.rs
- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs

Note that GCC, Clang and LLVM do not support c-variadic definitions of multiple ABIs: the `va_start`, `va_arg` etc. macros are always expanded using the default C calling convention. Clang and GCC reject a variable argument list on definitions that use a non-default calling convention.

## History

- [#t-lang > C-variadic naked functions](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/C-variadic.20naked.20functions/with/554593886)
- rust-lang#148770

The stabilization report of `feature(c_variadic)` mentions this feature:

- rust-lang#155697

## Unresolved questions

None.
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 9, 2026
…ked-functions, r=tiif

stabilize `c_variadic_naked_functions`

tracking issue: rust-lang#148767
reference PR: rust-lang/reference#2321

# Stabilization report

## Summary

Stabilize the ability to use `#[unsafe(naked)]` functions to define c-variadic functions. These c-variadic naked functions accept the same set of ABIs as c-variadic foreign functions, this set is larger than what we currently accept for c-variadic definitions.

```rust
#[unsafe(naked)]
unsafe extern "aapcs" fn variadic_aapcs(_: f64, _: ...) -> f64 {
    core::arch::naked_asm!(
        r#"
        sub     sp, sp, rust-lang#12
        stmib   sp, {{r2, r3}}
        vmov    d0, r0, r1
        add     r0, sp, rust-lang#4
        vldr    d1, [sp, rust-lang#4]
        add     r0, r0, rust-lang#15
        bic     r0, r0, rust-lang#7
        vadd.f64        d0, d0, d1
        add     r1, r0, rust-lang#8
        str     r1, [sp]
        vldr    d1, [r0]
        vadd.f64        d0, d0, d1
        vmov    r0, r1, d0
        add     sp, sp, rust-lang#12
        bx      lr
    "#,
    )
}
```

## Accepted ABIs

The set of accepted ABIs is the same as for c-variadic foreign functions, defined as rule [`items.extern.variadic.conventions`](https://doc.rust-lang.org/nightly/reference/items/external-blocks.html?highlight=externblo#r-items.extern.variadic.conventions):

- `"aapcs"`
- `"C"`
- `"cdecl"`
- `"efiapi"`
- `"system"`
- `"sysv64"`
- `"win64"`

And their corresponding `-unwind` variants. Given that naked functions desugar to a block of module assembly and a foreign definition, it makes sense to support the same set as source-level foreign definitions.

For c-variadic definitions we only accept `"C"` and `"C-unwind"`.

## Multiple c-variadic ABIs in the same program

LLVM supports c-variadic calls of different ABIs in the same program. We test both an arm and x86 configuration

- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-arm.rs
- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs

Note that GCC, Clang and LLVM do not support c-variadic definitions of multiple ABIs: the `va_start`, `va_arg` etc. macros are always expanded using the default C calling convention. Clang and GCC reject a variable argument list on definitions that use a non-default calling convention.

## History

- [#t-lang > C-variadic naked functions](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/C-variadic.20naked.20functions/with/554593886)
- rust-lang#148770

The stabilization report of `feature(c_variadic)` mentions this feature:

- rust-lang#155697

## Unresolved questions

None.
rust-timer added a commit to rust-lang/rust that referenced this pull request Aug 9, 2026
Rollup merge of #159746 - folkertdev:stabilize-c-variadic-naked-functions, r=tiif

stabilize `c_variadic_naked_functions`

tracking issue: #148767
reference PR: rust-lang/reference#2321

# Stabilization report

## Summary

Stabilize the ability to use `#[unsafe(naked)]` functions to define c-variadic functions. These c-variadic naked functions accept the same set of ABIs as c-variadic foreign functions, this set is larger than what we currently accept for c-variadic definitions.

```rust
#[unsafe(naked)]
unsafe extern "aapcs" fn variadic_aapcs(_: f64, _: ...) -> f64 {
    core::arch::naked_asm!(
        r#"
        sub     sp, sp, #12
        stmib   sp, {{r2, r3}}
        vmov    d0, r0, r1
        add     r0, sp, #4
        vldr    d1, [sp, #4]
        add     r0, r0, #15
        bic     r0, r0, #7
        vadd.f64        d0, d0, d1
        add     r1, r0, #8
        str     r1, [sp]
        vldr    d1, [r0]
        vadd.f64        d0, d0, d1
        vmov    r0, r1, d0
        add     sp, sp, #12
        bx      lr
    "#,
    )
}
```

## Accepted ABIs

The set of accepted ABIs is the same as for c-variadic foreign functions, defined as rule [`items.extern.variadic.conventions`](https://doc.rust-lang.org/nightly/reference/items/external-blocks.html?highlight=externblo#r-items.extern.variadic.conventions):

- `"aapcs"`
- `"C"`
- `"cdecl"`
- `"efiapi"`
- `"system"`
- `"sysv64"`
- `"win64"`

And their corresponding `-unwind` variants. Given that naked functions desugar to a block of module assembly and a foreign definition, it makes sense to support the same set as source-level foreign definitions.

For c-variadic definitions we only accept `"C"` and `"C-unwind"`.

## Multiple c-variadic ABIs in the same program

LLVM supports c-variadic calls of different ABIs in the same program. We test both an arm and x86 configuration

- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-arm.rs
- https://github.com/rust-lang/rust/blob/771916f9028e7fe56d2685f2c4f698de5d7d6a45/tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs

Note that GCC, Clang and LLVM do not support c-variadic definitions of multiple ABIs: the `va_start`, `va_arg` etc. macros are always expanded using the default C calling convention. Clang and GCC reject a variable argument list on definitions that use a non-default calling convention.

## History

- [#t-lang > C-variadic naked functions](https://rust-lang.zulipchat.com/#narrow/channel/213817-t-lang/topic/C-variadic.20naked.20functions/with/554593886)
- #148770

The stabilization report of `feature(c_variadic)` mentions this feature:

- #155697

## Unresolved questions

None.
@rustbot

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. label Aug 16, 2026
@traviscross traviscross removed S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. labels Aug 16, 2026
folkertdev and others added 8 commits August 16, 2026 09:43
For the link definition for "naked functions", let's use the rule
identifier.  For `items.extern.variadic.conventions`, we don't need a
link definition since the link text is the full rule identifier.
We use "naked functions" twice in a single rule.  Let's link the first
use of this rather than the second.  (There would be some logic, here,
in linking the second since the first use is an exclusion while the
second is defining something for these, but it's better to follow our
convention.)
Let's restate this sentence in the active voice.  This is clearer and
better parallels the preceding rule.
For this example, rather than showing raw compiler output, which
contains a spill-and-reload sequence that is hard to follow, let's
write some assembly by hand.  And let's pick an example that motivates
the use of variadics.  We'll compute the dot product of a vector with
a projected scalar.  We'll support vector dimensions up to what can be
passed in with the `xmm` registers.
The rule says a naked function's ABI string must be "listed in"
another rule.  But that rule lists some ABI strings and then
separately accepts their `-unwind` variants.  We mean to accept
everything the other rule accepts.  Let's say "accepted under"
instead.
@traviscross
traviscross force-pushed the c-variadic-naked-functions branch from 3bb5bd3 to 4063aaf Compare August 16, 2026 09:44
@rustbot

rustbot commented Aug 16, 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.

@traviscross
traviscross added this pull request to the merge queue Aug 16, 2026
@traviscross

Copy link
Copy Markdown
Contributor

Thanks @folkertdev.

Merged via the queue into rust-lang:master with commit 9df7eb8 Aug 16, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants