Skip to content

Commit

Permalink
Add explicit abi RFC.
Browse files Browse the repository at this point in the history
  • Loading branch information
m-ou-se committed Oct 30, 2024
1 parent 60a6758 commit d0699ca
Showing 1 changed file with 84 additions and 0 deletions.
84 changes: 84 additions & 0 deletions text/3722-explicit-abi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
- Feature Name: `explicit_abi`
- Start Date: 2024-10-30
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000)
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000)

# Summary

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

```diff
- 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](https://github.com/rust-lang/rfcs/pull/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

- 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.
- Do we warn about `extern` without an explicit ABI in previous editions?

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

0 comments on commit d0699ca

Please sign in to comment.