|
| 1 | +- Feature Name: `explicit_abi` |
| 2 | +- Start Date: 2024-10-30 |
| 3 | +- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) |
| 4 | +- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) |
| 5 | + |
| 6 | +# Summary |
| 7 | + |
| 8 | +Disallow `extern` without an explicit ABI in a new edition. Write `extern "C"` (or another ABI) instead of just `extern`. |
| 9 | + |
| 10 | +```diff |
| 11 | +- extern { … } |
| 12 | ++ extern "C" { … } |
| 13 | + |
| 14 | +- extern fn foo() { … } |
| 15 | ++ extern "C" fn foo() { … } |
| 16 | +``` |
| 17 | + |
| 18 | +# Motivation |
| 19 | + |
| 20 | +Originally, `"C"` was a very reasable default for `extern`. |
| 21 | +However, with work ongoing to add other ABIs to Rust, it is no longer obvious that `"C"` should forever stay the default. |
| 22 | + |
| 23 | +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. |
| 24 | +Removing the default makes it easier to add a new ABI on equal footing as `"C"`. |
| 25 | + |
| 26 | +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: |
| 27 | + |
| 28 | +``` |
| 29 | +warning: `extern` fn uses type `String`, which is not FFI-safe |
| 30 | + --> src/main.rs:1:16 |
| 31 | + | |
| 32 | +1 | extern fn a(s: String) {} |
| 33 | + | ^^^^^^ not FFI-safe |
| 34 | + | |
| 35 | + = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct |
| 36 | + = note: this struct has unspecified layout |
| 37 | + = note: `#[warn(improper_ctypes_definitions)]` on by default |
| 38 | +``` |
| 39 | + |
| 40 | +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`. |
| 41 | +This would be easier if there was actually a `"C"` token to point at in the source code. E.g.: |
| 42 | + |
| 43 | +``` |
| 44 | +warning: `extern` fn uses type `String`, which is not supported by the "C" ABI |
| 45 | + --> src/main.rs:1:16 |
| 46 | + | |
| 47 | +1 | extern "C" fn a(s: String) {} |
| 48 | + | --- ^^^^^^ String type not supported by this ABI |
| 49 | + | | |
| 50 | + | the "C" ABI does not support this type |
| 51 | +``` |
| 52 | + |
| 53 | +It would also make it clearer that swapping `"C"` for another ABI might be an option. |
| 54 | + |
| 55 | +# Guilde-level explanation |
| 56 | + |
| 57 | +Up to the previous edition, `extern` without an explicit ABI was equivalent to `extern "C"`. |
| 58 | +In the new edition, writing `extern` without an ABI is an error. |
| 59 | +Instead, you must write `extern "C"` explicitly. |
| 60 | + |
| 61 | +# Automatic migration |
| 62 | + |
| 63 | +Automatic migration (for `cargo fix --edition`) is trivial: Insert `"C"` after `extern` if there is no ABI. |
| 64 | + |
| 65 | +# Drawbacks |
| 66 | + |
| 67 | +- This is a breaking change and needs to be done in a new edition. |
| 68 | + |
| 69 | +# Prior art |
| 70 | + |
| 71 | +This was proposed before Rust 1.0 in 2015 in [RFC 697](https://github.com/rust-lang/rfcs/pull/697). |
| 72 | +It was not accepted at the time, because "C" seemed like the only resonable default. |
| 73 | +It was later closed because it'd be a backwards incompatible change, and editions were not yet invented. |
| 74 | + |
| 75 | +# Unresolved questions |
| 76 | + |
| 77 | +- In which edition do we make this change? It's a bit late to add things to the 2024 edition, but the change is tiny and the migration and impact is trivial. |
| 78 | +- Do we warn about `extern` without an explicit ABI in previous editions? |
| 79 | + |
| 80 | +# Future possibilities |
| 81 | + |
| 82 | +In the future, we might want to add a new default ABI. |
| 83 | +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. |
| 84 | +That is, however, a separate discussion; it might also be reasonable to never have a default ABI again. |
0 commit comments