# Static rustc_lint_defs::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE

source ·

    pub static NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE: &Lint

Expand description

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:

ⓘ

    // 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>(_: !) -> T { ... }

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:

ⓘ

    // 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::<Fallback>(panic!()) };`. This is what is known as “never type fallback”.

#### §Example

ⓘ

    #![deny(never_type_fallback_flowing_into_unsafe)]
    fn main() {
        if true {
            // return has type `!` which, is some cases, causes never type fallback
            return
        } else {
            // `zeroed` is an unsafe function, which returns an unbounded type
            unsafe { std::mem::zeroed() }
        };
        // depending on the fallback, `zeroed` may create `()` (which is completely sound),
        // or `!` (which is instant undefined behavior)
    }

{{produces}}

#### §Explanation

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:

    if true {
        return
    } else {
        // type is explicitly specified, fallback can't hurt us no more
        unsafe { std::mem::zeroed::<()>() }
    };

See Tracking Issue for making `!` fall back to `!`.