diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 092c34da2ba46..206eb9126f54b 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -861,20 +861,46 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } + /// Starting at a target unreachable block, find some user code to lint as unreachable + fn find_unreachable_code_from( + bb: BasicBlock, + bbs: &IndexVec>, + ) -> Option<(SourceInfo, &'static str)> { + let bb = &bbs[bb]; + for stmt in &bb.statements { + match &stmt.kind { + // Ignore the implicit `()` return place assignment for unit functions/blocks + StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(const_)))) + if const_.ty().is_unit() => + { + continue; + } + StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => { + continue; + } + StatementKind::FakeRead(..) => return Some((stmt.source_info, "definition")), + _ => return Some((stmt.source_info, "expression")), + } + } + + let term = bb.terminator(); + match term.kind { + // No user code in this bb, and our goto target may be reachable via other paths + TerminatorKind::Goto { .. } | TerminatorKind::Return => None, + _ => Some((term.source_info, "expression")), + } + } + for (target_bb, orig_ty, orig_span) in lints { if orig_span.in_external_macro(self.tcx.sess.source_map()) { continue; } - let target_bb = &self.cfg.basic_blocks[target_bb]; - let (target_loc, descr) = target_bb - .statements - .iter() - .find_map(|stmt| match stmt.kind { - StatementKind::StorageLive(_) | StatementKind::StorageDead(_) => None, - StatementKind::FakeRead(..) => Some((stmt.source_info, "definition")), - _ => Some((stmt.source_info, "expression")), - }) - .unwrap_or_else(|| (target_bb.terminator().source_info, "expression")); + + let Some((target_loc, descr)) = + find_unreachable_code_from(target_bb, &self.cfg.basic_blocks) + else { + continue; + }; let lint_root = self.source_scopes[target_loc.scope] .local_data .as_ref() diff --git a/tests/ui/uninhabited/unreachable.rs b/tests/ui/uninhabited/unreachable.rs new file mode 100644 index 0000000000000..a7298d0dcd341 --- /dev/null +++ b/tests/ui/uninhabited/unreachable.rs @@ -0,0 +1,26 @@ +//! Test that a diverging function as the final expression in a block does not +//! raise an 'unreachable code' lint. + +//@ check-pass +#![deny(unreachable_code)] + +enum Never {} + +fn make_never() -> Never { + loop {} +} + +fn func() { + make_never(); +} + +fn block() { + { + make_never(); + } +} + +fn main() { + func(); + block(); +} diff --git a/tests/ui/uninhabited/void-branch.rs b/tests/ui/uninhabited/void-branch.rs index e000f946dc156..b9e1d70382910 100644 --- a/tests/ui/uninhabited/void-branch.rs +++ b/tests/ui/uninhabited/void-branch.rs @@ -6,8 +6,9 @@ enum Void {} fn with_void() { if false { unsafe { - //~^ ERROR unreachable expression std::mem::uninitialized::(); + println!(); + //~^ ERROR unreachable expression } } @@ -20,8 +21,9 @@ fn infallible() -> std::convert::Infallible { fn with_infallible() { if false { - //~^ ERROR unreachable expression infallible(); + println!() + //~^ ERROR unreachable expression } println!() diff --git a/tests/ui/uninhabited/void-branch.stderr b/tests/ui/uninhabited/void-branch.stderr index 7bbcb763ddf7c..ee5efb94ed214 100644 --- a/tests/ui/uninhabited/void-branch.stderr +++ b/tests/ui/uninhabited/void-branch.stderr @@ -1,15 +1,13 @@ error: unreachable expression - --> $DIR/void-branch.rs:8:9 + --> $DIR/void-branch.rs:10:13 | -LL | / unsafe { -LL | | -LL | | std::mem::uninitialized::(); - | | --------------------------------- any code following this expression is unreachable -LL | | } - | |_________^ unreachable expression +LL | std::mem::uninitialized::(); + | --------------------------------- any code following this expression is unreachable +LL | println!(); + | ^^^^^^^^^^ unreachable expression | note: this expression has type `Void`, which is uninhabited - --> $DIR/void-branch.rs:10:13 + --> $DIR/void-branch.rs:9:13 | LL | std::mem::uninitialized::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -18,23 +16,22 @@ note: the lint level is defined here | LL | #![deny(unreachable_code)] | ^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable expression - --> $DIR/void-branch.rs:22:14 + --> $DIR/void-branch.rs:25:9 | -LL | if false { - | ______________^ -LL | | -LL | | infallible(); - | | ------------ any code following this expression is unreachable -LL | | } - | |_____^ unreachable expression +LL | infallible(); + | ------------ any code following this expression is unreachable +LL | println!() + | ^^^^^^^^^^ unreachable expression | note: this expression has type `Infallible`, which is uninhabited --> $DIR/void-branch.rs:24:9 | LL | infallible(); | ^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::format_args` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors