Polonius: generate killed facts for assignments to projections

This commit is contained in:
lqd 2019-07-16 17:30:41 +02:00
parent 823ab42e66
commit 2f3e36f51a

View File

@ -3,12 +3,15 @@ use crate::borrow_check::location::LocationTable;
use crate::borrow_check::nll::ToRegionVid; use crate::borrow_check::nll::ToRegionVid;
use crate::borrow_check::nll::facts::AllFacts; use crate::borrow_check::nll::facts::AllFacts;
use crate::borrow_check::nll::region_infer::values::LivenessValues; use crate::borrow_check::nll::region_infer::values::LivenessValues;
use crate::borrow_check::places_conflict;
use rustc::infer::InferCtxt; use rustc::infer::InferCtxt;
use rustc::mir::visit::TyContext; use rustc::mir::visit::TyContext;
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, BasicBlockData, Location, Body, Place, PlaceBase, Rvalue, TerminatorKind}; use rustc::mir::{
use rustc::mir::{Local, SourceInfo, Statement, StatementKind, Terminator}; BasicBlock, BasicBlockData, Body, Local, Location, Place, PlaceBase, Projection,
use rustc::mir::UserTypeProjection; ProjectionElem, Rvalue, SourceInfo, Statement, StatementKind, Terminator, TerminatorKind,
UserTypeProjection,
};
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty}; use rustc::ty::{self, ClosureSubsts, GeneratorSubsts, RegionVid, Ty};
use rustc::ty::subst::SubstsRef; use rustc::ty::subst::SubstsRef;
@ -27,6 +30,7 @@ pub(super) fn generate_constraints<'cx, 'tcx>(
liveness_constraints, liveness_constraints,
location_table, location_table,
all_facts, all_facts,
body,
}; };
for (bb, data) in body.basic_blocks().iter_enumerated() { for (bb, data) in body.basic_blocks().iter_enumerated() {
@ -41,6 +45,7 @@ struct ConstraintGeneration<'cg, 'cx, 'tcx> {
location_table: &'cg LocationTable, location_table: &'cg LocationTable,
liveness_constraints: &'cg mut LivenessValues<RegionVid>, liveness_constraints: &'cg mut LivenessValues<RegionVid>,
borrow_set: &'cg BorrowSet<'tcx>, borrow_set: &'cg BorrowSet<'tcx>,
body: &'cg Body<'tcx>,
} }
impl<'cg, 'cx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, '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. /// 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) { fn record_killed_borrows_for_place(&mut self, place: &Place<'tcx>, location: Location) {
if let Some(all_facts) = self.all_facts { if let Some(all_facts) = self.all_facts {
if let Place { // Depending on the `Place` we're killing:
base: PlaceBase::Local(local), // - if it's a local, or a single deref of a local,
projection: None, // we kill all the borrows on the local.
} = place { // - if it's a deeper projection, we have to filter which
record_killed_borrows_for_local( // of the borrows are killed: the ones whose `borrowed_place`
all_facts, // conflicts with the `place`.
self.borrow_set, match place {
self.location_table, Place {
local, base: PlaceBase::Local(local),
location, 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));
}
}
}
}
} }
} }
} }