From 0a83cc3e74c047aa6a27a5823ec291c032fa072d Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Sun, 28 Jun 2026 01:50:04 +0200 Subject: [PATCH 1/8] add `extern "custom"` --- src/items/external-blocks.md | 5 ++++- src/items/functions.md | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index e547edf8a1..aa3b0072db 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -48,7 +48,7 @@ r[items.extern.fn.param-patterns] Patterns are not allowed in parameters, only [IDENTIFIER] or `_` may be used. r[items.extern.fn.qualifiers] -The `safe` and `unsafe` function qualifiers are allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are not. +The `safe` and `unsafe` function qualifiers are allowed, but other function qualifiers (e.g. `const`, `async`, `extern`) are not. The `safe` qualifier is rejected in `extern "custom"` blocks. r[items.extern.fn.foreign-abi] Functions within external blocks may be called by Rust code, just like functions defined in Rust. The Rust compiler automatically translates between the Rust ABI and the foreign ABI. @@ -112,6 +112,9 @@ r[items.extern.abi.system] r[items.extern.abi.unwind] * `extern "C-unwind"` and `extern "system-unwind"` --- Identical to `"C"` and `"system"`, respectively, but with [different behavior][unwind-behavior] when the callee unwinds (by panicking or throwing a C++ style exception). +r[items.extern.abi.custom] +* `unsafe extern "custom"` --- A custom ABI that is not known to the rust compiler. + r[items.extern.abi.platform] There are also some platform-specific ABI strings: diff --git a/src/items/functions.md b/src/items/functions.md index 362b39b573..360f734bd4 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -239,6 +239,15 @@ With `panic=unwind`, when a `panic` is turned into an abort by a non-unwinding A For other considerations and limitations regarding unwinding across FFI boundaries, see the [relevant section in the Panic documentation][panic-ffi]. +r[items.fn.extern.custom] +An `extern "custom"` function has an unknown, custom ABI. The only way to call such a function is via [inline assembly]. + +r[items.fn.extern.custom.safety] +An `extern "custom"` function must be `unsafe`. + +r[items.fn.extern.custom.naked] +An `extern "custom"` function definition must be a [naked function]. + [forced-unwinding]: https://rust-lang.github.io/rfcs/2945-c-unwind-abi.html#forced-unwinding [panic handler]: ../panic.md#the-panic_handler-attribute [panic-ffi]: ../panic.md#unwinding-across-ffi-boundaries @@ -411,6 +420,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [testing attributes]: ../attributes/testing.md [`cold`]: ../attributes/codegen.md#the-cold-attribute [`inline`]: ../attributes/codegen.md#the-inline-attribute +[naked function]: ../attributes/codegen.md#the-naked-attribute [`deprecated`]: ../attributes/diagnostics.md#the-deprecated-attribute [`doc`]: ../../rustdoc/the-doc-attribute.html [`must_use`]: ../attributes/diagnostics.md#the-must_use-attribute @@ -427,3 +437,4 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [variadic function]: external-blocks.md#variadic-functions [`extern` block]: external-blocks.md [zero-sized]: glossary.zst +[inline assembly]: ../inline-assembly.md From 2890548b6305957be3e84194591f1ab136deda7f Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 29 Jul 2026 13:57:05 +0200 Subject: [PATCH 2/8] Update src/items/external-blocks.md Co-authored-by: Travis Cross --- src/items/external-blocks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/external-blocks.md b/src/items/external-blocks.md index aa3b0072db..938ac35fa2 100644 --- a/src/items/external-blocks.md +++ b/src/items/external-blocks.md @@ -113,7 +113,7 @@ r[items.extern.abi.unwind] * `extern "C-unwind"` and `extern "system-unwind"` --- Identical to `"C"` and `"system"`, respectively, but with [different behavior][unwind-behavior] when the callee unwinds (by panicking or throwing a C++ style exception). r[items.extern.abi.custom] -* `unsafe extern "custom"` --- A custom ABI that is not known to the rust compiler. +* `unsafe extern "custom"` --- A custom ABI that is not known to the compiler. r[items.extern.abi.platform] There are also some platform-specific ABI strings: From c979f98ab1ed5234a0155b672af4591e024235be Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 29 Jul 2026 14:02:19 +0200 Subject: [PATCH 3/8] add rules for parameters and return type --- src/items/functions.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/items/functions.md b/src/items/functions.md index 360f734bd4..81c2bdd9df 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -245,6 +245,12 @@ An `extern "custom"` function has an unknown, custom ABI. The only way to call s r[items.fn.extern.custom.safety] An `extern "custom"` function must be `unsafe`. +r[items.fn.extern.custom.parameters] +An `extern "custom"` function does not have any parameters. + +r[items.fn.extern.custom.return-type] +An `extern "custom"` function must return the [unit type]. + r[items.fn.extern.custom.naked] An `extern "custom"` function definition must be a [naked function]. From 38b00b1d08e88b795d3fd32470f5767bc2baf440 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 4 Aug 2026 20:29:08 +0000 Subject: [PATCH 4/8] Add missing header for `extern "custom"` The `extern "custom"` rules were falling under the *Unwinding* section. Let's fix that. --- src/items/functions.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/items/functions.md b/src/items/functions.md index 81c2bdd9df..f15a23365d 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -240,6 +240,9 @@ With `panic=unwind`, when a `panic` is turned into an abort by a non-unwinding A For other considerations and limitations regarding unwinding across FFI boundaries, see the [relevant section in the Panic documentation][panic-ffi]. r[items.fn.extern.custom] +### Extern "custom" + +r[items.fn.extern.custom.intro] An `extern "custom"` function has an unknown, custom ABI. The only way to call such a function is via [inline assembly]. r[items.fn.extern.custom.safety] From 20aeb84b1d26f5a0cd927c596d047e619ba855f8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 4 Aug 2026 20:30:08 +0000 Subject: [PATCH 5/8] Say that an `extern "custom"` fn *must* not have params 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. --- src/items/functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/items/functions.md b/src/items/functions.md index f15a23365d..293b3fbebd 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -249,7 +249,7 @@ r[items.fn.extern.custom.safety] An `extern "custom"` function must be `unsafe`. r[items.fn.extern.custom.parameters] -An `extern "custom"` function does not have any parameters. +An `extern "custom"` function must not have any parameters. r[items.fn.extern.custom.return-type] An `extern "custom"` function must return the [unit type]. From 9ea9daf71d284d1036eac3108e8b35632dc28b70 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 4 Aug 2026 20:37:57 +0000 Subject: [PATCH 6/8] Add rules on `extern "custom"` `fn()` signatures 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. --- src/items/functions.md | 12 +++++------- src/types/function-pointer.md | 3 +++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/items/functions.md b/src/items/functions.md index 293b3fbebd..61c42d1199 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -245,14 +245,12 @@ r[items.fn.extern.custom] r[items.fn.extern.custom.intro] An `extern "custom"` function has an unknown, custom ABI. The only way to call such a function is via [inline assembly]. -r[items.fn.extern.custom.safety] -An `extern "custom"` function must be `unsafe`. +r[items.fn.extern.custom.signature] +An `extern "custom"` function must: -r[items.fn.extern.custom.parameters] -An `extern "custom"` function must not have any parameters. - -r[items.fn.extern.custom.return-type] -An `extern "custom"` function must return the [unit type]. +- Be `unsafe`. +- Not have any parameters. +- Return the [unit type]. r[items.fn.extern.custom.naked] An `extern "custom"` function definition must be a [naked function]. diff --git a/src/types/function-pointer.md b/src/types/function-pointer.md index 08dfbbf235..70db496571 100644 --- a/src/types/function-pointer.md +++ b/src/types/function-pointer.md @@ -50,6 +50,9 @@ The `unsafe` qualifier indicates that the type's value is an [unsafe function], r[type.fn-pointer.constraint-variadic] For the function to be variadic, its `extern` ABI must be one of those listed in [items.extern.variadic.conventions]. +r[type.fn-pointer.extern-custom] +An `extern "custom"` function pointer must follow the rules in [items.fn.extern.custom.signature]. + r[type.fn-pointer.attributes] ## Attributes on function pointer parameters From ae9e6b97adcc101dacac093052e40cb58590903a Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 4 Aug 2026 21:14:54 +0000 Subject: [PATCH 7/8] Add example to the `extern "custom"` section In review, it was suggested that we add an example showing how `extern "custom"` functions are used in practice. Let's do that. --- src/items/functions.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/items/functions.md b/src/items/functions.md index 61c42d1199..c034711798 100644 --- a/src/items/functions.md +++ b/src/items/functions.md @@ -245,6 +245,39 @@ r[items.fn.extern.custom] r[items.fn.extern.custom.intro] An `extern "custom"` function has an unknown, custom ABI. The only way to call such a function is via [inline assembly]. +> [!EXAMPLE] +> ```rust +> # #[cfg(target_arch = "x86_64")] { +> # use core::arch::{asm, naked_asm}; +> # +> /// Adds 1 to `rax`. +> /// +> /// This function uses a custom calling convention: the argument is +> /// passed in `rax`, the result is returned in `rax`, the flags may +> /// be clobbered, and all other registers are preserved. +> #[unsafe(naked)] +> unsafe extern "custom" fn increment() { +> naked_asm!( +> "add rax, 1", +> "ret", +> ) +> } +> +> let mut x: u64 = 41; +> // SAFETY: The inline assembly respects the calling convention of +> // `increment`: the argument is passed in `rax`, the result is read +> // from `rax`, and no other registers are affected. +> unsafe { +> asm!( +> "call {}", +> sym increment, +> inout("rax") x, +> ); +> } +> assert_eq!(x, 42); +> # } +> ``` + r[items.fn.extern.custom.signature] An `extern "custom"` function must: From 66b3bc5b868839206f675b2c54416f89c1098a60 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 4 Aug 2026 21:14:54 +0000 Subject: [PATCH 8/8] Note that naked functions often want `extern "custom"` Often naked functions should use `extern "custom"`. Let's add an admonition to note that. --- src/attributes/codegen.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/attributes/codegen.md b/src/attributes/codegen.md index d3ecf00b88..ee8301d102 100644 --- a/src/attributes/codegen.md +++ b/src/attributes/codegen.md @@ -144,6 +144,9 @@ The *`naked` [attribute]* prevents the compiler from emitting a function prologu > # } > ``` +> [!NOTE] +> The assembly code of a naked function often does not follow the calling convention of any ABI known to the compiler. Such a function should be declared as an [`extern "custom"` function][items.fn.extern.custom]. + r[attributes.codegen.naked.syntax] The `naked` attribute uses the [MetaWord] syntax.