1
Fork 0

support X = &*Y reborrows

This commit is contained in:
Niko Matsakis 2018-08-03 08:15:55 +02:00
parent 341a07c4c3
commit e79656c5b7
3 changed files with 47 additions and 16 deletions

View file

@ -13,6 +13,7 @@
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use rustc::mir::*; use rustc::mir::*;
use rustc::ty::{self, TyCtxt};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use rustc_data_structures::unify as ut; use rustc_data_structures::unify as ut;
@ -22,11 +23,13 @@ crate struct EscapingLocals {
} }
impl EscapingLocals { impl EscapingLocals {
crate fn compute(mir: &Mir<'_>) -> Self { crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
let mut visitor = GatherAssignedLocalsVisitor::new(); let mut visitor = GatherAssignedLocalsVisitor::new(tcx, mir);
visitor.visit_mir(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 /// 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 /// The MIR visitor gathering the union-find of the locals used in
/// assignments. /// assignments.
struct GatherAssignedLocalsVisitor { struct GatherAssignedLocalsVisitor<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>, unification_table: ut::UnificationTable<ut::InPlace<AssignedLocal>>,
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
mir: &'cx Mir<'tcx>,
} }
#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
@ -71,10 +76,12 @@ impl From<Local> for AssignedLocal {
} }
} }
impl GatherAssignedLocalsVisitor { impl GatherAssignedLocalsVisitor<'cx, 'gcx, 'tcx> {
fn new() -> Self { fn new(tcx: TyCtxt<'cx, 'gcx, 'tcx>, mir: &'cx Mir<'tcx>) -> Self {
Self { Self {
unification_table: ut::UnificationTable::new(), unification_table: ut::UnificationTable::new(),
tcx,
mir,
} }
} }
@ -82,6 +89,7 @@ impl GatherAssignedLocalsVisitor {
if let Some(lvalue) = lvalue { if let Some(lvalue) = lvalue {
if let Some(rvalue) = rvalue { if let Some(rvalue) = rvalue {
if lvalue != rvalue { if lvalue != rvalue {
debug!("EscapingLocals: union {:?} and {:?}", lvalue, rvalue);
self.unification_table self.unification_table
.union(AssignedLocal::from(lvalue), AssignedLocal::from(rvalue)); .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>) { fn visit_mir(&mut self, mir: &Mir<'tcx>) {
// We need as many union-find keys as there are locals // We need as many union-find keys as there are locals
for _ in 0..mir.local_decls.len() { for _ in 0..mir.local_decls.len() {
@ -139,6 +147,19 @@ impl<'tcx> Visitor<'tcx> for GatherAssignedLocalsVisitor {
match rvalue { match rvalue {
Rvalue::Use(op) => self.union_locals_if_needed(local, find_local_in_operand(op)), Rvalue::Use(op) => self.union_locals_if_needed(local, find_local_in_operand(op)),
Rvalue::Ref(_, _, place) => { 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)) self.union_locals_if_needed(local, find_local_in_place(place))
} }

View file

@ -18,7 +18,7 @@
use borrow_check::nll::escaping_locals::EscapingLocals; use borrow_check::nll::escaping_locals::EscapingLocals;
use rustc::mir::{Local, Mir}; use rustc::mir::{Local, Mir};
use rustc::ty::TypeFoldable; use rustc::ty::{TyCtxt, TypeFoldable};
use rustc_data_structures::indexed_vec::IndexVec; use rustc_data_structures::indexed_vec::IndexVec;
use util::liveness::LiveVariableMap; use util::liveness::LiveVariableMap;
@ -55,10 +55,12 @@ impl LiveVariableMap for NllLivenessMap {
impl NllLivenessMap { impl NllLivenessMap {
/// Iterates over the variables in Mir and assigns each Local whose type contains /// 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. /// regions a LocalWithRegion index. Returns a map for converting back and forth.
crate fn compute(mir: &Mir<'_>) -> Self { crate fn compute(tcx: TyCtxt<'_, '_, 'tcx>, mir: &Mir<'tcx>) -> Self {
let mut escaping_locals = EscapingLocals::compute(mir); let mut escaping_locals = EscapingLocals::compute(tcx, mir);
let mut to_local = IndexVec::default(); let mut to_local = IndexVec::default();
let mut escapes_into_return = 0;
let mut no_regions = 0;
let from_local: IndexVec<Local, Option<_>> = mir let from_local: IndexVec<Local, Option<_>> = mir
.local_decls .local_decls
.iter_enumerated() .iter_enumerated()
@ -70,14 +72,22 @@ impl NllLivenessMap {
// (e.g., `'static`) and hence liveness is not // (e.g., `'static`) and hence liveness is not
// needed. This is particularly important for big // needed. This is particularly important for big
// statics. // statics.
escapes_into_return += 1;
None None
} else if local_decl.ty.has_free_regions() { } 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 { } else {
no_regions += 1;
None None
} }
}).collect(); }).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 { Self {
from_local, from_local,
to_local, to_local,

View file

@ -109,7 +109,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(mir)); let elements = &Rc::new(RegionValueElements::new(mir));
// Run the MIR type-checker. // 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 liveness = LivenessResults::compute(mir, &liveness_map);
let (constraint_sets, universal_region_relations) = type_check::type_check( let (constraint_sets, universal_region_relations) = type_check::type_check(
infcx, infcx,
@ -206,6 +206,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
dump_mir_results( dump_mir_results(
infcx, infcx,
&liveness, &liveness,
&liveness_map,
MirSource::item(def_id), MirSource::item(def_id),
&mir, &mir,
&regioncx, &regioncx,
@ -222,6 +223,7 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
fn dump_mir_results<'a, 'gcx, 'tcx>( fn dump_mir_results<'a, 'gcx, 'tcx>(
infcx: &InferCtxt<'a, 'gcx, 'tcx>, infcx: &InferCtxt<'a, 'gcx, 'tcx>,
liveness: &LivenessResults<LocalWithRegion>, liveness: &LivenessResults<LocalWithRegion>,
liveness_map: &NllLivenessMap,
source: MirSource, source: MirSource,
mir: &Mir<'tcx>, mir: &Mir<'tcx>,
regioncx: &RegionInferenceContext, regioncx: &RegionInferenceContext,
@ -231,8 +233,6 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
return; return;
} }
let map = &NllLivenessMap::compute(mir);
let regular_liveness_per_location: FxHashMap<_, _> = mir let regular_liveness_per_location: FxHashMap<_, _> = mir
.basic_blocks() .basic_blocks()
.indices() .indices()
@ -240,7 +240,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
let mut results = vec![]; let mut results = vec![];
liveness liveness
.regular .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.push((location, local_set.clone()));
}); });
results results
@ -254,7 +254,7 @@ fn dump_mir_results<'a, 'gcx, 'tcx>(
let mut results = vec![]; let mut results = vec![];
liveness liveness
.drop .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.push((location, local_set.clone()));
}); });
results results