about summary refs log tree commit diff
path: root/src/librustc_mir/dataflow/impls
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2018-12-17 13:11:33 +0100
committerDavid Wood <david@davidtw.co>2018-12-17 14:49:52 +0100
commitdb635fc5664c0a19cdb4063545ca2d2b297f0212 (patch)
tree53610cb23ec6723c00757e9f41b5c4b09c9e2d80 /src/librustc_mir/dataflow/impls
parent1149c58bb8020338ea5f3065af0a3342d42a31fa (diff)
downloadrust-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.rs77
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
     }
 }
-