Auto merge of #60266 - albins:polonius-liveness, r=nikomatsakis
Fact generation for liveness calculations in Polonius This PR tracks ongoing work to extend `rustc` with support for generating variable use, definition, and later also drop output for the Polonius solver, the whole of which is being tracked in [Polonius Issue #104](https://github.com/rust-lang/polonius/issues/104).
This commit is contained in:
commit
6b468c6360
@ -2214,7 +2214,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "polonius-engine"
|
||||
version = "0.7.0"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"datafrog 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2686,7 +2686,7 @@ dependencies = [
|
||||
"measureme 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-rayon 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-rayon-core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_apfloat 0.0.0",
|
||||
@ -3203,7 +3203,7 @@ dependencies = [
|
||||
"graphviz 0.0.0",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc 0.0.0",
|
||||
"rustc_apfloat 0.0.0",
|
||||
"rustc_data_structures 0.0.0",
|
||||
@ -4695,7 +4695,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
"checksum phf_generator 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662"
|
||||
"checksum phf_shared 0.7.24 (registry+https://github.com/rust-lang/crates.io-index)" = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0"
|
||||
"checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
||||
"checksum polonius-engine 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b24942fee141ea45628484a453762bb7e515099c3ec05fbeb76b7bf57b1aeed"
|
||||
"checksum polonius-engine 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f6b8a5defa2aef9ba4999aaa745fbc01c622ecea35964a306adc3e44be4f3b5b"
|
||||
"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
|
||||
"checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6"
|
||||
"checksum pretty_env_logger 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8b3f4e0475def7d9c2e5de8e5a1306949849761e107b360d03e98eafaffd61"
|
||||
|
@ -19,9 +19,9 @@ lazy_static = "1.0.0"
|
||||
num_cpus = "1.0"
|
||||
scoped-tls = "1.0"
|
||||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
polonius-engine = "0.7.0"
|
||||
rustc-rayon = "0.2.0"
|
||||
rustc-rayon-core = "0.2.0"
|
||||
polonius-engine = "0.9.0"
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@ either = "1.5.0"
|
||||
dot = { path = "../libgraphviz", package = "graphviz" }
|
||||
log = "0.4"
|
||||
log_settings = "0.1.1"
|
||||
polonius-engine = "0.7.0"
|
||||
polonius-engine = "0.9.0"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! FIXME: this might be better as a "generic" fixed-point combinator,
|
||||
//! but is not as ugly as it is right now.
|
||||
|
||||
use rustc::mir::{BasicBlock, Location};
|
||||
use rustc::mir::{BasicBlock, Local, Location};
|
||||
use rustc::ty::RegionVid;
|
||||
use rustc_data_structures::bit_set::BitIter;
|
||||
|
||||
@ -15,12 +15,14 @@ use crate::dataflow::indexes::BorrowIndex;
|
||||
use crate::dataflow::move_paths::HasMoveData;
|
||||
use crate::dataflow::Borrows;
|
||||
use crate::dataflow::EverInitializedPlaces;
|
||||
use crate::dataflow::{FlowAtLocation, FlowsAtLocation};
|
||||
use crate::dataflow::MaybeUninitializedPlaces;
|
||||
use crate::dataflow::{FlowAtLocation, FlowsAtLocation};
|
||||
use either::Either;
|
||||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local>;
|
||||
|
||||
// (forced to be `pub` due to its use as an associated type below.)
|
||||
crate struct Flows<'b, 'tcx> {
|
||||
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
|
||||
@ -28,7 +30,7 @@ crate struct Flows<'b, 'tcx> {
|
||||
pub ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>,
|
||||
|
||||
/// Polonius Output
|
||||
pub polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
pub polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
}
|
||||
|
||||
impl<'b, 'tcx> Flows<'b, 'tcx> {
|
||||
@ -36,14 +38,9 @@ impl<'b, 'tcx> Flows<'b, 'tcx> {
|
||||
borrows: FlowAtLocation<'tcx, Borrows<'b, 'tcx>>,
|
||||
uninits: FlowAtLocation<'tcx, MaybeUninitializedPlaces<'b, 'tcx>>,
|
||||
ever_inits: FlowAtLocation<'tcx, EverInitializedPlaces<'b, 'tcx>>,
|
||||
polonius_output: Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
polonius_output: Option<Rc<PoloniusOutput>>,
|
||||
) -> Self {
|
||||
Flows {
|
||||
borrows,
|
||||
uninits,
|
||||
ever_inits,
|
||||
polonius_output,
|
||||
}
|
||||
Flows { borrows, uninits, ever_inits, polonius_output }
|
||||
}
|
||||
|
||||
crate fn borrows_in_scope(
|
||||
|
@ -2,6 +2,7 @@ use crate::borrow_check::location::{LocationIndex, LocationTable};
|
||||
use crate::dataflow::indexes::BorrowIndex;
|
||||
use polonius_engine::AllFacts as PoloniusAllFacts;
|
||||
use polonius_engine::Atom;
|
||||
use rustc::mir::Local;
|
||||
use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
use std::error::Error;
|
||||
@ -10,7 +11,7 @@ use std::fs::{self, File};
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex>;
|
||||
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local>;
|
||||
|
||||
crate trait AllFactsExt {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
@ -27,8 +28,7 @@ crate trait AllFactsExt {
|
||||
impl AllFactsExt for AllFacts {
|
||||
/// Return
|
||||
fn enabled(tcx: TyCtxt<'_>) -> bool {
|
||||
tcx.sess.opts.debugging_opts.nll_facts
|
||||
|| tcx.sess.opts.debugging_opts.polonius
|
||||
tcx.sess.opts.debugging_opts.nll_facts || tcx.sess.opts.debugging_opts.polonius
|
||||
}
|
||||
|
||||
fn write_to_dir(
|
||||
@ -60,6 +60,12 @@ impl AllFactsExt for AllFacts {
|
||||
outlives,
|
||||
region_live_at,
|
||||
invalidates,
|
||||
var_used,
|
||||
var_defined,
|
||||
var_drop_used,
|
||||
var_uses_region,
|
||||
var_drops_region,
|
||||
var_initialized_on_exit,
|
||||
])
|
||||
}
|
||||
Ok(())
|
||||
@ -84,11 +90,7 @@ struct FactWriter<'w> {
|
||||
}
|
||||
|
||||
impl<'w> FactWriter<'w> {
|
||||
fn write_facts_to_path<T>(
|
||||
&self,
|
||||
rows: &[T],
|
||||
file_name: &str,
|
||||
) -> Result<(), Box<dyn Error>>
|
||||
fn write_facts_to_path<T>(&self, rows: &[T], file_name: &str) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
T: FactRow,
|
||||
{
|
||||
@ -102,19 +104,11 @@ impl<'w> FactWriter<'w> {
|
||||
}
|
||||
|
||||
trait FactRow {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>>;
|
||||
fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl FactRow for RegionVid {
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[self])
|
||||
}
|
||||
}
|
||||
@ -124,11 +118,7 @@ where
|
||||
A: FactCell,
|
||||
B: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1])
|
||||
}
|
||||
}
|
||||
@ -139,11 +129,7 @@ where
|
||||
B: FactCell,
|
||||
C: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2])
|
||||
}
|
||||
}
|
||||
@ -155,11 +141,7 @@ where
|
||||
C: FactCell,
|
||||
D: FactCell,
|
||||
{
|
||||
fn write(
|
||||
&self,
|
||||
out: &mut File,
|
||||
location_table: &LocationTable,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
fn write(&self, out: &mut File, location_table: &LocationTable) -> Result<(), Box<dyn Error>> {
|
||||
write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
|
||||
}
|
||||
}
|
||||
@ -170,11 +152,7 @@ fn write_row(
|
||||
columns: &[&dyn FactCell],
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
for (index, c) in columns.iter().enumerate() {
|
||||
let tail = if index == columns.len() - 1 {
|
||||
"\n"
|
||||
} else {
|
||||
"\t"
|
||||
};
|
||||
let tail = if index == columns.len() - 1 { "\n" } else { "\t" };
|
||||
write!(out, "{:?}{}", c.to_string(location_table), tail)?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -11,7 +11,7 @@ use crate::transform::MirSource;
|
||||
use crate::borrow_check::Upvar;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::infer::InferCtxt;
|
||||
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Body};
|
||||
use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body};
|
||||
use rustc::ty::{self, RegionKind, RegionVid};
|
||||
use rustc_errors::Diagnostic;
|
||||
use std::fmt::Debug;
|
||||
@ -84,7 +84,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
||||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex>>>,
|
||||
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local>>>,
|
||||
Option<ClosureRegionRequirements<'tcx>>,
|
||||
) {
|
||||
let mut all_facts = if AllFacts::enabled(infcx.tcx) {
|
||||
|
@ -7,7 +7,7 @@ use crate::borrow_check::nll::ToRegionVid;
|
||||
use crate::dataflow::move_paths::MoveData;
|
||||
use crate::dataflow::FlowAtLocation;
|
||||
use crate::dataflow::MaybeInitializedPlaces;
|
||||
use rustc::mir::{Local, Body};
|
||||
use rustc::mir::{Body, Local};
|
||||
use rustc::ty::{RegionVid, TyCtxt};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use std::rc::Rc;
|
||||
@ -15,6 +15,7 @@ use std::rc::Rc;
|
||||
use super::TypeChecker;
|
||||
|
||||
mod local_use_map;
|
||||
mod polonius;
|
||||
mod trace;
|
||||
|
||||
/// Combines liveness analysis with initialization analysis to
|
||||
@ -57,15 +58,9 @@ pub(super) fn generate<'tcx>(
|
||||
};
|
||||
|
||||
if !live_locals.is_empty() {
|
||||
trace::trace(
|
||||
typeck,
|
||||
body,
|
||||
elements,
|
||||
flow_inits,
|
||||
move_data,
|
||||
live_locals,
|
||||
location_table,
|
||||
);
|
||||
trace::trace(typeck, body, elements, flow_inits, move_data, live_locals, location_table);
|
||||
|
||||
polonius::populate_var_liveness_facts(typeck, body, location_table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,94 @@
|
||||
use crate::borrow_check::location::{LocationIndex, LocationTable};
|
||||
use crate::util::liveness::{categorize, DefUse};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::{Body, Local, Location};
|
||||
use rustc::ty::subst::Kind;
|
||||
use rustc::ty::Ty;
|
||||
|
||||
use super::TypeChecker;
|
||||
|
||||
type VarPointRelations = Vec<(Local, LocationIndex)>;
|
||||
|
||||
struct LivenessPointFactsExtractor<'me> {
|
||||
var_defined: &'me mut VarPointRelations,
|
||||
var_used: &'me mut VarPointRelations,
|
||||
location_table: &'me LocationTable,
|
||||
}
|
||||
|
||||
// A Visitor to walk through the MIR and extract point-wise facts
|
||||
impl LivenessPointFactsExtractor<'_> {
|
||||
fn location_to_index(&self, location: Location) -> LocationIndex {
|
||||
self.location_table.mid_index(location)
|
||||
}
|
||||
|
||||
fn insert_def(&mut self, local: Local, location: Location) {
|
||||
debug!("LivenessFactsExtractor::insert_def()");
|
||||
self.var_defined.push((local, self.location_to_index(location)));
|
||||
}
|
||||
|
||||
fn insert_use(&mut self, local: Local, location: Location) {
|
||||
debug!("LivenessFactsExtractor::insert_use()");
|
||||
self.var_used.push((local, self.location_to_index(location)));
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
|
||||
fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Location) {
|
||||
match categorize(context) {
|
||||
Some(DefUse::Def) => self.insert_def(local, location),
|
||||
Some(DefUse::Use) => self.insert_use(local, location),
|
||||
_ => (),
|
||||
// NOTE: Drop handling is now done in trace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty<'tcx>) {
|
||||
debug!("add_regions(local={:?}, type={:?})", local, ty);
|
||||
typeck.tcx().for_each_free_region(&ty, |region| {
|
||||
let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(region);
|
||||
debug!("add_regions for region {:?}", region_vid);
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts {
|
||||
facts.var_uses_region.push((local, region_vid));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn populate_var_liveness_facts(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("populate_var_liveness_facts()");
|
||||
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
||||
LivenessPointFactsExtractor {
|
||||
var_defined: &mut facts.var_defined,
|
||||
var_used: &mut facts.var_used,
|
||||
location_table,
|
||||
}
|
||||
.visit_body(mir);
|
||||
}
|
||||
|
||||
for (local, local_decl) in mir.local_decls.iter_enumerated() {
|
||||
add_var_uses_regions(typeck, local, local_decl.ty);
|
||||
}
|
||||
}
|
||||
|
||||
// For every potentially drop()-touched region `region` in `local`'s type
|
||||
// (`kind`), emit a Polonius `var_drops_region(local, region)` fact.
|
||||
pub(super) fn add_var_drops_regions(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
local: Local,
|
||||
kind: &Kind<'tcx>,
|
||||
) {
|
||||
debug!("add_var_drops_region(local={:?}, kind={:?}", local, kind);
|
||||
let tcx = typeck.tcx();
|
||||
|
||||
tcx.for_each_free_region(kind, |drop_live_region| {
|
||||
let region_vid = typeck.borrowck_context.universal_regions.to_region_vid(drop_live_region);
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
||||
facts.var_drops_region.push((local, region_vid));
|
||||
};
|
||||
});
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
use crate::borrow_check::location::LocationTable;
|
||||
use crate::borrow_check::nll::region_infer::values::{self, PointIndex, RegionValueElements};
|
||||
use crate::borrow_check::nll::type_check::liveness::local_use_map::LocalUseMap;
|
||||
use crate::borrow_check::nll::type_check::liveness::polonius;
|
||||
use crate::borrow_check::nll::type_check::NormalizeLocation;
|
||||
use crate::borrow_check::nll::type_check::TypeChecker;
|
||||
use crate::dataflow::indexes::MovePathIndex;
|
||||
use crate::dataflow::move_paths::MoveData;
|
||||
use crate::dataflow::{FlowAtLocation, FlowsAtLocation, MaybeInitializedPlaces};
|
||||
use rustc::infer::canonical::QueryRegionConstraints;
|
||||
use rustc::mir::{BasicBlock, ConstraintCategory, Local, Location, Body};
|
||||
use rustc::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
|
||||
use rustc::traits::query::dropck_outlives::DropckOutlivesResult;
|
||||
use rustc::traits::query::type_op::outlives::DropckOutlives;
|
||||
use rustc::traits::query::type_op::TypeOp;
|
||||
@ -130,6 +131,12 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
for local in live_locals {
|
||||
self.reset_local_state();
|
||||
self.add_defs_for(local);
|
||||
|
||||
// FIXME: this is temporary until we can generate our own initialization
|
||||
if self.cx.typeck.borrowck_context.all_facts.is_some() {
|
||||
self.add_polonius_var_initialized_on_exit_for(local)
|
||||
}
|
||||
|
||||
self.compute_use_live_points_for(local);
|
||||
self.compute_drop_live_points_for(local);
|
||||
|
||||
@ -150,6 +157,63 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// WARNING: panics if self.cx.typeck.borrowck_context.all_facts != None
|
||||
//
|
||||
// FIXME: this analysis (the initialization tracking) should be
|
||||
// done in Polonius, but isn't yet.
|
||||
fn add_polonius_var_initialized_on_exit_for(&mut self, local: Local) {
|
||||
let move_path = self.cx.move_data.rev_lookup.find_local(local);
|
||||
let facts = self.cx.typeck.borrowck_context.all_facts.as_mut().unwrap();
|
||||
for block in self.cx.body.basic_blocks().indices() {
|
||||
debug!("polonius: generating initialization facts for {:?} in {:?}", local, block);
|
||||
|
||||
// iterate through the block, applying the effects of each statement
|
||||
// up to and including location, and populate `var_initialized_on_exit`
|
||||
self.cx.flow_inits.reset_to_entry_of(block);
|
||||
let start_location = Location { block, statement_index: 0 };
|
||||
self.cx.flow_inits.apply_local_effect(start_location);
|
||||
|
||||
for statement_index in 0..self.cx.body[block].statements.len() {
|
||||
let current_location = Location { block, statement_index };
|
||||
|
||||
self.cx.flow_inits.reconstruct_statement_effect(current_location);
|
||||
|
||||
// statement has not yet taken effect:
|
||||
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
|
||||
facts
|
||||
.var_initialized_on_exit
|
||||
.push((local, self.cx.location_table.start_index(current_location)));
|
||||
}
|
||||
|
||||
// statement has now taken effect
|
||||
self.cx.flow_inits.apply_local_effect(current_location);
|
||||
|
||||
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
|
||||
facts
|
||||
.var_initialized_on_exit
|
||||
.push((local, self.cx.location_table.mid_index(current_location)));
|
||||
}
|
||||
}
|
||||
|
||||
let terminator_location = self.cx.body.terminator_loc(block);
|
||||
|
||||
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
|
||||
facts
|
||||
.var_initialized_on_exit
|
||||
.push((local, self.cx.location_table.start_index(terminator_location)));
|
||||
}
|
||||
|
||||
// apply the effects of the terminator and push it if needed
|
||||
self.cx.flow_inits.reset_to_exit_of(block);
|
||||
|
||||
if self.cx.flow_inits.has_any_child_of(move_path).is_some() {
|
||||
facts
|
||||
.var_initialized_on_exit
|
||||
.push((local, self.cx.location_table.mid_index(terminator_location)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Clear the value of fields that are "per local variable".
|
||||
fn reset_local_state(&mut self) {
|
||||
self.defs.clear();
|
||||
@ -183,9 +247,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
}
|
||||
|
||||
if self.use_live_at.insert(p) {
|
||||
self.cx
|
||||
.elements
|
||||
.push_predecessors(self.cx.body, p, &mut self.stack)
|
||||
self.cx.elements.push_predecessors(self.cx.body, p, &mut self.stack)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,6 +273,11 @@ 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);
|
||||
@ -218,10 +285,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
"compute_drop_live_points_for: drop_locations={:?}",
|
||||
self.drop_locations
|
||||
);
|
||||
debug!("compute_drop_live_points_for: drop_locations={:?}", self.drop_locations);
|
||||
|
||||
// Reverse DFS. But for drops, we do it a bit differently.
|
||||
// The stack only ever stores *terminators of blocks*. Within
|
||||
@ -257,17 +321,11 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
// block. One of them may be either a definition or use
|
||||
// live point.
|
||||
let term_location = self.cx.elements.to_location(term_point);
|
||||
debug_assert_eq!(
|
||||
self.cx.body.terminator_loc(term_location.block),
|
||||
term_location,
|
||||
);
|
||||
debug_assert_eq!(self.cx.body.terminator_loc(term_location.block), term_location,);
|
||||
let block = term_location.block;
|
||||
let entry_point = self.cx.elements.entry_point(term_location.block);
|
||||
for p in (entry_point..term_point).rev() {
|
||||
debug!(
|
||||
"compute_drop_live_points_for_block: p = {:?}",
|
||||
self.cx.elements.to_location(p),
|
||||
);
|
||||
debug!("compute_drop_live_points_for_block: p = {:?}", self.cx.elements.to_location(p));
|
||||
|
||||
if self.defs.contains(p) {
|
||||
debug!("compute_drop_live_points_for_block: def site");
|
||||
@ -286,10 +344,7 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
}
|
||||
|
||||
for &pred_block in self.cx.body.predecessors_for(block).iter() {
|
||||
debug!(
|
||||
"compute_drop_live_points_for_block: pred_block = {:?}",
|
||||
pred_block,
|
||||
);
|
||||
debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,);
|
||||
|
||||
// Check whether the variable is (at least partially)
|
||||
// initialized at the exit of this predecessor. If so, we
|
||||
@ -320,18 +375,12 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> {
|
||||
// If the terminator of this predecessor either *assigns*
|
||||
// our value or is a "normal use", then stop.
|
||||
if self.defs.contains(pred_term_point) {
|
||||
debug!(
|
||||
"compute_drop_live_points_for_block: defined at {:?}",
|
||||
pred_term_loc
|
||||
);
|
||||
debug!("compute_drop_live_points_for_block: defined at {:?}", pred_term_loc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if self.use_live_at.contains(pred_term_point) {
|
||||
debug!(
|
||||
"compute_drop_live_points_for_block: use-live at {:?}",
|
||||
pred_term_loc
|
||||
);
|
||||
debug!("compute_drop_live_points_for_block: use-live at {:?}", pred_term_loc);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -392,10 +441,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
||||
// "just ahead" of a terminator.
|
||||
self.flow_inits.reset_to_entry_of(block);
|
||||
for statement_index in 0..self.body[block].statements.len() {
|
||||
let location = Location {
|
||||
block,
|
||||
statement_index,
|
||||
};
|
||||
let location = Location { block, statement_index };
|
||||
self.flow_inits.reconstruct_statement_effect(location);
|
||||
self.flow_inits.apply_local_effect(location);
|
||||
}
|
||||
@ -462,12 +508,11 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
||||
|
||||
if let Some(data) = &drop_data.region_constraint_data {
|
||||
for &drop_location in drop_locations {
|
||||
self.typeck
|
||||
.push_region_constraints(
|
||||
drop_location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
data,
|
||||
);
|
||||
self.typeck.push_region_constraints(
|
||||
drop_location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
data,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -487,6 +532,8 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
||||
live_at,
|
||||
self.location_table,
|
||||
);
|
||||
|
||||
polonius::add_var_drops_regions(&mut self.typeck, dropped_local, &kind);
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,14 +552,15 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
||||
|
||||
let tcx = typeck.tcx();
|
||||
tcx.for_each_free_region(&value, |live_region| {
|
||||
let live_region_vid = typeck.borrowck_context
|
||||
.universal_regions
|
||||
.to_region_vid(live_region);
|
||||
typeck.borrowck_context
|
||||
let live_region_vid =
|
||||
typeck.borrowck_context.universal_regions.to_region_vid(live_region);
|
||||
typeck
|
||||
.borrowck_context
|
||||
.constraints
|
||||
.liveness_constraints
|
||||
.add_elements(live_region_vid, live_at);
|
||||
|
||||
// FIXME: remove this when we can generate our own region-live-at reliably
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts {
|
||||
for point in live_at.iter() {
|
||||
let loc = elements.to_location(point);
|
||||
@ -530,14 +578,9 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
||||
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
|
||||
|
||||
let param_env = typeck.param_env;
|
||||
let (dropck_result, region_constraint_data) = param_env
|
||||
.and(DropckOutlives::new(dropped_ty))
|
||||
.fully_perform(typeck.infcx)
|
||||
.unwrap();
|
||||
let (dropck_result, region_constraint_data) =
|
||||
param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
|
||||
|
||||
DropData {
|
||||
dropck_result,
|
||||
region_constraint_data,
|
||||
}
|
||||
DropData { dropck_result, region_constraint_data }
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user