Skip to content

document naked c-variadic functions - #2321

Open
folkertdev wants to merge 8 commits into
rust-lang:masterfrom
folkertdev:c-variadic-naked-functions
Open

document naked c-variadic functions#2321
folkertdev wants to merge 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
folkertdev and others added 7 commits August 9, 2026 00:36
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 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants