about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlqd <remy.rakic+github@gmail.com>2019-07-16 17:30:41 +0200
committerlqd <remy.rakic+github@gmail.com>2019-07-22 12:46:53 +0200
commit2f3e36f51a7055da3b55253edad7df594b0711d7 (patch)
tree32360e427c73ce31ea6a8651d2dedfc46ff2d769
parent823ab42e66cc966098030616e36e4aa7417dcf7f (diff)
downloadrust-2f3e36f51a7055da3b55253edad7df594b0711d7.tar.gz
rust-2f3e36f51a7055da3b55253edad7df594b0711d7.zip
Polonius: generate `killed` facts for assignments to projections
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs89
1 files changed, 75 insertions, 14 deletions
diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
index 25d0eaafc00..95c3299693b 100644
--- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs
+++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs
@@ -3,12 +3,15 @@ use crate::borrow_check::location::LocationTable;
 use crate::borrow_check::nll::ToRegionVid;
 use crate::borrow_check::nll::facts::AllFacts;
 use crate::borrow_check::nll::region_infer::values::LivenessValues;
+use crate::borrow_check::places_conflict;
 use rustc::infer::InferCtxt;
 use rustc::mir::visit::TyContext;
 use rustc::mir::visit::Visitor;
-use rustc::mir::{BasicBlock, BasicBlockData, Location, Body, Place, PlaceBase, Rvalue, TerminatorKind};
-use rustc::mir::{Local, SourceInfo, Statement, StatementKind, Terminator};
-use rustc::mir::UserTypeProjection;
+use rustc::mir::{
+    BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
+    ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
+    UserTypeProjection,
+};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
 use rustc::ty::subst::SubstsRef;
@@ -27,6 +30,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
         liveness_constraints,
         location_table,
         all_facts,
+        body,
     };
 
     for (bb, data) in body.basic_blocks().iter_enumerated() {
@@ -41,6 +45,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> {
     location_table: &'cg LocationTable,
     liveness_constraints: &'cg mut LivenessValues<RegionVid>,
     borrow_set: &'cg BorrowSet<'tcx>,
+    body: &'cg Body<'tcx>,
 }
 
 impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'tcx> {
@@ -212,17 +217,73 @@ impl<'cx, 'cg, 'tcx> ConstraintGeneration<'cx, 'cg, 'tcx> {
     /// as `killed`. For example, when assigning to a local, or on a call's return destination.
     fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) {
         if let Some(all_facts) = self.all_facts {
-            if let Place {
-                base: PlaceBase::Local(local),
-                projection: None,
-            } = place {
-                record_killed_borrows_for_local(
-                    all_facts,
-                    self.borrow_set,
-                    self.location_table,
-                    local,
-                    location,
-                );
+            // Depending on the `Place` we're killing:
+            // - if it's a local, or a single deref of a local,
+            //   we kill all the borrows on the local.
+            // - if it's a deeper projection, we have to filter which
+            //   of the borrows are killed: the ones whose `borrowed_place`
+            //   conflicts with the `place`.
+            match place {
+                Place {
+                    base: PlaceBase::Local(local),
+                    projection: None,
+                } |
+                Place {
+                    base: PlaceBase::Local(local),
+                    projection: Some(box Projection {
+                        base: None,
+                        elem: ProjectionElem::Deref,
+                    }),
+                } => {
+                    debug!(
+                        "Recording `killed` facts for borrows of local={:?} at location={:?}",
+                        local, location
+                    );
+
+                    record_killed_borrows_for_local(
+                        all_facts,
+                        self.borrow_set,
+                        self.location_table,
+                        local,
+                        location,
+                    );
+                }
+
+                Place {
+                    base: PlaceBase::Static(_),
+                    ..
+                } => {
+                    // Ignore kills of static or static mut variables.
+                }
+
+                Place {
+                    base: PlaceBase::Local(local),
+                    projection: Some(_),
+                } => {
+                    // Kill conflicting borrows of the innermost local.
+                    debug!(
+                        "Recording `killed` facts for borrows of \
+                            innermost projected local={:?} at location={:?}",
+                        local, location
+                    );
+
+                    if let Some(borrow_indices) = self.borrow_set.local_map.get(local) {
+                        for &borrow_index in borrow_indices {
+                            let places_conflict = places_conflict::places_conflict(
+                                self.infcx.tcx,
+                                self.body,
+                                &self.borrow_set.borrows[borrow_index].borrowed_place,
+                                place,
+                                places_conflict::PlaceConflictBias::NoOverlap,
+                            );
+
+                            if places_conflict {
+                                let location_index = self.location_table.mid_index(location);
+                                all_facts.killed.push((borrow_index, location_index));
+                            }
+                        }
+                    }
+                }
             }
         }
     }