diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2018-08-03 08:15:55 +0200 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2018-08-03 08:15:55 +0200 |
| commit | e79656c5b7f58d592c9ed3544009c096bf81cad8 (patch) | |
| tree | ec764a76d61311d25499c15fe1b942c50dc3ecbd | |
| parent | 341a07c4c3adbc96b4a7fd6532ed34bfeb22d553 (diff) | |
| download | rust-e79656c5b7f58d592c9ed3544009c096bf81cad8.tar.gz rust-e79656c5b7f58d592c9ed3544009c096bf81cad8.zip | |
support `X = &*Y` reborrows
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/escaping_locals.rs | 35 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/liveness_map.rs | 18 | ||||
| -rw-r--r-- | src/librustc_mir/borrow_check/nll/mod.rs | 10 |
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, ®ioncx, @@ -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 |
