Skip to content

Add extern "custom" - #2300

Open
folkertdev wants to merge 14 commits into
rust-lang:masterfrom
folkertdev:extern-custom
Open

Add extern "custom"#2300
folkertdev wants to merge 14 commits into
rust-lang:masterfrom
folkertdev:extern-custom

Conversation

@folkertdev

Copy link
Copy Markdown
Contributor

stabilization PR: rust-lang/rust#158504

This is a tricky one that is an exception to some rules. I've tried to put the raw information in, but this'll probably require some refinement.

Comment thread src/items/external-blocks.md
Comment thread src/items/functions.md
Comment thread src/items/external-blocks.md
@ehuss ehuss added the S-waiting-on-stabilization Waiting for a stabilization PR to be merged in the main Rust repository label Jul 28, 2026
Comment thread src/items/external-blocks.md Outdated
Comment thread src/items/functions.md
@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 Jul 28, 2026
@rustbot

rustbot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Reminder, once the PR becomes ready for a review, use @rustbot ready.

folkertdev and others added 4 commits July 29, 2026 13:57
Co-authored-by: Travis Cross <tc@traviscross.com>
The `extern "custom"` rules were falling under the *Unwinding*
section.  Let's fix that.
This had said that an `extern "custom"` function *does* not have any
parameters, but it's clearer to say it *must* not have any parameters.
Comment thread src/items/functions.md Outdated
@traviscross
traviscross force-pushed the extern-custom branch 2 times, most recently from ac3a0e7 to 8752db9 Compare August 4, 2026 21:32
On the lang side, we decided the signature rules for `extern "custom"`
function pointers should match those for `extern "custom"` function
items.  Let's consolidate the signature rules on function items into a
single rule then cite that rule normatively from the function pointer
types chapter.
@traviscross traviscross removed the S-waiting-on-author Status: The marked PR is awaiting some action (such as code changes) from the PR author. label Aug 4, 2026
@traviscross
traviscross marked this pull request as ready for review August 4, 2026 21:39
@rustbot rustbot added the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Aug 4, 2026
@traviscross traviscross changed the title add extern "custom" Add extern "custom" Aug 4, 2026
@traviscross traviscross removed the S-waiting-on-review Status: The marked PR is awaiting review from a maintainer label Aug 4, 2026
In review, it was suggested that we add an example showing how
`extern "custom"` functions are used in practice.  Let's do that.
Often naked functions should use `extern "custom"`.  Let's add an
admonition to note that.
Comment thread src/items/functions.md Outdated
Comment on lines +284 to +286
- Be `unsafe`.
- Not have any parameters.
- Return the [unit type].

@tgross35 tgross35 Aug 9, 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.

Needs some consideration for generics, rust-lang/rust#158504 (comment) and the comment below

View changes since the review

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 guess that generics are probably okay and allowed by default if not disallowed?

@tgross35 tgross35 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.

Two things that I think should be resolved before merge

View changes since this review

Comment thread src/items/functions.md

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.

Looking through the list at https://doc.rust-lang.org/reference/items/functions.html#attributes-on-functions, also noticed that #[cold] may make no sense. Everything else seems fine

rust-lang/rust#158504 (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.

It doesn't do harm either, so should we really make an exception here? I'm not against it per se, just wondering if we should make this calling convention even more special.

@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.

I've added two updates based on the T-lang meeting (notes).

  • we decided that the current implementation of only allowing unit as a return type syntactically (i.e. type aliases that resolve to unit are rejected) is acceptable.
  • rust-lang/rust#161002

View changes since this review

Comment thread src/items/functions.md Outdated
Comment thread src/items/functions.md Outdated
jhpratt added a commit to jhpratt/rust that referenced this pull request Aug 15, 2026
…, r=tgross35

Stabilize `extern "custom"`

tracking issue: rust-lang#140829
reference PR: rust-lang/reference#2300
closes rust-lang#140829

## Summary

An `extern "custom" fn` is a function with a custom ABI that is unknown to rust. Often these are low-level functions that pass arguments in different registers than any standard calling convention.

```rust
#[unsafe(naked)]
pub unsafe extern "custom" fn __aeabi_uidivmod() {
    core::arch::naked_asm!(
        "push {{lr}}",
        "sub sp, sp, rust-lang#4",
        "mov r2, sp",
        "bl {trampoline}",
        "ldr r1, [sp]",
        "add sp, sp, rust-lang#4",
        "pop {{pc}}",
        trampoline = sym crate::arm::__udivmodsi4
    );
}

unsafe extern "custom" {
	fn __fentry__();
}
```

## Design

Because rust doesn't know what calling convention to use, an `extern "custom"` function can only be called via inline assembly or FFI.

```
error: functions with the "custom" ABI cannot be called
 --> <source>:5:5
  |
5 |     bar();
  |     ^^^^^
  |
note: an `extern "custom"` function can only be called using inline assembly
```

An `extern "custom"` function definition must be a naked function:

```
error: items with the "custom" ABI can only be declared externally or defined via naked functions
  --> <source>:10:1
   |
10 | unsafe extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: convert this to an `#[unsafe(naked)]` function
   |
10 + #[unsafe(naked)]
11 | unsafe extern "custom" fn bar() {
   |
```

An `extern "custom"` function definition must be unsafe. The intent here is that a safety comment is written on how this function may be called.

```
error: functions with the "custom" ABI must be unsafe
  --> <source>:10:1
   |
10 | extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: add the `unsafe` keyword to this definition
   |
10 | unsafe extern "custom" fn bar() {
   | ++++++
```

In an `extern "custom"` block, functions cannot be marked as `safe`:

```
error: foreign functions with the "custom" ABI cannot be safe
  --> <source>:16:5
   |
16 |     safe fn foobar();
   |     ^^^^^^^^^^^^^^^^^
   |
help: remove the `safe` keyword from this definition
   |
16 -     safe fn foobar();
16 +     fn foobar();
```

An `extern "custom"` function cannot have any arguments or a return type:

```
error: invalid signature for `extern "custom"` function
 --> <source>:6:31
  |
6 | unsafe extern "custom" fn foo(a: i32) -> i32 {
  |                               ^^^^^^     ^^^
  |
  = note: functions with the "custom" ABI cannot have any parameters or return type
help: remove the parameters and return type
  |
6 - unsafe extern "custom" fn foo(a: i32) -> i32 {
6 + unsafe extern "custom" fn foo() {
  |
```

## Tests

- [tests/ui/abi/custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/custom.rs) tests that the feature works as expected, e.g. that functions can be defined, symbols are defined, and extern blocks can be used.
- [tests/ui/abi/bad-custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/bad-custom.rs) checks the restrictions: definitions must be unsafe and naked, attempting to call an `extern "custom"` function gives an error, etc.
-
## History

* rust-lang#140566
* rust-lang#140829
* rust-lang#140770
* rust-lang#159780

## unresolved questions

None
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 15, 2026
…, r=tgross35

Stabilize `extern "custom"`

tracking issue: rust-lang#140829
reference PR: rust-lang/reference#2300
closes rust-lang#140829

## Summary

An `extern "custom" fn` is a function with a custom ABI that is unknown to rust. Often these are low-level functions that pass arguments in different registers than any standard calling convention.

```rust
#[unsafe(naked)]
pub unsafe extern "custom" fn __aeabi_uidivmod() {
    core::arch::naked_asm!(
        "push {{lr}}",
        "sub sp, sp, rust-lang#4",
        "mov r2, sp",
        "bl {trampoline}",
        "ldr r1, [sp]",
        "add sp, sp, rust-lang#4",
        "pop {{pc}}",
        trampoline = sym crate::arm::__udivmodsi4
    );
}

unsafe extern "custom" {
	fn __fentry__();
}
```

## Design

Because rust doesn't know what calling convention to use, an `extern "custom"` function can only be called via inline assembly or FFI.

```
error: functions with the "custom" ABI cannot be called
 --> <source>:5:5
  |
5 |     bar();
  |     ^^^^^
  |
note: an `extern "custom"` function can only be called using inline assembly
```

An `extern "custom"` function definition must be a naked function:

```
error: items with the "custom" ABI can only be declared externally or defined via naked functions
  --> <source>:10:1
   |
10 | unsafe extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: convert this to an `#[unsafe(naked)]` function
   |
10 + #[unsafe(naked)]
11 | unsafe extern "custom" fn bar() {
   |
```

An `extern "custom"` function definition must be unsafe. The intent here is that a safety comment is written on how this function may be called.

```
error: functions with the "custom" ABI must be unsafe
  --> <source>:10:1
   |
10 | extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: add the `unsafe` keyword to this definition
   |
10 | unsafe extern "custom" fn bar() {
   | ++++++
```

In an `extern "custom"` block, functions cannot be marked as `safe`:

```
error: foreign functions with the "custom" ABI cannot be safe
  --> <source>:16:5
   |
16 |     safe fn foobar();
   |     ^^^^^^^^^^^^^^^^^
   |
help: remove the `safe` keyword from this definition
   |
16 -     safe fn foobar();
16 +     fn foobar();
```

An `extern "custom"` function cannot have any arguments or a return type:

```
error: invalid signature for `extern "custom"` function
 --> <source>:6:31
  |
6 | unsafe extern "custom" fn foo(a: i32) -> i32 {
  |                               ^^^^^^     ^^^
  |
  = note: functions with the "custom" ABI cannot have any parameters or return type
help: remove the parameters and return type
  |
6 - unsafe extern "custom" fn foo(a: i32) -> i32 {
6 + unsafe extern "custom" fn foo() {
  |
```

## Tests

- [tests/ui/abi/custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/custom.rs) tests that the feature works as expected, e.g. that functions can be defined, symbols are defined, and extern blocks can be used.
- [tests/ui/abi/bad-custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/bad-custom.rs) checks the restrictions: definitions must be unsafe and naked, attempting to call an `extern "custom"` function gives an error, etc.
-
## History

* rust-lang#140566
* rust-lang#140829
* rust-lang#140770
* rust-lang#159780

## unresolved questions

None
On lang, we decided that an `extern "custom"` function must
syntactically have a return type of unit and that the `cold` attribute
may not be applied to these functions.  Let's revise the text for
these new rules.
Rather than putting the rule that the `cold` attribute may not be
applied to `extern "custom"` functions in the functions chapter, let's
document it with the `cold` attribute.  This is what we do in other
cases where an attribute has restrictions on where it may be used.
Let's add an example to show that we do not allow applying the `cold`
attribute to an `extern "custom"` function.
Let's add an example to show that we do not allow an `extern "custom"`
function to have a type alias as its return type, even if that type
alias is defined to be the unit type.
JonathanBrouwer added a commit to JonathanBrouwer/rust that referenced this pull request Aug 15, 2026
…, r=tgross35

Stabilize `extern "custom"`

tracking issue: rust-lang#140829
reference PR: rust-lang/reference#2300
closes rust-lang#140829

## Summary

An `extern "custom" fn` is a function with a custom ABI that is unknown to rust. Often these are low-level functions that pass arguments in different registers than any standard calling convention.

```rust
#[unsafe(naked)]
pub unsafe extern "custom" fn __aeabi_uidivmod() {
    core::arch::naked_asm!(
        "push {{lr}}",
        "sub sp, sp, rust-lang#4",
        "mov r2, sp",
        "bl {trampoline}",
        "ldr r1, [sp]",
        "add sp, sp, rust-lang#4",
        "pop {{pc}}",
        trampoline = sym crate::arm::__udivmodsi4
    );
}

unsafe extern "custom" {
	fn __fentry__();
}
```

## Design

Because rust doesn't know what calling convention to use, an `extern "custom"` function can only be called via inline assembly or FFI.

```
error: functions with the "custom" ABI cannot be called
 --> <source>:5:5
  |
5 |     bar();
  |     ^^^^^
  |
note: an `extern "custom"` function can only be called using inline assembly
```

An `extern "custom"` function definition must be a naked function:

```
error: items with the "custom" ABI can only be declared externally or defined via naked functions
  --> <source>:10:1
   |
10 | unsafe extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: convert this to an `#[unsafe(naked)]` function
   |
10 + #[unsafe(naked)]
11 | unsafe extern "custom" fn bar() {
   |
```

An `extern "custom"` function definition must be unsafe. The intent here is that a safety comment is written on how this function may be called.

```
error: functions with the "custom" ABI must be unsafe
  --> <source>:10:1
   |
10 | extern "custom" fn bar() {
   | ^^^^^^^^^^^^^^^^^^^^^^^^
   |
help: add the `unsafe` keyword to this definition
   |
10 | unsafe extern "custom" fn bar() {
   | ++++++
```

In an `extern "custom"` block, functions cannot be marked as `safe`:

```
error: foreign functions with the "custom" ABI cannot be safe
  --> <source>:16:5
   |
16 |     safe fn foobar();
   |     ^^^^^^^^^^^^^^^^^
   |
help: remove the `safe` keyword from this definition
   |
16 -     safe fn foobar();
16 +     fn foobar();
```

An `extern "custom"` function cannot have any arguments or a return type:

```
error: invalid signature for `extern "custom"` function
 --> <source>:6:31
  |
6 | unsafe extern "custom" fn foo(a: i32) -> i32 {
  |                               ^^^^^^     ^^^
  |
  = note: functions with the "custom" ABI cannot have any parameters or return type
help: remove the parameters and return type
  |
6 - unsafe extern "custom" fn foo(a: i32) -> i32 {
6 + unsafe extern "custom" fn foo() {
  |
```

## Tests

- [tests/ui/abi/custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/custom.rs) tests that the feature works as expected, e.g. that functions can be defined, symbols are defined, and extern blocks can be used.
- [tests/ui/abi/bad-custom.rs](https://github.com/rust-lang/rust/blob/main/tests/ui/abi/bad-custom.rs) checks the restrictions: definitions must be unsafe and naked, attempting to call an `extern "custom"` function gives an error, etc.
-
## History

* rust-lang#140566
* rust-lang#140829
* rust-lang#140770
* rust-lang#159780

## 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.

6 participants