1
Fork 0

Complete implementation of invalidates facts

This commit is contained in:
bobtwinkles 2018-05-15 22:31:29 -07:00
parent 3b36fa8c3f
commit 0c902cfeca
2 changed files with 60 additions and 36 deletions

View file

@ -17,10 +17,10 @@ use borrow_check::{Context, ContextKind};
use borrow_check::{LocalMutationIsAllowed, MutateMode}; use borrow_check::{LocalMutationIsAllowed, MutateMode};
use borrow_check::ArtificialField; use borrow_check::ArtificialField;
use borrow_check::{ReadKind, WriteKind, Overlap}; use borrow_check::{ReadKind, WriteKind, Overlap};
use borrow_check::nll::region_infer::RegionInferenceContext;
use borrow_check::nll::facts::AllFacts; use borrow_check::nll::facts::AllFacts;
use dataflow::move_paths::indexes::BorrowIndex; use dataflow::move_paths::indexes::BorrowIndex;
use rustc::hir; use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt; use rustc::infer::InferCtxt;
use rustc::mir::visit::Visitor; use rustc::mir::visit::Visitor;
use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue, Projection}; use rustc::mir::{BasicBlock, Location, Mir, Place, Rvalue, Projection};
@ -28,16 +28,16 @@ use rustc::mir::{Local, ProjectionElem};
use rustc::mir::{Statement, StatementKind}; use rustc::mir::{Statement, StatementKind};
use rustc::mir::{Terminator, TerminatorKind}; use rustc::mir::{Terminator, TerminatorKind};
use rustc::mir::{Field, Operand, BorrowKind}; use rustc::mir::{Field, Operand, BorrowKind};
use rustc::ty; use rustc::ty::{self, ParamEnv};
use rustc_data_structures::indexed_vec::Idx; use rustc_data_structures::indexed_vec::Idx;
use std::iter; use std::iter;
pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>( pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>(
infcx: &InferCtxt<'cx, 'gcx, 'tcx>, infcx: &InferCtxt<'cx, 'gcx, 'tcx>,
regioncx: &mut RegionInferenceContext<'tcx>,
all_facts: &mut Option<AllFacts>, all_facts: &mut Option<AllFacts>,
location_table: &LocationTable, location_table: &LocationTable,
mir: &Mir<'tcx>, mir: &Mir<'tcx>,
mir_def_id: DefId,
borrow_set: &BorrowSet<'tcx>, borrow_set: &BorrowSet<'tcx>,
) { ) {
if !all_facts.is_some() { if !all_facts.is_some() {
@ -45,36 +45,42 @@ pub(super) fn generate_invalidates<'cx, 'gcx, 'tcx>(
return; return;
} }
let mut ig = InvalidationGenerator { let param_env = infcx.tcx.param_env(mir_def_id);
all_facts: &mut all_facts.unwrap(),
borrow_set, let mut all_facts_taken = all_facts.take().unwrap();
infcx, {
regioncx, let mut ig = InvalidationGenerator {
location_table, all_facts: &mut all_facts_taken,
mir, borrow_set,
}; infcx,
location_table,
mir,
param_env,
};
ig.visit_mir(mir);
}
*all_facts = Some(all_facts_taken);
} }
/// 'cg = the duration of the constraint generation process itself. /// 'cg = the duration of the constraint generation process itself.
struct InvalidationGenerator<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> { struct InvalidationGenerator<'cg, 'cx: 'cg, 'tcx: 'cx, 'gcx: 'tcx> {
infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>, infcx: &'cg InferCtxt<'cx, 'gcx, 'tcx>,
all_facts: &'cg mut AllFacts, all_facts: &'cg mut AllFacts,
location_table: &'cg LocationTable, location_table: &'cg LocationTable,
regioncx: &'cg mut RegionInferenceContext<'tcx>,
mir: &'cg Mir<'tcx>, mir: &'cg Mir<'tcx>,
borrow_set: &'cg BorrowSet<'tcx>, borrow_set: &'cg BorrowSet<'tcx>,
param_env: ParamEnv<'gcx>,
} }
/// Visits the whole MIR and generates invalidates() facts /// Visits the whole MIR and generates invalidates() facts
/// Most of the code implementing this was stolen from borrow_check/mod.rs /// Most of the code implementing this was stolen from borrow_check/mod.rs
impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx> { impl<'cg, 'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> {
fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>, location: Location) { fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>, location: Location) {
match statement.kind { match statement.kind {
StatementKind::Assign(ref lhs, ref rhs) => { StatementKind::Assign(ref lhs, ref rhs) => {
self.consume_rvalue( self.consume_rvalue(
ContextKind::AssignRhs.new(location), ContextKind::AssignRhs.new(location),
rhs, rhs,
location
); );
self.mutate_place( self.mutate_place(
@ -170,6 +176,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> Visitor<'tcx> for InvalidationGenerat
let gcx = tcx.global_tcx(); let gcx = tcx.global_tcx();
let drop_place_ty = drop_place.ty(self.mir, tcx); let drop_place_ty = drop_place.ty(self.mir, tcx);
let drop_place_ty = tcx.erase_regions(&drop_place_ty).to_ty(tcx); let drop_place_ty = tcx.erase_regions(&drop_place_ty).to_ty(tcx);
let drop_place_ty = gcx.lift(&drop_place_ty).unwrap();
self.visit_terminator_drop(location, terminator, drop_place, drop_place_ty); self.visit_terminator_drop(location, terminator, drop_place, drop_place_ty);
} }
TerminatorKind::DropAndReplace { TerminatorKind::DropAndReplace {
@ -275,7 +282,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> Visitor<'tcx> for InvalidationGenerat
} }
} }
impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx> { impl<'cg, 'cx, 'tcx, 'gcx> InvalidationGenerator<'cg, 'cx, 'tcx, 'gcx> {
/// Simulates dropping of a variable /// Simulates dropping of a variable
fn visit_terminator_drop( fn visit_terminator_drop(
&mut self, &mut self,
@ -286,10 +293,10 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
) { ) {
let gcx = self.infcx.tcx.global_tcx(); let gcx = self.infcx.tcx.global_tcx();
let drop_field = | let drop_field = |
ig: &mut InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx>, ig: &mut InvalidationGenerator<'cg, 'cx, 'gcx, 'tcx>,
(index, field): (usize, ty::Ty<'gcx>), (index, field): (usize, ty::Ty<'gcx>),
| { | {
let field_ty = gcx.normalize_erasing_regions(self.mir.param_env, field); let field_ty = gcx.normalize_erasing_regions(ig.param_env, field);
let place = drop_place.clone().field(Field::new(index), field_ty); let place = drop_place.clone().field(Field::new(index), field_ty);
ig.visit_terminator_drop(loc, term, &place, field_ty); ig.visit_terminator_drop(loc, term, &place, field_ty);
@ -351,7 +358,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
context: Context, context: Context,
place: &Place<'tcx>, place: &Place<'tcx>,
kind: ShallowOrDeep, kind: ShallowOrDeep,
mode: MutateMode, _mode: MutateMode,
) { ) {
self.access_place( self.access_place(
context, context,
@ -393,7 +400,6 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
&mut self, &mut self,
context: Context, context: Context,
rvalue: &Rvalue<'tcx>, rvalue: &Rvalue<'tcx>,
location: Location,
) { ) {
match *rvalue { match *rvalue {
Rvalue::Ref(_ /*rgn*/, bk, ref place) => { Rvalue::Ref(_ /*rgn*/, bk, ref place) => {
@ -447,7 +453,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
Rvalue::NullaryOp(_op, _ty) => { Rvalue::NullaryOp(_op, _ty) => {
} }
Rvalue::Aggregate(ref aggregate_kind, ref operands) => { Rvalue::Aggregate(_, ref operands) => {
for operand in operands { for operand in operands {
self.consume_operand(context, operand); self.consume_operand(context, operand);
} }
@ -461,7 +467,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
context: Context, context: Context,
place: &Place<'tcx>, place: &Place<'tcx>,
kind: (ShallowOrDeep, ReadOrWrite), kind: (ShallowOrDeep, ReadOrWrite),
is_local_mutation_allowed: LocalMutationIsAllowed, _is_local_mutation_allowed: LocalMutationIsAllowed,
) { ) {
let (sd, rw) = kind; let (sd, rw) = kind;
// note: not doing check_access_permissions checks because they don't generate invalidates // note: not doing check_access_permissions checks because they don't generate invalidates
@ -502,7 +508,7 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
// Reads/reservations don't invalidate shared borrows // Reads/reservations don't invalidate shared borrows
} }
(Read(kind), BorrowKind::Unique) | (Read(kind), BorrowKind::Mut { .. }) => { (Read(_), BorrowKind::Unique) | (Read(_), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK. // Reading from mere reservations of mutable-borrows is OK.
if !this.is_active(borrow, context.loc) { if !this.is_active(borrow, context.loc) {
// If the borrow isn't active yet, reads don't invalidate it // If the borrow isn't active yet, reads don't invalidate it
@ -512,20 +518,13 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
// Unique and mutable borrows are invalidated by reads from any // Unique and mutable borrows are invalidated by reads from any
// involved path // involved path
match kind { this.generate_invalidates(borrow_index, context.loc);
ReadKind::Copy => {
this.generate_invalidates(borrow_index, context.loc);
}
ReadKind::Borrow(bk) => {
this.generate_invalidates(borrow_index, context.loc);
}
}
} }
(Reservation(kind), BorrowKind::Unique) (Reservation(_), BorrowKind::Unique)
| (Reservation(kind), BorrowKind::Mut { .. }) | (Reservation(_), BorrowKind::Mut { .. })
| (Activation(kind, _), _) | (Activation(_, _), _)
| (Write(kind), _) => { | (Write(_), _) => {
// unique or mutable borrows are invalidated by writes. // unique or mutable borrows are invalidated by writes.
// Reservations count as writes since we need to check // Reservations count as writes since we need to check
// that activating the borrow will be OK // that activating the borrow will be OK
@ -588,6 +587,23 @@ impl<'cg, 'cx: 'cg, 'gcx: 'tcx, 'tcx: 'cx> InvalidationGenerator<'cg, 'cx, 'gcx,
} }
} }
/// Determine if a given two-phase borrow is active using dominator information
fn is_active(&self, borrow: &BorrowData, location: Location) -> bool {
// If it's not two-phase, the borrow is definitely active
if !self.allow_two_phase_borrow(borrow.kind) {
return true;
}
if borrow.activation_location.is_none() {
return false;
}
let activation_location = borrow.activation_location.unwrap();
if activation_location.block == location.block {
activation_location.statement_index >= location.statement_index
} else {
self.mir.dominators().is_dominated_by(location.block, activation_location.block)
}
}
/// Returns whether an access of kind `access` to `access_place` conflicts with /// Returns whether an access of kind `access` to `access_place` conflicts with
/// a borrow/full access to `borrow_place` (for deep accesses to mutable /// a borrow/full access to `borrow_place` (for deep accesses to mutable
/// locations, this function is symmetric between `borrow_place` & `access_place`). /// locations, this function is symmetric between `borrow_place` & `access_place`).

View file

@ -131,6 +131,14 @@ pub(in borrow_check) fn compute_regions<'cx, 'gcx, 'tcx>(
&mir, &mir,
borrow_set, borrow_set,
); );
invalidation::generate_invalidates(
infcx,
&mut all_facts,
location_table,
&mir,
def_id,
borrow_set
);
// Dump facts if requested. // Dump facts if requested.
if let Some(all_facts) = all_facts { if let Some(all_facts) = all_facts {