Skip to content

Unreachable code errors after the never type got stabilized #161841

Closed as not planned

Description

@ilovepi

I tried this code:

// RUN: rustc %s --crate-type=lib
// Version rustc 1.100.0-nightly (6510953ce 2026-08-26)

#![deny(unreachable_code)]
use std::convert::Infallible;

pub fn repro_unreachable_expression(res: Result<u32, Infallible>) -> u32 {
    match res {
        Ok(v) => v,
        Err(x) => {
            let x: Infallible = x;
            match x {}
        }
    }
}

pub fn repro_unreachable_call(res: Result<(), Infallible>) -> Result<(), String> {
    res.map_err(|e| e.to_string())
}

I expected to see this happen: No errors or diagnostics.

Instead, this happened: An error diagnostic.

prebuilt/third_party/rust/linux-x64/bin/rustc repro_inlined.rs --crate-type=lib
error: unreachable expression
  --> repro_inlined.rs:12:13
   |
11 |             let x: Infallible = x;
   |                                 - any code following this expression is unreachable
12 |             match x {}
   |             ^^^^^^^^^^ unreachable expression
   |
note: the lint level is defined here
  --> repro_inlined.rs:4:9
   |
 4 | #![deny(unreachable_code)]
   |         ^^^^^^^^^^^^^^^^

error: unreachable call
  --> repro_inlined.rs:18:23
   |
18 |     res.map_err(|e| e.to_string())
   |                     - ^^^^^^^^^ unreachable call
   |                     |
   |                     any code following this expression is unreachable

error: aborting due to 2 previous errors

Meta

rustc --version --verbose:

rustc 1.100.0-nightly (6510953ce 2026-08-26)
binary: rustc
commit-hash: 6510953ce01859dc271e3285cf539e03d0d781e7
commit-date: 2026-08-26
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 24.0.0

We hit this when qualifying a new Toochain for Fuchsia. From what I can tell, this seems like a regression after #155499 landed. There are probably some changes we can make in Fuchsia's Rust code to avoid breaking the build, but I thought its surprising enough to bear reporting, as this wasn't an obvious thing to happen as fallout from that PR. Admittedly, I'm not the sagest of Rust developers, so perhaps it should have been.

In any case, I wanted to raise this and figure out if the maintainers agree this is a regression, and if so how to proceed. If this the diagnostic is the intended behavior, it likely warrants more documentation and maybe a more detailed example in the release notes (or wherever is appropriate), as I think this will break many users.

Activity

  1. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 26, 2026
  2. asquared31415 commented on Aug 26, 2026

    @asquared31415
    Contributor

    The expressions x and e now have type ! which means that reachability analysis can now see that following expressions cannot be reached. I believe this is an expected (and even desired) change because of Infallible=!. The tracking issue for this change is #155924. Crater runs from various never type change tests did turn up a few deny(unreachable_code) errors (the most I see among the crater runs that I checked is 4 unique crates), so this is at the very least not completely unknown.

    Additionally, changes to lints (especially when they become more correct) are not generally considered breaking, unless there's a particularly good reason.

  3. asquared31415 commented on Aug 26, 2026

    @asquared31415
  4. added
    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.
    A-never-typeArea: `!` type. For issues not specific to `!`, use A-uninhabited-types.
    T-libsRelevant to the library team, which will review and decide on the PR/issue.
    and removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Aug 26, 2026
  5. changed the title [-]Unreachable code errors after #155499[/-] [+]Unreachable code errors after the never type got stabilized[/+] on Aug 27, 2026
  6. added
    C-discussionCategory: Discussion or questions that doesn't represent real issues.
    and removed
    C-bugCategory: This is a bug.
    on Aug 27, 2026
  7. WaffleLapkin commented on Aug 27, 2026

    @WaffleLapkin
    Member

    As @asquared31415 pointed out, this is expected behavior. Since #155499 made Infallible a type alias to !, the unreachable code lint detects more code that is unreachable (it checks for ! specifically).

    In these examples you can fix the problem by omitting unnecessary branches or using the never-to-any coercion directly (play):

    #![deny(unreachable_code)]
    use std::convert::Infallible;
    
    pub fn repro_unreachable_expression(res: Result<u32, Infallible>) -> u32 {
        match res {
            Ok(v) => v,
    -        Err(x) => {
    -            let x: Infallible = x;
    -            match x {}
    -        }
        }
    }
    
    pub fn repro_unreachable_call(res: Result<(), Infallible>) -> Result<(), String> {
    -    res.map_err(|e| e.to_string())
    +    res.map_err(|e| e)
    }
  8. ilovepi commented on Aug 27, 2026

    @ilovepi
    ContributorAuthor

    Thanks for confirming. I'll see if we can get some of this addressed in Fuchsia.

  9. djkoloski commented on Aug 28, 2026

    @djkoloski
    Contributor

    In this case, the lint is "leaking" through an external declarative macro (from pin-init). Per this comment, it seems like lints should be suppressed when they're from external macros. Do we expect reachability analysis to leak through macros e.g. because it's run on HIR/MIR?

  10. WaffleLapkin commented on Sep 4, 2026

    @WaffleLapkin
    Member

    @djkoloski unreachable code lint is specifically defined to be reported in external macros since #52562. I'm not sure what the context of that is though...

  11. djkoloski commented on Sep 4, 2026

    @djkoloski
    Contributor

    Looks like this is intentional then. Thanks for clarifying this for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.A-never-typeArea: `!` type. For issues not specific to `!`, use A-uninhabited-types.C-discussionCategory: Discussion or questions that doesn't represent real issues.L-unreachable_codeLint: unreachable_codeT-libsRelevant to the library team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions