compiler/rustc_borrowck/src/used_muts.rs RUST 110 lines View on github.com → Search inside
1use rustc_data_structures::fx::FxIndexSet;2use rustc_middle::mir::visit::{PlaceContext, Visitor};3use rustc_middle::mir::{4    Local, Location, Place, Statement, StatementKind, Terminator, TerminatorKind,5};6use tracing::debug;78use crate::MirBorrowckCtxt;910impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {11    /// Walks the MIR adding to the set of `used_mut` locals that will be ignored for the purposes12    /// of the `unused_mut` lint.13    ///14    /// `temporary_used_locals` should contain locals that were found to be temporary, mutable and15    ///  used from borrow checking. This function looks for assignments into these locals from16    ///  user-declared locals and adds those user-defined locals to the `used_mut` set. This can17    ///  occur due to a rare case involving upvars in closures.18    ///19    /// `never_initialized_mut_locals` should contain the set of user-declared mutable locals20    ///  (not arguments) that have not already been marked as being used.21    ///  This function then looks for assignments from statements or the terminator into the locals22    ///  from this set and removes them from the set. This leaves only those locals that have not23    ///  been assigned to - this set is used as a proxy for locals that were not initialized due to24    ///  unreachable code. These locals are then considered "used" to silence the lint for them.25    ///  See #55344 for context.26    pub(crate) fn gather_used_muts(27        &mut self,28        temporary_used_locals: FxIndexSet<Local>,29        mut never_initialized_mut_locals: FxIndexSet<Local>,30    ) {31        {32            let mut visitor = GatherUsedMutsVisitor {33                temporary_used_locals,34                never_initialized_mut_locals: &mut never_initialized_mut_locals,35                mbcx: self,36            };37            visitor.visit_body(visitor.mbcx.body);38        }3940        // Take the union of the existed `used_mut` set with those variables we've found were41        // never initialized.42        debug!("gather_used_muts: never_initialized_mut_locals={:?}", never_initialized_mut_locals);43        self.used_mut = self.used_mut.union(&never_initialized_mut_locals).cloned().collect();44    }45}4647/// MIR visitor for collecting used mutable variables.48/// The 'visit lifetime represents the duration of the MIR walk.49struct GatherUsedMutsVisitor<'a, 'b, 'infcx, 'tcx> {50    temporary_used_locals: FxIndexSet<Local>,51    never_initialized_mut_locals: &'a mut FxIndexSet<Local>,52    mbcx: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,53}5455impl GatherUsedMutsVisitor<'_, '_, '_, '_> {56    fn remove_never_initialized_mut_locals(&mut self, into: Place<'_>) {57        // Remove any locals that we found were initialized from the58        // `never_initialized_mut_locals` set. At the end, the only remaining locals will59        // be those that were never initialized - we will consider those as being used as60        // they will either have been removed by unreachable code optimizations; or linted61        // as unused variables.62        // FIXME(#120456) - is `swap_remove` correct?63        self.never_initialized_mut_locals.swap_remove(&into.local);64    }65}6667impl<'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'_, '_, '_, 'tcx> {68    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {69        debug!("visit_terminator: terminator={:?}", terminator);70        match &terminator.kind {71            TerminatorKind::Call { destination, .. } => {72                self.remove_never_initialized_mut_locals(*destination);73            }74            _ => {}75        }7677        self.super_terminator(terminator, location);78    }7980    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {81        if let StatementKind::Assign(box (into, _)) = &statement.kind {82            debug!(83                "visit_statement: statement={:?} local={:?} \84                    never_initialized_mut_locals={:?}",85                statement, into.local, self.never_initialized_mut_locals86            );87            self.remove_never_initialized_mut_locals(*into);88        }8990        self.super_statement(statement, location);91    }9293    fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) {94        if place_context.is_place_assignment() && self.temporary_used_locals.contains(&local) {95            // Propagate the Local assigned at this Location as a used mutable local variable96            for moi in &self.mbcx.move_data.loc_map[location] {97                let mpi = &self.mbcx.move_data.moves[*moi].path;98                let path = &self.mbcx.move_data.move_paths[*mpi];99                debug!(100                    "assignment of {:?} to {:?}, adding {:?} to used mutable set",101                    path.place, local, path.place102                );103                if let Some(user_local) = path.place.as_local() {104                    self.mbcx.used_mut.insert(user_local);105                }106            }107        }108    }109}

Code quality findings 4

Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
for moi in &self.mbcx.move_data.loc_map[location] {
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let mpi = &self.mbcx.move_data.moves[*moi].path;
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
let path = &self.mbcx.move_data.move_paths[*mpi];
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match &terminator.kind {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.