Polonius: emit initialization/move tracking facts

- var_starts_path
- parent
- initialized_at
- moved_out_at

This also switches to the intended emission of `var_drop_used` fact emission,
where that fact is always emitted on a drop-use of a variable, regardless of its
initialization status, as Polonius now handles that.
This commit is contained in:
Albin Stjerna 2019-07-19 15:38:54 +02:00
parent 996ba932cc
commit 6b09477e91
4 changed files with 74 additions and 9 deletions

View file

@ -4,14 +4,14 @@ use crate::borrow_check::nll::facts::AllFactsExt;
use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
use crate::borrow_check::nll::region_infer::values::RegionValueElements;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::{MoveData, MovePathIndex};
use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind};
use crate::dataflow::FlowAtLocation;
use crate::dataflow::MaybeInitializedPlaces;
use crate::transform::MirSource;
use crate::borrow_check::Upvar;
use rustc::hir::def_id::DefId;
use rustc::infer::InferCtxt;
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body, Promoted};
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, Body, LocalKind, BasicBlock, Promoted};
use rustc::ty::{self, RegionKind, RegionVid};
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_errors::Diagnostic;
@ -69,6 +69,61 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
universal_regions
}
// This function populates an AllFacts instance with base facts related to
// MovePaths and needed for the move analysis.
fn populate_polonius_move_facts(all_facts: &mut AllFacts, move_data: &MoveData<'_>, location_table: &LocationTable, body: &Body<'_>) {
all_facts.var_starts_path.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (v, m)));
for (idx, move_path) in move_data.move_paths.iter_enumerated() {
all_facts.parent.extend(move_path.parents(&move_data.move_paths).iter().map(|&parent| (parent, idx)));
}
// initialized_at
for init in move_data.inits.iter() {
match init.location {
InitLocation::Statement(location) => {
let block_data = &body[location.block];
let is_terminator = location.statement_index == block_data.statements.len();
if is_terminator && init.kind == InitKind::NonPanicPathOnly {
// We are at the terminator of an init that has a panic path,
// and where the init should not happen on panic
for &successor in block_data.terminator().successors() {
if body[successor].is_cleanup {
continue;
}
// The initialization happened in (or rather, when arriving at)
// the successors, but not in the unwind block.
let first_statement = Location { block: successor, statement_index: 0};
all_facts.initialized_at.push((init.path, location_table.start_index(first_statement)));
}
} else {
// In all other cases, the initialization just happens at the
// midpoint, like any other effect.
all_facts.initialized_at.push((init.path, location_table.mid_index(location)));
}
},
// Arguments are initialized on function entry
InitLocation::Argument(local) => {
assert!(body.local_kind(local) == LocalKind::Arg);
let fn_entry = Location {block: BasicBlock::from_u32(0u32), statement_index: 0 };
all_facts.initialized_at.push((init.path, location_table.start_index(fn_entry)));
}
}
}
// moved_out_at
// deinitialisation is assumed to always happen!
all_facts.moved_out_at.extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
}
/// Computes the (non-lexical) regions from the input MIR.
///
/// This may result in errors being reported.
@ -123,6 +178,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
all_facts
.universal_region
.extend(universal_regions.universal_regions());
populate_polonius_move_facts(all_facts, move_data, location_table, body);
}
// Create the region inference context, taking ownership of the

View file

@ -13,6 +13,7 @@ struct LivenessPointFactsExtractor<'me> {
var_defined: &'me mut VarPointRelations,
var_used: &'me mut VarPointRelations,
location_table: &'me LocationTable,
var_drop_used: &'me mut VarPointRelations,
}
// A Visitor to walk through the MIR and extract point-wise facts
@ -30,6 +31,11 @@ impl LivenessPointFactsExtractor<'_> {
debug!("LivenessFactsExtractor::insert_use()");
self.var_used.push((local, self.location_to_index(location)));
}
fn insert_drop_use(&mut self, local: Local, location: Location) {
debug!("LivenessFactsExtractor::insert_drop_use()");
self.var_drop_used.push((local, self.location_to_index(location)));
}
}
impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
@ -37,8 +43,8 @@ impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
match categorize(context) {
Some(DefUse::Def) => self.insert_def(local, location),
Some(DefUse::Use) => self.insert_use(local, location),
Some(DefUse::Drop) => self.insert_drop_use(local, location),
_ => (),
// NOTE: Drop handling is now done in trace()
}
}
}
@ -65,6 +71,7 @@ pub(super) fn populate_var_liveness_facts(
LivenessPointFactsExtractor {
var_defined: &mut facts.var_defined,
var_used: &mut facts.var_used,
var_drop_used: &mut facts.var_drop_used,
location_table,
}
.visit_body(mir);

View file

@ -273,11 +273,6 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
debug_assert_eq!(self.cx.body.terminator_loc(location.block), location,);
if self.cx.initialized_at_terminator(location.block, mpi) {
// FIXME: this analysis (the initialization tracking) should be
// done in Polonius, but isn't yet.
if let Some(facts) = self.cx.typeck.borrowck_context.all_facts {
facts.var_drop_used.push((local, self.cx.location_table.mid_index(location)));
}
if self.drop_live_at.insert(drop_point) {
self.drop_locations.push(location);
self.stack.push(drop_point);

View file

@ -1,9 +1,10 @@
use rustc::ty::{Ty, TyCtxt};
use rustc::mir::*;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc_data_structures::indexed_vec::{Idx, IndexVec, Enumerated};
use smallvec::SmallVec;
use syntax_pos::{Span};
use core::slice::Iter;
use std::fmt;
use std::ops::{Index, IndexMut};
@ -262,6 +263,12 @@ impl MovePathLookup {
pub fn find_local(&self, local: Local) -> MovePathIndex {
self.locals[local]
}
/// An enumerated iterator of `local`s and their associated
/// `MovePathIndex`es.
pub fn iter_locals_enumerated(&self) -> Enumerated<Local, Iter<'_, MovePathIndex>> {
self.locals.iter_enumerated()
}
}
#[derive(Debug)]