False-positive with the unreachable code lint
Given the following code: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=67b068c7dded060fd71f7e5a5ca91278
#![allow(deprecated, invalid_value)]
enum Void {}
fn main() {
if false {
unsafe { std::mem::uninitialized::<Void>(); }
}
println!();
}
The current output is:
warning: unreachable expression
--> src/main.rs:10:5
|
7 | unsafe { std::mem::uninitialized::<Void>(); }
| --------------------------------- any code following this expression is unreachable
...
10 | println!();
| ^^^^^^^^^^^ unreachable expression
|
= note: `#[warn(unreachable_code)]` on by default
note: this expression has type `Void`, which is uninhabited
--> src/main.rs:7:18
|
7 | unsafe { std::mem::uninitialized::<Void>(); }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this warning originates in the macro `$crate::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
warning: `playground` (bin "playground") generated 1 warning
I expected no lint to trigger as the println!() is actually reachable. This problem doesn't occur for panic!().
@rustbot claim
Hi @bjorn3! Can you elaborate a little on what makes println!() reachable here?
println!() is reachable as the std::mem::uninitialized::<Void>(); is never executed due to if false {}.
@rustbot release-assignment
I've located the issue to be in the liveness check: https://github.com/rust-lang/rust/blob/56694b04532cc0dec6e2f577135da3513e856923/compiler/rustc_passes/src/liveness.rs#L875-L896
Here a diverge point sits inside a conditional block, but this information is lost when calling propagate_through_expr, which then calls warn_about_unreachable.
A simple fix for this would be skipping the check for conditional neighbors. But that will actually bring out another false negative case:
#![allow(deprecated, invalid_value)]
enum Void {}
fn main() {
let b = false;
// should warn:
// any code following this `match` expression is unreachable, as all arms diverge
match b {
false => unsafe { std::mem::uninitialized::<Void>(); }
_ => unreachable!(),
}
println!();
}
I'm quite new to the compiler code, but this case seems difficult to fix because the exhaustiveness check takes place in a earlier(?) pass which doesn't have the complete type information.