diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 664c63da0fc..c7996c27c2f 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4250,13 +4250,46 @@ /// The `never_type_fallback_flowing_into_unsafe` lint detects cases where never type fallback /// affects unsafe function calls. /// + /// ### Never type fallback + /// + /// When the compiler sees a value of type [`!`] it implicitly inserts a coercion (if possible), + /// to allow type check to infer any type: + /// + /// ```ignore (illustrative-and-has-placeholders) + /// // this + /// let x: u8 = panic!(); + /// + /// // is (essentially) turned by the compiler into + /// let x: u8 = absurd(panic!()); + /// + /// // where absurd is a function with the following signature + /// // (it's sound, because `!` always marks unreachable code): + /// fn absurd(_: !) -> T { ... } + // FIXME: use `core::convert::absurd` here instead, once it's merged + /// ``` + /// + /// While it's convenient to be able to use non-diverging code in one of the branches (like + /// `if a { b } else { return }`) this could lead to compilation errors: + /// + /// ```compile_fail + /// // this + /// { panic!() }; + /// + /// // gets turned into this + /// { absurd(panic!()) }; // error: can't infer the type of `absurd` + /// ``` + /// + /// To prevent such errors, compiler remembers where it inserted `absurd` calls, and if it + /// can't infer their type, it sets the type to fallback. `{ absurd::(panic!()) };`. + /// This is what is known as "never type fallback". + /// /// ### Example /// /// ```rust,compile_fail /// #![deny(never_type_fallback_flowing_into_unsafe)] /// fn main() { /// if true { - /// // return has type `!` (never) which, is some cases, causes never type fallback + /// // return has type `!` which, is some cases, causes never type fallback /// return /// } else { /// // `zeroed` is an unsafe function, which returns an unbounded type @@ -4271,7 +4304,7 @@ /// /// ### Explanation /// - /// Due to historic reasons never type fallback were `()`, meaning that `!` got spontaneously + /// Due to historic reasons never type fallback was `()`, meaning that `!` got spontaneously /// coerced to `()`. There are plans to change that, but they may make the code such as above /// unsound. Instead of depending on the fallback, you should specify the type explicitly: /// ``` @@ -4284,6 +4317,9 @@ /// ``` /// /// See [Tracking Issue for making `!` fall back to `!`](https://github.com/rust-lang/rust/issues/123748). + /// + /// [`!`]: https://doc.rust-lang.org/core/primitive.never.html + /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE, Warn, "never type fallback affecting unsafe function calls"