about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-08-03 08:15:55 +0200
committerNiko Matsakis <niko@alum.mit.edu>2018-08-03 08:15:55 +0200
commite79656c5b7f58d592c9ed3544009c096bf81cad8 (patch)
treeec764a76d61311d25499c15fe1b942c50dc3ecbd
parent341a07c4c3adbc96b4a7fd6532ed34bfeb22d553 (diff)
downloadrust-e79656c5b7f58d592c9ed3544009c096bf81cad8.tar.gz
rust-e79656c5b7f58d592c9ed3544009c096bf81cad8.zip
support `X = &*Y` reborrows
-rw-r--r--src/librustc_mir/borrow_check/nll/escaping_locals.rs35
-rw-r--r--src/librustc_mir/borrow_check/nll/liveness_map.rs18
-rw-r--r--src/librustc_mir/borrow_check/nll/mod.rs10
3 files changed, 47 insertions, 16 deletions
diff --git a/src/librustc_mir/borrow_check/nll/escaping_locals.rs b/src/librustc_mir/borrow_check/nll/escaping_locals.rs
index da9cc10853e..d12ce5b4511 100644
--- a/src/librustc_mir/borrow_check/nll/escaping_locals.rs
+++ b/src/librustc_mir/borrow_check/nll/escaping_locals.rs
@@ -13,6 +13,7 @@
 
 use rustc::mir::visit::Visitor;
 use rustc::mir::*;
+use rustc::ty::{self, TyCtxt};
 
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::unify as ut;
@@ -22,11 +23,13 @@ crate struct EscapingLocals {
 }
 
 impl EscapingLocals {
-    crate fn compute(mir: &Mir<'_>) -> Self {
-        let mut visitor = GatherAssignedLocalsVisitor::new();
+    crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
+        let mut visitor = GatherAssignedLocalsVisitor::new(tcx, mir);
         visitor.visit_mir(mir);
 
-        EscapingLocals { unification_table: visitor.unification_table }
+        EscapingLocals {
+            unification_table: visitor.unification_table,
+        }
     }
 
     /// True if `local` is known to escape into static
@@ -40,8 +43,10 @@ impl EscapingLocals {
 
 /// The MIR visitor gathering the union-find of the locals used in
 /// assignments.
-struct GatherAssignedLocalsVisitor {
+struct GatherAssignedLocalsVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
     unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>,
+    tcx: TyCtxt<'cx, 'gcx, 'tcx>,
+    mir: &'cx Mir<'tcx>,
 }
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@@ -71,10 +76,12 @@ impl From<Local> for AssignedLocal {
     }
 }
 
-impl GatherAssignedLocalsVisitor {
-    fn new() -> Self {
+impl GatherAssignedLocalsVisitor<'cx, 'gcx, 'tcx> {
+    fn new(tcx: TyCtxt<'cx, 'gcx, 'tcx>, mir: &'cx Mir<'tcx>) -> Self {
         Self {
             unification_table: ut::UnificationTable::new(),
+            tcx,
+            mir,
         }
     }
 
@@ -82,6 +89,7 @@ impl GatherAssignedLocalsVisitor {
         if let Some(lvalue) = lvalue {
             if let Some(rvalue) = rvalue {
                 if lvalue != rvalue {
+                    debug!("EscapingLocals: union {:?} and {:?}", lvalue, rvalue);
                     self.unification_table
                         .union(AssignedLocal::from(lvalue), AssignedLocal::from(rvalue));
                 }
@@ -115,7 +123,7 @@ fn find_local_in_operand(op: &Operand) -> Option<Local> {
     }
 }
 
-impl<'tcx> Visitor<'tcx> for GatherAssignedLocalsVisitor {
+impl Visitor<'tcx> for GatherAssignedLocalsVisitor<'_, '_, 'tcx> {
     fn visit_mir(&mut self, mir: &Mir<'tcx>) {
         // We need as many union-find keys as there are locals
         for _ in 0..mir.local_decls.len() {
@@ -139,6 +147,19 @@ impl<'tcx> Visitor<'tcx> for GatherAssignedLocalsVisitor {
         match rvalue {
             Rvalue::Use(op) => self.union_locals_if_needed(local, find_local_in_operand(op)),
             Rvalue::Ref(_, _, place) => {
+                // Special case: if you have `X = &*Y` where `Y` is a
+                // reference, then the outlives relationships should
+                // ensure that all regions in `Y` are constrained by
+                // regions in `X`.
+                if let Place::Projection(proj) = place {
+                    if let ProjectionElem::Deref = proj.elem {
+                        if let ty::TyRef(..) = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx).sty
+                        {
+                            self.union_locals_if_needed(local, find_local_in_place(&proj.base));
+                        }
+                    }
+                }
+
                 self.union_locals_if_needed(local, find_local_in_place(place))
             }
 
diff --git a/src/librustc_mir/borrow_check/nll/liveness_map.rs b/src/librustc_mir/borrow_check/nll/liveness_map.rs
index be29744ab13..771be05422c 100644
--- a/src/librustc_mir/borrow_check/nll/liveness_map.rs
+++ b/src/librustc_mir/borrow_check/nll/liveness_map.rs
@@ -18,7 +18,7 @@
 
 use borrow_check::nll::escaping_locals::EscapingLocals;
 use rustc::mir::{Local, Mir};
-use rustc::ty::TypeFoldable;
+use rustc::ty::{TyCtxt, TypeFoldable};
 use rustc_data_structures::indexed_vec::IndexVec;
 use util::liveness::LiveVariableMap;
 
@@ -55,10 +55,12 @@ impl LiveVariableMap for NllLivenessMap {
 impl NllLivenessMap {
     /// Iterates over the variables in Mir and assigns each Local whose type contains
     /// regions a LocalWithRegion index. Returns a map for converting back and forth.
-    crate fn compute(mir: &Mir<'_>) -> Self {
-        let mut escaping_locals = EscapingLocals::compute(mir);
+    crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
+        let mut escaping_locals = EscapingLocals::compute(tcx, mir);
 
         let mut to_local = IndexVec::default();
+        let mut escapes_into_return = 0;
+        let mut no_regions = 0;
         let from_local: IndexVec<Local, Option<_>> = mir
             .local_decls
             .iter_enumerated()
@@ -70,14 +72,22 @@ impl NllLivenessMap {
                     // (e.g., `'static`) and hence liveness is not
                     // needed. This is particularly important for big
                     // statics.
+                    escapes_into_return += 1;
                     None
                 } else if local_decl.ty.has_free_regions() {
-                    Some(to_local.push(local))
+                    let l = to_local.push(local);
+                    debug!("liveness_map: {:?} = {:?}", local, l);
+                    Some(l)
                 } else {
+                    no_regions += 1;
                     None
                 }
             }).collect();
 
+        debug!("liveness_map: {} variables need liveness", to_local.len());
+        debug!("liveness_map: {} escapes into return", escapes_into_return);
+        debug!("liveness_map: {} no regions", no_regions);
+
         Self {
             from_local,
             to_local,
diff --git a/src/librustc_mir/borrow_check/nll/mod.rs b/src/librustc_mir/borrow_check/nll/mod.rs
index d991908b699..cc070a37ba1 100644
--- a/src/librustc_mir/borrow_check/nll/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/mod.rs
@@ -109,7 +109,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     let elements = &Rc::new(RegionValueElements::new(mir));
 
     // Run the MIR type-checker.
-    let liveness_map = NllLivenessMap::compute(&mir);
+    let liveness_map = NllLivenessMap::compute(infcx.tcx, &mir);
     let liveness = LivenessResults::compute(mir, &liveness_map);
     let (constraint_sets, universal_region_relations) = type_check::type_check(
         infcx,
@@ -206,6 +206,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
     dump_mir_results(
         infcx,
         &liveness,
+        &liveness_map,
         MirSource::item(def_id),
         &mir,
         &regioncx,
@@ -222,6 +223,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
 fn dump_mir_results<'a, 'gcx, 'tcx>(
     infcx: &InferCtxt<'a, 'gcx, 'tcx>,
     liveness: &LivenessResults<LocalWithRegion>,
+    liveness_map: &NllLivenessMap,
     source: MirSource,
     mir: &Mir<'tcx>,
     regioncx: &RegionInferenceContext,
@@ -231,8 +233,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
         return;
     }
 
-    let map = &NllLivenessMap::compute(mir);
-
     let regular_liveness_per_location: FxHashMap<_, _> = mir
         .basic_blocks()
         .indices()
@@ -240,7 +240,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
             let mut results = vec![];
             liveness
                 .regular
-                .simulate_block(&mir, bb, map, |location, local_set| {
+                .simulate_block(&mir, bb, liveness_map, |location, local_set| {
                     results.push((location, local_set.clone()));
                 });
             results
@@ -254,7 +254,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
             let mut results = vec![];
             liveness
                 .drop
-                .simulate_block(&mir, bb, map, |location, local_set| {
+                .simulate_block(&mir, bb, liveness_map, |location, local_set| {
                     results.push((location, local_set.clone()));
                 });
             results