diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 3d3275a6b1714..115f36c149b64 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -61,6 +61,7 @@ mod location; crate mod place_ext; mod prefixes; mod path_utils; +mod used_muts; pub(crate) mod nll; @@ -281,20 +282,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>( .filter(|&local| !mbcx.mir.local_decls[*local].is_user_variable.is_some()) .cloned() .collect(); - - for local in temporary_used_locals { - for location in mbcx.mir.find_assignments(local) { - for moi in &mbcx.move_data.loc_map[location] { - let mpi = &mbcx.move_data.moves[*moi].path; - let path = &mbcx.move_data.move_paths[*mpi]; - debug!("assignment of {:?} to {:?}, adding {:?} to used mutable set", - path.place, local, path.place); - if let Place::Local(user_local) = path.place { - mbcx.used_mut.insert(user_local); - } - } - } - } + mbcx.gather_used_muts(temporary_used_locals); debug!("mbcx.used_mut: {:?}", mbcx.used_mut); diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/src/librustc_mir/borrow_check/used_muts.rs new file mode 100644 index 0000000000000..dbe19bc47859f --- /dev/null +++ b/src/librustc_mir/borrow_check/used_muts.rs @@ -0,0 +1,64 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::mir::visit::{PlaceContext, Visitor}; +use rustc::mir::{Local, Location, Place}; + +use rustc_data_structures::fx::FxHashSet; + +use borrow_check::MirBorrowckCtxt; +use util::collect_writes::is_place_assignment; + +impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { + /// Walks the MIR looking for assignments to a set of locals, as part of the unused mutable + /// local variables lint, to update the context's `used_mut` in a single walk. + crate fn gather_used_muts(&mut self, locals: FxHashSet) { + let mut visitor = GatherUsedMutsVisitor { + needles: locals, + mbcx: self, + }; + visitor.visit_mir(visitor.mbcx.mir); + } +} + +/// MIR visitor gathering the assignments to a set of locals, in a single walk. +/// 'visit = the duration of the MIR walk +struct GatherUsedMutsVisitor<'visit, 'cx: 'visit, 'gcx: 'tcx, 'tcx: 'cx> { + needles: FxHashSet, + mbcx: &'visit mut MirBorrowckCtxt<'cx, 'gcx, 'tcx>, +} + +impl<'visit, 'cx, 'gcx, 'tcx> Visitor<'tcx> for GatherUsedMutsVisitor<'visit, 'cx, 'gcx, 'tcx> { + fn visit_local( + &mut self, + local: &Local, + place_context: PlaceContext<'tcx>, + location: Location, + ) { + if !self.needles.contains(local) { + return; + } + + if is_place_assignment(&place_context) { + // Propagate the Local assigned at this Location as a used mutable local variable + for moi in &self.mbcx.move_data.loc_map[location] { + let mpi = &self.mbcx.move_data.moves[*moi].path; + let path = &self.mbcx.move_data.move_paths[*mpi]; + debug!( + "assignment of {:?} to {:?}, adding {:?} to used mutable set", + path.place, local, path.place + ); + if let Place::Local(user_local) = path.place { + self.mbcx.used_mut.insert(user_local); + } + } + } + } +} diff --git a/src/librustc_mir/util/collect_writes.rs b/src/librustc_mir/util/collect_writes.rs index f04f9233447c3..23f753f8569bb 100644 --- a/src/librustc_mir/util/collect_writes.rs +++ b/src/librustc_mir/util/collect_writes.rs @@ -43,25 +43,24 @@ impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { return; } - match place_context { - PlaceContext::Store | PlaceContext::Call => { - self.locations.push(location); - } - PlaceContext::AsmOutput | - PlaceContext::Drop | - PlaceContext::Inspect | - PlaceContext::Borrow { .. } | - PlaceContext::Projection(..) | - PlaceContext::Copy | - PlaceContext::Move | - PlaceContext::StorageLive | - PlaceContext::StorageDead | - PlaceContext::Validate => { - // TO-DO - // self.super_local(local) - } + if is_place_assignment(&place_context) { + self.locations.push(location); } } - // TO-DO - // fn super_local() +} + +/// Returns true if this place context represents an assignment statement +crate fn is_place_assignment(place_context: &PlaceContext) -> bool { + match *place_context { + PlaceContext::Store | PlaceContext::Call | PlaceContext::AsmOutput => true, + PlaceContext::Drop + | PlaceContext::Inspect + | PlaceContext::Borrow { .. } + | PlaceContext::Projection(..) + | PlaceContext::Copy + | PlaceContext::Move + | PlaceContext::StorageLive + | PlaceContext::StorageDead + | PlaceContext::Validate => false, + } }