recorded decision · public · no signup

accepted2026-06-22rust-lang/rfcs

Explicit extern abis

What was chosen

  • In a new Rust edition, `extern` without an explicit ABI will be disallowed.adr
  • A warning will be issued for `extern` without an explicit ABI in editions prior to the change.adr
  • Users must explicitly write `extern "C"` or another ABI instead of just `extern`.adr

Constraints

  • This change cannot be included in the 2024 Rust edition due to timing constraints.adr
  • The original default of `"C"` for `extern` is no longer universally appropriate due to ongoing work on other ABIs.adr

Consequences

  • Explicit ABIs will enable clearer diagnostic messages regarding FFI-safety for specific ABIs.adr
  • Automatic migration for `cargo fix --edition` will be trivial, inserting `"C"` after `extern` if no ABI is present.adr
  • This change is breaking and requires a new Rust edition for implementation.adr
  • Removing the default ABI simplifies the future addition of new ABIs on equal footing with `"C"`.adr
  • Making the ABI explicit clarifies that `"C"` is one of many choices, not the sole standard for external functions.adr

The recorded why

§ Summary

Disallow extern without an explicit ABI in a new edition. Write extern "C" (or another ABI) instead of just extern.

- extern { … }
+ extern "C" { … }

- extern fn foo() { … }
+ extern "C" fn foo() { … }

§ Motivation

Originally, "C" was a very reasable default for extern. However, with work ongoing to add other ABIs to Rust, it is no longer obvious that "C" should forever stay the default.

By making the ABI explicit, it becomes much clearer that "C" is just one of the possible choices, rather than the "standard" way for external functions. Removing the default makes it easier to add a new ABI on equal footing as "C".

Right now, "extern", "FFI" and "C" are somewhat used interchangeably in Rust. For example, this is the diagnostic when using a String in an extern function:

warning: `extern` fn uses type `String`, which is not FFI-safe
 --> src/main.rs:1:16
  |
1 | extern fn a(s: String) {}
  |                ^^^^^^ not FFI-safe
  |
  = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
  = note: this struct has unspecified layout
  = note: `#[warn(improper_ctypes_definitions)]` on by default

If another future ABI will support String, this error should make it clearer that the problem is not that String doesn't support FFI, but rather that the "C" ABI doesn't support String. This would be easier if there was actually a "C" token to point at in the source code. E.g.:

warning: `extern` fn uses type `String`, which is not supported by the "C" ABI
 --> src/main.rs:1:16
  |
1 | extern "C" fn a(s: String) {}
  |        ---         ^^^^^^ String type not supported by this ABI
  |         |
  |         the "C" ABI does not support this type

It would also make it clearer that swapping "C" for another ABI might be an option.

§ Guilde-level explanation

Up to the previous edition, extern without an explicit ABI was equivalent to extern "C". In the new edition, writing extern without an ABI is an error. Instead, you must write extern "C" explicitly.

§ Automatic migration

Automatic migration (for cargo fix --edition) is trivial: Insert "C" after extern if there is no ABI.

§ Drawbacks

  • This is a breaking change and needs to be done in a new edition.

§ Prior art

This was proposed before Rust 1.0 in 2015 in RFC 697. It was not accepted at the time, because "C" seemed like the only resonable default. It was later closed because it'd be a backwards incompatible change, and editions were not yet invented.

§ Unresolved questions

§ Future possibilities

In the future, we might want to add a new default ABI. For example, if extern "stable-rust-abi" becomes a thing and e.g. dynamically linking Rust from Rust becomes very popular, it might make sense to make that the default when writing extern fn without an ABI. That is, however, a separate discussion; it might also be reasonable to never have a default ABI again.

Source: text/3722-explicit-extern-abis.md