|
| 1 | +# Externally Implementable Items |
| 2 | + |
| 3 | +| Metadata | | |
| 4 | +| -------- | -------------------------------------------------------------- | |
| 5 | +| Owner(s) | [Jonathan Dönszelmann](@jdonszelmann) and [Mara Bos](@m-ou-se) | |
| 6 | +| Teams | [lang], [compiler] | |
| 7 | +| Status | Proposed | |
| 8 | + |
| 9 | +## Summary |
| 10 | + |
| 11 | +We intend to implement [Externally Implementable Items](https://github.com/rust-lang/rust/issues/125418) in the compiler. |
| 12 | +The plan is to do so in a way that allows us to change the way `#[panic_handler]` and similar attributes are handled, |
| 13 | +making these library features instead of compiler built-ins. |
| 14 | +We intend to eventually support both statics and functions, |
| 15 | +but the priority is at functions right now. |
| 16 | + |
| 17 | +## Motivation |
| 18 | + |
| 19 | +(as per the rfcs[^1][^2][^3] on this): |
| 20 | + |
| 21 | +We have several items in the standard library that are overridable/definable by the user crate. |
| 22 | +For example, the (no_std) `panic_handler`, the global allocator for `alloc`, and so on. |
| 23 | + |
| 24 | +Each of those is a special lang item with its own special handling. |
| 25 | +Having a general mechanism simplifies the language and makes this functionality available for other crates, |
| 26 | +and potentially for more use cases in `core`/`alloc`/`std`. |
| 27 | + |
| 28 | +In general, having externally implementable items be feature of the language instead of magic lang items and linker hacks gives more flexibility. |
| 29 | +It creates a standard interface to expose points where libraries can be customized. |
| 30 | + |
| 31 | +Additionally, making externally implementable items a language feature makes it easier to document these points of customization. |
| 32 | +They can become part of the public api of a crate. |
| 33 | + |
| 34 | +[^1]: https://github.com/rust-lang/rfcs/pull/3632 |
| 35 | +[^2]: https://github.com/rust-lang/rfcs/pull/3635 |
| 36 | +[^3]: https://github.com/rust-lang/rfcs/pull/3645 |
| 37 | + |
| 38 | +### The status quo |
| 39 | + |
| 40 | +Today, "externally implementable items" exist in various forms that each have their own implementation. |
| 41 | +Examples are the `#[panic_handler]`, the global allocator, the global logger of the `log` crate, and so on. |
| 42 | +Some of these are magical lang items, whereas others need to be set at runtime or are done (unsafely) through a global (`#[no_mangle]`) linker symbol. |
| 43 | + |
| 44 | +After [RFC 3632], which proposes a new syntax for externally implementable _functions_, |
| 45 | +several alternative ideas were proposed in rapid succession |
| 46 | +that focussing on [statics](https://github.com/rust-lang/rfcs/pull/3635), [traits](https://github.com/rust-lang/rfcs/pull/3645), and [impl blocks](https://github.com/rust-lang/rfcs/pull/3632) rather than function definitions. |
| 47 | +Each of these having rougly equivalent power, but using a different part of Rust to achieve it. |
| 48 | + |
| 49 | +The lang team agreed that this is a problem worth solving, and accepted it as a _lang experiment_.[^4] |
| 50 | + |
| 51 | +While working on implementing possible solutions, |
| 52 | +we concluded that it'd be better to make use of attributes rather than new syntax, at least for now.[^5] |
| 53 | + |
| 54 | +Because this requires support for name resolution in attributes, this led to a big detour: |
| 55 | +refactoring how attributes are implemented and handled in rustc.[^6] |
| 56 | +The main part of that is now merged[^7], allowing us to finally continue on implementing the externally implementable items experiment itself. |
| 57 | + |
| 58 | +[^4]: https://github.com/rust-lang/rfcs/pull/3632#issuecomment-2125488373 |
| 59 | +[^5]: https://github.com/rust-lang/rust/issues/125418#issuecomment-2360542039 |
| 60 | +[^6]: https://github.com/rust-lang/rust/issues/131229 |
| 61 | +[^7]: https://github.com/rust-lang/rust/pull/131808 |
| 62 | + |
| 63 | +### The next 6 months |
| 64 | + |
| 65 | +The goal for the next six months is to finish the implementation of externally implementable items (as an experimental feature). |
| 66 | + |
| 67 | +It is not unthinkable that we run into more obstacles that requires some changes in the compiler, |
| 68 | +but we estimate that six months is enough to make the feature available for experimentation. |
| 69 | + |
| 70 | +### The "shiny future" we are working towards |
| 71 | + |
| 72 | +In the longer term, this feature should be able to replace the magic behind the panic handler, global allocator, oom handler, and so on. |
| 73 | +At that point, an attribute like `#[panic_handler]` would simply be a regular (externally implementable) item exported by `core`, for example. |
| 74 | + |
| 75 | +After stabilization, other crates in the ecosystem, such as the `log` crate, should be able to make use of this as well. |
| 76 | +E.g., they could have a `#[log::global_logger]` item that can be used to provide the global logger. |
| 77 | + |
| 78 | +In the longer term, this could enable more fine grained customization of parts of `core`, `alloc` and `std`, such as panic handling. |
| 79 | +For example, right now, all kind of panics, including overflows and out-of-bounds panics, can all only be handled |
| 80 | +through the `#[panic_handler]`, which will only get a panic message containing an (english) description of the problem. |
| 81 | +Instead, one could imagine having a `#[panic_oob_handler]` that gets the index and size as arguments, |
| 82 | +allowing one to customize the default behavior. |
| 83 | + |
| 84 | +## Design axioms |
| 85 | + |
| 86 | +The experimental feature we implement should: |
| 87 | + |
| 88 | +- be able to replace how `#[panic_handler]` and global allocator features are implemented. |
| 89 | + - This means the feature should not have a higher (memory, performance, etc.) cost than how those features are currently implemented. |
| 90 | + - This also puts some requirements on the supported functionality, to support everything that those features currently support. |
| 91 | + (E.g., being able to provide a default implementation that can be overridden later.) |
| 92 | +- be ergonomic. |
| 93 | + - This means that mistakes should not result in confusing linker errors, but in reasonable diagnostics. |
| 94 | +- allow for semver-compatible upgrade paths. |
| 95 | + - E.g. if a crate wants to change the signature or kind of an externally implementable item, |
| 96 | + it should be possible to have some backwards-compatible path forward. |
| 97 | +- be as close to zero-cost as possible. |
| 98 | + - E.g. adding the option for more fine grained panic handlers to `core` should not result in a loss of performance. |
| 99 | + |
| 100 | +## Ownership and team asks |
| 101 | + |
| 102 | +**Owner:** [Jonathan Dönszelmann](@jdonszelmann) and [Mara Bos](@m-ou-se) |
| 103 | + |
| 104 | +| Task | Owner(s) or team(s) | Notes | |
| 105 | +| ---------------------------------------------- | ----------------------- | ----- | |
| 106 | +| Discussion and moral support | [compiler], [lang] | | |
| 107 | +| Lang-team experiment | ![Team][] [lang] | Already approved | |
| 108 | +| Design experiment (syntax, etc.) | *Jonathan and Mara* | Done | |
| 109 | +| Refactor attributes in rustc | *Jonathan* | In progress, refactor merged | |
| 110 | +| Implement experiment | *Jonathan and Mara* | | |
| 111 | +| Standard reviews | ![Team][] [compiler] | | |
| 112 | +| Blog post inviting feedback | *Jonathan and Mara* | | |
| 113 | +| Update RFC with new findings | *Jonathan and Mara* | | |
| 114 | + |
| 115 | +## Frequently asked questions |
| 116 | + |
| 117 | +- None yet. |
0 commit comments