In today's Rust, the concept of panic, a critical runtime error, exists outside of the type system. While this allows us to code without thinking much about it, people who code in embedded, bare-metal, or do FFI, really do have to. There have been multiple efforts to tackle this outside of the language, like extra tooling or linker scripts, but these are workarounds and cumbersome at best.
We currently have different traits for functions:
FnMut. On closures, these are implemented based on what the closure does with its captured variables. My idea is to have another
Fn trait for those that do not panic, e.g.
FnNoPanic, which is implemented by all functions that may never (safely) trigger stack unwinding. Then, we would be able to do
let x: impl FnNoPanic = || foo(); in order to ensure panic safety. This way, if
foo() called code that, in turn, could panic, it would result in a compilation error.
In order to have these checks performed at the function declaration boundary, the most straightforward way would be an attribute. We could have a
#[no_panic] attribute that ensures that the function implements the
FnNoPanic trait. With this header, the function will not compile if it may panic.
However, this is a HUGE semver hazard. Changing the internal code of a function (not the interface) would have an effect on the callers! For this reason, I propose this to not be part of semver unless the attribute is used. I fear this is not enough and would create lots of footguns, so a reasonable solution would be to have the
FnNoPanic trait be only implemented if the attribute is present or all called functions have this attribute; and then have a way to unsafely implement it if a function from another crate doesn't implement it, but should.
Functions pointers do and will not make any guarantees about panic safety, so any function pointer that can't be tracked while type-checking (function pointers as function arguments, for example), are assumed not to implement
Any external function (rust ABI or not) must implement the
FnNoPanic trait unsafely. This is because the compiler is unable to check them directly.
Unsafe attributes are a feature that has been discussed for quite long, and we could use them to implement this unsafely. Bikeshed: