diff options
| author | David Wood <david@davidtw.co> | 2018-12-17 13:11:33 +0100 |
|---|---|---|
| committer | David Wood <david@davidtw.co> | 2018-12-17 14:49:52 +0100 |
| commit | db635fc5664c0a19cdb4063545ca2d2b297f0212 (patch) | |
| tree | 53610cb23ec6723c00757e9f41b5c4b09c9e2d80 /src/librustc_mir/dataflow/impls | |
| parent | 1149c58bb8020338ea5f3065af0a3342d42a31fa (diff) | |
| download | rust-db635fc5664c0a19cdb4063545ca2d2b297f0212.tar.gz rust-db635fc5664c0a19cdb4063545ca2d2b297f0212.zip | |
Kill borrows from a projection after assignment.
This commit extends previous work to kill borrows from a local after assignment into that local to kill borrows from a projection after assignment into a prefix of that place.
Diffstat (limited to 'src/librustc_mir/dataflow/impls')
| -rw-r--r-- | src/librustc_mir/dataflow/impls/borrows.rs | 77 |
1 files changed, 54 insertions, 23 deletions
diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index 3a9e4fc9e4a..532143af6d3 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -11,7 +11,6 @@ use borrow_check::borrow_set::{BorrowSet, BorrowData}; use borrow_check::place_ext::PlaceExt; -use rustc; use rustc::mir::{self, Location, Place, Mir}; use rustc::ty::TyCtxt; use rustc::ty::RegionVid; @@ -24,6 +23,7 @@ use dataflow::{BitDenotation, BlockSets, InitialFlow}; pub use dataflow::indexes::BorrowIndex; use borrow_check::nll::region_infer::RegionInferenceContext; use borrow_check::nll::ToRegionVid; +use borrow_check::places_conflict; use std::rc::Rc; @@ -191,12 +191,54 @@ impl<'a, 'gcx, 'tcx> Borrows<'a, 'gcx, 'tcx> { } } - fn kill_borrows_on_local(&self, - sets: &mut BlockSets<BorrowIndex>, - local: &rustc::mir::Local) - { - if let Some(borrow_indexes) = self.borrow_set.local_map.get(local) { - sets.kill_all(borrow_indexes); + /// Kill any borrows that conflict with `place`. + fn kill_borrows_on_place( + &self, + sets: &mut BlockSets<BorrowIndex>, + location: Location, + place: &Place<'tcx> + ) { + debug!("kill_borrows_on_place: location={:?} place={:?}", location, place); + // Handle the `Place::Local(..)` case first and exit early. + if let Place::Local(local) = place { + if let Some(borrow_indexes) = self.borrow_set.local_map.get(&local) { + debug!( + "kill_borrows_on_place: local={:?} borrow_indexes={:?}", + local, borrow_indexes, + ); + sets.kill_all(borrow_indexes); + return; + } + } + + // Otherwise, look at all borrows that are live and if they conflict with the assignment + // into our place then we can kill them. + let mut borrows = sets.on_entry.clone(); + let _ = borrows.union(sets.gen_set); + for borrow_index in borrows.iter() { + let borrow_data = &self.borrows()[borrow_index]; + debug!( + "kill_borrows_on_place: borrow_index={:?} borrow_data={:?}", + borrow_index, borrow_data, + ); + + // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given + // pair of array indices are unequal, so that when `places_conflict` returns true, we + // will be assured that two places being compared definitely denotes the same sets of + // locations. + if places_conflict::places_conflict( + self.tcx, + self.mir, + place, + &borrow_data.borrowed_place, + places_conflict::PlaceConflictBias::NoOverlap, + ) { + debug!( + "kill_borrows_on_place: (kill) place={:?} borrow_index={:?} borrow_data={:?}", + place, borrow_index, borrow_data, + ); + sets.kill(borrow_index); + } } } } @@ -222,7 +264,7 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { } fn statement_effect(&self, sets: &mut BlockSets<BorrowIndex>, location: Location) { - debug!("Borrows::statement_effect sets: {:?} location: {:?}", sets, location); + debug!("Borrows::statement_effect: sets={:?} location={:?}", sets, location); let block = &self.mir.basic_blocks().get(location.block).unwrap_or_else(|| { panic!("could not find block at location {:?}", location); @@ -231,21 +273,17 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { panic!("could not find statement at location {:?}"); }); + debug!("Borrows::statement_effect: stmt={:?}", stmt); match stmt.kind { mir::StatementKind::Assign(ref lhs, ref rhs) => { // Make sure there are no remaining borrows for variables // that are assigned over. - if let Place::Local(ref local) = *lhs { - // FIXME: Handle the case in which we're assigning over - // a projection (`foo.bar`). - self.kill_borrows_on_local(sets, local); - } + self.kill_borrows_on_place(sets, location, lhs); // NOTE: if/when the Assign case is revised to inspect // the assigned_place here, make sure to also // re-consider the current implementations of the // propagate_call_return method. - if let mir::Rvalue::Ref(_, _, ref place) = **rhs { if place.ignore_borrow( self.tcx, @@ -279,19 +317,13 @@ impl<'a, 'gcx, 'tcx> BitDenotation for Borrows<'a, 'gcx, 'tcx> { mir::StatementKind::StorageDead(local) => { // Make sure there are no remaining borrows for locals that // are gone out of scope. - self.kill_borrows_on_local(sets, &local) + self.kill_borrows_on_place(sets, location, &Place::Local(local)); } mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { for (output, kind) in outputs.iter().zip(&asm.outputs) { if !kind.is_indirect && !kind.is_rw { - // Make sure there are no remaining borrows for direct - // output variables. - if let Place::Local(ref local) = *output { - // FIXME: Handle the case in which we're assigning over - // a projection (`foo.bar`). - self.kill_borrows_on_local(sets, local); - } + self.kill_borrows_on_place(sets, location, output); } } } @@ -342,4 +374,3 @@ impl<'a, 'gcx, 'tcx> InitialFlow for Borrows<'a, 'gcx, 'tcx> { false // bottom = nothing is reserved or activated yet } } - |
