Skip unused variables warning for unreachable code

(cherry picked from commit 2c6b1d3430)
This commit is contained in:
yukang 2025-11-19 21:53:26 +08:00 committed by Josh Stone
parent 807097675a
commit 4bd154fa71
5 changed files with 91 additions and 11 deletions

View file

@ -880,6 +880,33 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
dead_captures
}
/// Check if a local is referenced in any reachable basic block.
/// Variables in unreachable code (e.g., after `todo!()`) should not trigger unused warnings.
fn is_local_in_reachable_code(&self, local: Local) -> bool {
struct LocalVisitor {
target_local: Local,
found: bool,
}
impl<'tcx> Visitor<'tcx> for LocalVisitor {
fn visit_local(&mut self, local: Local, _context: PlaceContext, _location: Location) {
if local == self.target_local {
self.found = true;
}
}
}
let mut visitor = LocalVisitor { target_local: local, found: false };
for (bb, bb_data) in traversal::postorder(self.body) {
visitor.visit_basic_block_data(bb, bb_data);
if visitor.found {
return true;
}
}
false
}
/// Report fully unused locals, and forget the corresponding assignments.
fn report_fully_unused(&mut self) {
let tcx = self.tcx;
@ -933,6 +960,10 @@ impl<'a, 'tcx> AssignmentResult<'a, 'tcx> {
let statements = &mut self.assignments[index];
if statements.is_empty() {
if !self.is_local_in_reachable_code(local) {
continue;
}
let sugg = if from_macro {
errors::UnusedVariableSugg::NoSugg { span: def_span, name }
} else {

View file

@ -0,0 +1,46 @@
//@ check-pass
#![allow(unreachable_code)]
#![allow(dead_code)]
#![warn(unused_variables)]
fn after_todo() {
todo!("not implemented");
// This should not warn - the code is unreachable
let a = 1;
if a < 2 {
eprintln!("a: {}", a);
}
}
fn after_panic() {
panic!("oops");
// This should not warn - the code is unreachable
let b = 2;
println!("{}", b);
}
fn after_unimplemented() {
unimplemented!();
// This should not warn - the code is unreachable
let c = 3;
println!("{}", c);
}
fn after_unreachable() {
unsafe { std::hint::unreachable_unchecked() }
// This should not warn - the code is unreachable
let d = 4;
println!("{}", d);
}
fn reachable_unused() {
// This SHOULD warn - the code is reachable
let e = 5; //~ WARN unused variable: `e`
}
fn main() {}

View file

@ -0,0 +1,14 @@
warning: unused variable: `e`
--> $DIR/unused-var-in-unreachable-code.rs:43:9
|
LL | let e = 5;
| ^ help: if this is intentional, prefix it with an underscore: `_e`
|
note: the lint level is defined here
--> $DIR/unused-var-in-unreachable-code.rs:5:9
|
LL | #![warn(unused_variables)]
| ^^^^^^^^^^^^^^^^
warning: 1 warning emitted

View file

@ -4,7 +4,6 @@ fn main() {
return ();
let x = ();
//~^ WARN unused variable: `x`
x
}

View file

@ -1,10 +0,0 @@
warning: unused variable: `x`
--> $DIR/early-return-with-unreachable-code-24353.rs:6:9
|
LL | let x = ();
| ^ help: if this is intentional, prefix it with an underscore: `_x`
|
= note: `#[warn(unused_variables)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emitted