Auto merge of #62800 - albins:polonius-initialization-1, r=nikomatsakis
Extend Polonius fact generation for (some) move tracking This PR will extend rustc to emit facts used for tracking moves and initialization in Polonius. It is most likely the final part of my master's thesis work.
This commit is contained in:
commit
9776723881
13 changed files with 322 additions and 272 deletions
|
|
@ -2324,9 +2324,9 @@ checksum = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c"
|
|||
|
||||
[[package]]
|
||||
name = "polonius-engine"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6b8a5defa2aef9ba4999aaa745fbc01c622ecea35964a306adc3e44be4f3b5b"
|
||||
checksum = "50fa9dbfd0d3d60594da338cfe6f94028433eecae4b11b7e83fd99759227bbfe"
|
||||
dependencies = [
|
||||
"datafrog",
|
||||
"log",
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ scoped-tls = "1.0"
|
|||
log = { version = "0.4", features = ["release_max_level_info", "std"] }
|
||||
rustc-rayon = "0.2.0"
|
||||
rustc-rayon-core = "0.2.0"
|
||||
polonius-engine = "0.9.0"
|
||||
polonius-engine = "0.10.0"
|
||||
rustc_apfloat = { path = "../librustc_apfloat" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_macros = { path = "../librustc_macros" }
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ either = "1.5.0"
|
|||
dot = { path = "../libgraphviz", package = "graphviz" }
|
||||
log = "0.4"
|
||||
log_settings = "0.1.1"
|
||||
polonius-engine = "0.9.0"
|
||||
polonius-engine = "0.10.0"
|
||||
rustc = { path = "../librustc" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
rustc_data_structures = { path = "../librustc_data_structures" }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ use crate::borrow_check::location::LocationIndex;
|
|||
use polonius_engine::Output;
|
||||
|
||||
use crate::dataflow::indexes::BorrowIndex;
|
||||
use crate::dataflow::move_paths::HasMoveData;
|
||||
use crate::dataflow::move_paths::{HasMoveData, MovePathIndex};
|
||||
use crate::dataflow::Borrows;
|
||||
use crate::dataflow::EverInitializedPlaces;
|
||||
use crate::dataflow::MaybeUninitializedPlaces;
|
||||
|
|
@ -21,7 +21,7 @@ use either::Either;
|
|||
use std::fmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local>;
|
||||
crate type PoloniusOutput = Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
|
||||
|
||||
// (forced to be `pub` due to its use as an associated type below.)
|
||||
crate struct Flows<'b, 'tcx> {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::borrow_check::location::{LocationIndex, LocationTable};
|
||||
use crate::dataflow::indexes::BorrowIndex;
|
||||
use crate::dataflow::indexes::{BorrowIndex, MovePathIndex};
|
||||
use polonius_engine::AllFacts as PoloniusAllFacts;
|
||||
use polonius_engine::Atom;
|
||||
use rustc::mir::Local;
|
||||
|
|
@ -11,7 +11,7 @@ use std::fs::{self, File};
|
|||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
|
||||
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local>;
|
||||
crate type AllFacts = PoloniusAllFacts<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>;
|
||||
|
||||
crate trait AllFactsExt {
|
||||
/// Returns `true` if there is a need to gather `AllFacts` given the
|
||||
|
|
@ -58,14 +58,17 @@ impl AllFactsExt for AllFacts {
|
|||
cfg_edge,
|
||||
killed,
|
||||
outlives,
|
||||
region_live_at,
|
||||
invalidates,
|
||||
var_used,
|
||||
var_defined,
|
||||
var_drop_used,
|
||||
var_uses_region,
|
||||
var_drops_region,
|
||||
var_initialized_on_exit,
|
||||
child,
|
||||
path_belongs_to_var,
|
||||
initialized_at,
|
||||
moved_out_at,
|
||||
path_accessed_at,
|
||||
])
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -84,6 +87,12 @@ impl Atom for LocationIndex {
|
|||
}
|
||||
}
|
||||
|
||||
impl Atom for MovePathIndex {
|
||||
fn index(self) -> usize {
|
||||
Idx::index(self)
|
||||
}
|
||||
}
|
||||
|
||||
struct FactWriter<'w> {
|
||||
location_table: &'w LocationTable,
|
||||
dir: &'w Path,
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@ 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;
|
||||
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 +70,85 @@ 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
|
||||
.path_belongs_to_var
|
||||
.extend(
|
||||
move_data
|
||||
.rev_lookup
|
||||
.iter_locals_enumerated()
|
||||
.map(|(v, &m)| (m, v)));
|
||||
|
||||
for (child, move_path) in move_data.move_paths.iter_enumerated() {
|
||||
all_facts
|
||||
.child
|
||||
.extend(
|
||||
move_path
|
||||
.parents(&move_data.move_paths)
|
||||
.iter()
|
||||
.map(|&parent| (child, parent)));
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
|
@ -87,7 +167,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
|
|||
errors_buffer: &mut Vec<Diagnostic>,
|
||||
) -> (
|
||||
RegionInferenceContext<'tcx>,
|
||||
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local>>>,
|
||||
Option<Rc<Output<RegionVid, BorrowIndex, LocationIndex, Local, MovePathIndex>>>,
|
||||
Option<ClosureRegionRequirements<'tcx>>,
|
||||
) {
|
||||
let mut all_facts = if AllFacts::enabled(infcx.tcx) {
|
||||
|
|
@ -123,6 +203,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
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use crate::borrow_check::nll::region_infer::values::{PointIndex, RegionValueElements};
|
||||
use crate::util::liveness::{categorize, DefUse};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::{Local, Location, Body};
|
||||
use rustc::mir::{Body, Local, Location};
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::vec_linked_list as vll;
|
||||
|
||||
|
|
@ -72,16 +72,10 @@ impl LocalUseMap {
|
|||
|
||||
let mut locals_with_use_data: IndexVec<Local, bool> =
|
||||
IndexVec::from_elem_n(false, body.local_decls.len());
|
||||
live_locals
|
||||
.iter()
|
||||
.for_each(|&local| locals_with_use_data[local] = true);
|
||||
live_locals.iter().for_each(|&local| locals_with_use_data[local] = true);
|
||||
|
||||
LocalUseMapBuild {
|
||||
local_use_map: &mut local_use_map,
|
||||
elements,
|
||||
locals_with_use_data,
|
||||
}
|
||||
.visit_body(body);
|
||||
LocalUseMapBuild { local_use_map: &mut local_use_map, elements, locals_with_use_data }
|
||||
.visit_body(body);
|
||||
|
||||
local_use_map
|
||||
}
|
||||
|
|
@ -151,10 +145,8 @@ impl LocalUseMapBuild<'_> {
|
|||
location: Location,
|
||||
) {
|
||||
let point_index = elements.point_from_location(location);
|
||||
let appearance_index = appearances.push(Appearance {
|
||||
point_index,
|
||||
next: *first_appearance,
|
||||
});
|
||||
let appearance_index =
|
||||
appearances.push(Appearance { point_index, next: *first_appearance });
|
||||
*first_appearance = Some(appearance_index);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +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);
|
||||
|
||||
polonius::populate_var_liveness_facts(typeck, body, location_table);
|
||||
polonius::populate_access_facts(typeck, body, location_table, move_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,28 @@
|
|||
use crate::borrow_check::location::{LocationIndex, LocationTable};
|
||||
use crate::dataflow::indexes::MovePathIndex;
|
||||
use crate::dataflow::move_paths::{LookupResult, MoveData};
|
||||
use crate::util::liveness::{categorize, DefUse};
|
||||
use rustc::mir::visit::{PlaceContext, Visitor};
|
||||
use rustc::mir::{Body, Local, Location};
|
||||
use rustc::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
|
||||
use rustc::mir::{Body, Local, Location, Place};
|
||||
use rustc::ty::subst::Kind;
|
||||
use rustc::ty::Ty;
|
||||
|
||||
use super::TypeChecker;
|
||||
|
||||
type VarPointRelations = Vec<(Local, LocationIndex)>;
|
||||
type MovePathPointRelations = Vec<(MovePathIndex, LocationIndex)>;
|
||||
|
||||
struct LivenessPointFactsExtractor<'me> {
|
||||
struct UseFactsExtractor<'me> {
|
||||
var_defined: &'me mut VarPointRelations,
|
||||
var_used: &'me mut VarPointRelations,
|
||||
location_table: &'me LocationTable,
|
||||
var_drop_used: &'me mut VarPointRelations,
|
||||
move_data: &'me MoveData<'me>,
|
||||
path_accessed_at: &'me mut MovePathPointRelations,
|
||||
}
|
||||
|
||||
// A Visitor to walk through the MIR and extract point-wise facts
|
||||
impl LivenessPointFactsExtractor<'_> {
|
||||
impl UseFactsExtractor<'_> {
|
||||
fn location_to_index(&self, location: Location) -> LocationIndex {
|
||||
self.location_table.mid_index(location)
|
||||
}
|
||||
|
|
@ -30,15 +36,50 @@ 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)));
|
||||
}
|
||||
|
||||
fn insert_path_access(&mut self, path: MovePathIndex, location: Location) {
|
||||
debug!("LivenessFactsExtractor::insert_path_access({:?}, {:?})", path, location);
|
||||
self.path_accessed_at.push((path, self.location_to_index(location)));
|
||||
}
|
||||
|
||||
fn place_to_mpi(&self, place: &Place<'_>) -> Option<MovePathIndex> {
|
||||
match self.move_data.rev_lookup.find(place.as_ref()) {
|
||||
LookupResult::Exact(mpi) => Some(mpi),
|
||||
LookupResult::Parent(mmpi) => mmpi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
|
||||
impl Visitor<'tcx> for UseFactsExtractor<'_> {
|
||||
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),
|
||||
Some(DefUse::Drop) => self.insert_drop_use(local, location),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
|
||||
self.super_place(place, context, location);
|
||||
match context {
|
||||
PlaceContext::NonMutatingUse(_) => {
|
||||
if let Some(mpi) = self.place_to_mpi(place) {
|
||||
self.insert_path_access(mpi, location);
|
||||
}
|
||||
}
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Borrow) => {
|
||||
if let Some(mpi) = self.place_to_mpi(place) {
|
||||
self.insert_path_access(mpi, location);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
// NOTE: Drop handling is now done in trace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -54,23 +95,27 @@ fn add_var_uses_regions(typeck: &mut TypeChecker<'_, 'tcx>, local: Local, ty: Ty
|
|||
});
|
||||
}
|
||||
|
||||
pub(super) fn populate_var_liveness_facts(
|
||||
pub(super) fn populate_access_facts(
|
||||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
mir: &Body<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
location_table: &LocationTable,
|
||||
move_data: &MoveData<'_>,
|
||||
) {
|
||||
debug!("populate_var_liveness_facts()");
|
||||
|
||||
if let Some(facts) = typeck.borrowck_context.all_facts.as_mut() {
|
||||
LivenessPointFactsExtractor {
|
||||
UseFactsExtractor {
|
||||
var_defined: &mut facts.var_defined,
|
||||
var_used: &mut facts.var_used,
|
||||
var_drop_used: &mut facts.var_drop_used,
|
||||
path_accessed_at: &mut facts.path_accessed_at,
|
||||
location_table,
|
||||
move_data,
|
||||
}
|
||||
.visit_body(mir);
|
||||
.visit_body(body);
|
||||
}
|
||||
|
||||
for (local, local_decl) in mir.local_decls.iter_enumerated() {
|
||||
for (local, local_decl) in body.local_decls.iter_enumerated() {
|
||||
add_var_uses_regions(typeck, local, local_decl.ty);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
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;
|
||||
|
|
@ -38,7 +37,6 @@ pub(super) fn trace(
|
|||
flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>,
|
||||
move_data: &MoveData<'tcx>,
|
||||
live_locals: Vec<Local>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("trace()");
|
||||
|
||||
|
|
@ -52,7 +50,6 @@ pub(super) fn trace(
|
|||
local_use_map,
|
||||
move_data,
|
||||
drop_data: FxHashMap::default(),
|
||||
location_table,
|
||||
};
|
||||
|
||||
LivenessResults::new(cx).compute_for_all_locals(live_locals);
|
||||
|
|
@ -82,9 +79,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
|
|||
/// Index indicating where each variable is assigned, used, or
|
||||
/// dropped.
|
||||
local_use_map: &'me LocalUseMap,
|
||||
|
||||
/// Maps between a MIR Location and a LocationIndex
|
||||
location_table: &'me LocationTable,
|
||||
}
|
||||
|
||||
struct DropData<'tcx> {
|
||||
|
|
@ -131,12 +125,6 @@ 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);
|
||||
|
||||
|
|
@ -157,63 +145,6 @@ 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();
|
||||
|
|
@ -273,11 +204,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);
|
||||
|
|
@ -468,13 +394,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
|||
) {
|
||||
debug!("add_use_live_facts_for(value={:?})", value);
|
||||
|
||||
Self::make_all_regions_live(
|
||||
self.elements,
|
||||
&mut self.typeck,
|
||||
value,
|
||||
live_at,
|
||||
self.location_table,
|
||||
)
|
||||
Self::make_all_regions_live(self.elements, &mut self.typeck, value, live_at)
|
||||
}
|
||||
|
||||
/// Some variable with type `live_ty` is "drop live" at `location`
|
||||
|
|
@ -525,13 +445,7 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
|||
// All things in the `outlives` array may be touched by
|
||||
// the destructor and must be live at this point.
|
||||
for &kind in &drop_data.dropck_result.kinds {
|
||||
Self::make_all_regions_live(
|
||||
self.elements,
|
||||
&mut self.typeck,
|
||||
kind,
|
||||
live_at,
|
||||
self.location_table,
|
||||
);
|
||||
Self::make_all_regions_live(self.elements, &mut self.typeck, kind, live_at);
|
||||
|
||||
polonius::add_var_drops_regions(&mut self.typeck, dropped_local, &kind);
|
||||
}
|
||||
|
|
@ -542,7 +456,6 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
|||
typeck: &mut TypeChecker<'_, 'tcx>,
|
||||
value: impl TypeFoldable<'tcx>,
|
||||
live_at: &HybridBitSet<PointIndex>,
|
||||
location_table: &LocationTable,
|
||||
) {
|
||||
debug!("make_all_regions_live(value={:?})", value);
|
||||
debug!(
|
||||
|
|
@ -559,15 +472,6 @@ impl LivenessContext<'_, '_, '_, 'tcx> {
|
|||
.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);
|
||||
facts.region_live_at.push((live_region_vid, location_table.start_index(loc)));
|
||||
facts.region_live_at.push((live_region_vid, location_table.mid_index(loc)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
//! `a[x]` would still overlap them both. But that is not this
|
||||
//! representation does today.)
|
||||
|
||||
use rustc::mir::{Local, PlaceElem, Operand, ProjectionElem};
|
||||
use rustc::mir::{Local, Operand, PlaceElem, ProjectionElem};
|
||||
use rustc::ty::Ty;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||
|
|
@ -26,36 +26,36 @@ pub trait Lift {
|
|||
}
|
||||
impl<'tcx> Lift for Operand<'tcx> {
|
||||
type Abstract = AbstractOperand;
|
||||
fn lift(&self) -> Self::Abstract { AbstractOperand }
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractOperand
|
||||
}
|
||||
}
|
||||
impl Lift for Local {
|
||||
type Abstract = AbstractOperand;
|
||||
fn lift(&self) -> Self::Abstract { AbstractOperand }
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractOperand
|
||||
}
|
||||
}
|
||||
impl<'tcx> Lift for Ty<'tcx> {
|
||||
type Abstract = AbstractType;
|
||||
fn lift(&self) -> Self::Abstract { AbstractType }
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
AbstractType
|
||||
}
|
||||
}
|
||||
impl<'tcx> Lift for PlaceElem<'tcx> {
|
||||
type Abstract = AbstractElem;
|
||||
fn lift(&self) -> Self::Abstract {
|
||||
match *self {
|
||||
ProjectionElem::Deref =>
|
||||
ProjectionElem::Deref,
|
||||
ProjectionElem::Field(ref f, ty) =>
|
||||
ProjectionElem::Field(f.clone(), ty.lift()),
|
||||
ProjectionElem::Index(ref i) =>
|
||||
ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Subslice {from, to} =>
|
||||
ProjectionElem::Subslice { from: from, to: to },
|
||||
ProjectionElem::ConstantIndex {offset,min_length,from_end} =>
|
||||
ProjectionElem::ConstantIndex {
|
||||
offset,
|
||||
min_length,
|
||||
from_end,
|
||||
},
|
||||
ProjectionElem::Downcast(a, u) =>
|
||||
ProjectionElem::Downcast(a, u.clone()),
|
||||
ProjectionElem::Deref => ProjectionElem::Deref,
|
||||
ProjectionElem::Field(ref f, ty) => ProjectionElem::Field(f.clone(), ty.lift()),
|
||||
ProjectionElem::Index(ref i) => ProjectionElem::Index(i.lift()),
|
||||
ProjectionElem::Subslice { from, to } => {
|
||||
ProjectionElem::Subslice { from: from, to: to }
|
||||
}
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
|
||||
ProjectionElem::ConstantIndex { offset, min_length, from_end }
|
||||
}
|
||||
ProjectionElem::Downcast(a, u) => ProjectionElem::Downcast(a, u.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::tcx::RvalueInitializationState;
|
||||
use rustc_data_structures::indexed_vec::{IndexVec};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::mem;
|
||||
|
||||
use super::abs_domain::Lift;
|
||||
use super::{LocationMap, MoveData, MovePath, MovePathLookup, MovePathIndex, MoveOut, MoveOutIndex};
|
||||
use super::{MoveError, InitIndex, Init, InitLocation, LookupResult, InitKind};
|
||||
use super::IllegalMoveOriginKind::*;
|
||||
use super::{Init, InitIndex, InitKind, InitLocation, LookupResult, MoveError};
|
||||
use super::{
|
||||
LocationMap, MoveData, MoveOut, MoveOutIndex, MovePath, MovePathIndex, MovePathLookup,
|
||||
};
|
||||
|
||||
struct MoveDataBuilder<'a, 'tcx> {
|
||||
body: &'a Body<'tcx>,
|
||||
|
|
@ -33,15 +35,19 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
moves: IndexVec::new(),
|
||||
loc_map: LocationMap::new(body),
|
||||
rev_lookup: MovePathLookup {
|
||||
locals: body.local_decls.indices().map(|i| {
|
||||
Self::new_move_path(
|
||||
&mut move_paths,
|
||||
&mut path_map,
|
||||
&mut init_path_map,
|
||||
None,
|
||||
Place::from(i),
|
||||
)
|
||||
}).collect(),
|
||||
locals: body
|
||||
.local_decls
|
||||
.indices()
|
||||
.map(|i| {
|
||||
Self::new_move_path(
|
||||
&mut move_paths,
|
||||
&mut path_map,
|
||||
&mut init_path_map,
|
||||
None,
|
||||
Place::from(i),
|
||||
)
|
||||
})
|
||||
.collect(),
|
||||
projections: Default::default(),
|
||||
},
|
||||
move_paths,
|
||||
|
|
@ -49,27 +55,22 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
inits: IndexVec::new(),
|
||||
init_loc_map: LocationMap::new(body),
|
||||
init_path_map,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn new_move_path(move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
|
||||
path_map: &mut IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
|
||||
init_path_map: &mut IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
|
||||
parent: Option<MovePathIndex>,
|
||||
place: Place<'tcx>)
|
||||
-> MovePathIndex
|
||||
{
|
||||
let move_path = move_paths.push(MovePath {
|
||||
next_sibling: None,
|
||||
first_child: None,
|
||||
parent,
|
||||
place,
|
||||
});
|
||||
fn new_move_path(
|
||||
move_paths: &mut IndexVec<MovePathIndex, MovePath<'tcx>>,
|
||||
path_map: &mut IndexVec<MovePathIndex, SmallVec<[MoveOutIndex; 4]>>,
|
||||
init_path_map: &mut IndexVec<MovePathIndex, SmallVec<[InitIndex; 4]>>,
|
||||
parent: Option<MovePathIndex>,
|
||||
place: Place<'tcx>,
|
||||
) -> MovePathIndex {
|
||||
let move_path =
|
||||
move_paths.push(MovePath { next_sibling: None, first_child: None, parent, place });
|
||||
|
||||
if let Some(parent) = parent {
|
||||
let next_sibling =
|
||||
mem::replace(&mut move_paths[parent].first_child, Some(move_path));
|
||||
let next_sibling = mem::replace(&mut move_paths[parent].first_child, Some(move_path));
|
||||
move_paths[move_path].next_sibling = next_sibling;
|
||||
}
|
||||
|
||||
|
|
@ -91,9 +92,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
/// problematic for borrowck.
|
||||
///
|
||||
/// Maybe we should have separate "borrowck" and "moveck" modes.
|
||||
fn move_path_for(&mut self, place: &Place<'tcx>)
|
||||
-> Result<MovePathIndex, MoveError<'tcx>>
|
||||
{
|
||||
fn move_path_for(&mut self, place: &Place<'tcx>) -> Result<MovePathIndex, MoveError<'tcx>> {
|
||||
debug!("lookup({:?})", place);
|
||||
place.iterate(|place_base, place_projection| {
|
||||
let mut base = match place_base {
|
||||
|
|
@ -108,39 +107,46 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
let tcx = self.builder.tcx;
|
||||
let place_ty = Place::ty_from(place_base, &proj.base, body, tcx).ty;
|
||||
match place_ty.sty {
|
||||
ty::Ref(..) | ty::RawPtr(..) =>
|
||||
ty::Ref(..) | ty::RawPtr(..) => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
self.loc,
|
||||
BorrowedContent {
|
||||
target_place: Place {
|
||||
base: place_base.clone(),
|
||||
projection: Some(Box::new(proj.clone())),
|
||||
}
|
||||
})),
|
||||
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() =>
|
||||
return Err(MoveError::cannot_move_out_of(self.loc,
|
||||
InteriorOfTypeWithDestructor {
|
||||
container_ty: place_ty
|
||||
})),
|
||||
},
|
||||
},
|
||||
));
|
||||
}
|
||||
ty::Adt(adt, _) if adt.has_dtor(tcx) && !adt.is_box() => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
self.loc,
|
||||
InteriorOfTypeWithDestructor { container_ty: place_ty },
|
||||
));
|
||||
}
|
||||
// move out of union - always move the entire union
|
||||
ty::Adt(adt, _) if adt.is_union() =>
|
||||
return Err(MoveError::UnionMove { path: base }),
|
||||
ty::Slice(_) =>
|
||||
ty::Adt(adt, _) if adt.is_union() => {
|
||||
return Err(MoveError::UnionMove { path: base });
|
||||
}
|
||||
ty::Slice(_) => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
self.loc,
|
||||
InteriorOfSliceOrArray {
|
||||
ty: place_ty, is_index: match proj.elem {
|
||||
ty: place_ty,
|
||||
is_index: match proj.elem {
|
||||
ProjectionElem::Index(..) => true,
|
||||
_ => false
|
||||
_ => false,
|
||||
},
|
||||
})),
|
||||
},
|
||||
));
|
||||
}
|
||||
ty::Array(..) => match proj.elem {
|
||||
ProjectionElem::Index(..) =>
|
||||
ProjectionElem::Index(..) => {
|
||||
return Err(MoveError::cannot_move_out_of(
|
||||
self.loc,
|
||||
InteriorOfSliceOrArray {
|
||||
ty: place_ty, is_index: true
|
||||
})),
|
||||
InteriorOfSliceOrArray { ty: place_ty, is_index: true },
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
// FIXME: still badly broken
|
||||
}
|
||||
|
|
@ -186,7 +192,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
|
||||
impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
||||
fn finalize(
|
||||
self
|
||||
self,
|
||||
) -> Result<MoveData<'tcx>, (MoveData<'tcx>, Vec<(Place<'tcx>, MoveError<'tcx>)>)> {
|
||||
debug!("{}", {
|
||||
debug!("moves for {:?}:", self.body.span);
|
||||
|
|
@ -200,11 +206,7 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
"done dumping moves"
|
||||
});
|
||||
|
||||
if !self.errors.is_empty() {
|
||||
Err((self.data, self.errors))
|
||||
} else {
|
||||
Ok(self.data)
|
||||
}
|
||||
if !self.errors.is_empty() { Err((self.data, self.errors)) } else { Ok(self.data) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,10 +224,7 @@ pub(super) fn gather_moves<'tcx>(
|
|||
builder.gather_statement(source, stmt);
|
||||
}
|
||||
|
||||
let terminator_loc = Location {
|
||||
block: bb,
|
||||
statement_index: block.statements.len()
|
||||
};
|
||||
let terminator_loc = Location { block: bb, statement_index: block.statements.len() };
|
||||
builder.gather_terminator(terminator_loc, block.terminator());
|
||||
}
|
||||
|
||||
|
|
@ -238,11 +237,12 @@ impl<'a, 'tcx> MoveDataBuilder<'a, 'tcx> {
|
|||
let path = self.data.rev_lookup.locals[arg];
|
||||
|
||||
let init = self.data.inits.push(Init {
|
||||
path, kind: InitKind::Deep, location: InitLocation::Argument(arg),
|
||||
path,
|
||||
kind: InitKind::Deep,
|
||||
location: InitLocation::Argument(arg),
|
||||
});
|
||||
|
||||
debug!("gather_args: adding init {:?} of {:?} for argument {:?}",
|
||||
init, path, arg);
|
||||
debug!("gather_args: adding init {:?} of {:?} for argument {:?}", init, path, arg);
|
||||
|
||||
self.data.init_path_map[path].push(init);
|
||||
}
|
||||
|
|
@ -297,26 +297,26 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
StatementKind::StorageDead(local) => {
|
||||
self.gather_move(&Place::from(local));
|
||||
}
|
||||
StatementKind::SetDiscriminant{ .. } => {
|
||||
span_bug!(stmt.source_info.span,
|
||||
"SetDiscriminant should not exist during borrowck");
|
||||
StatementKind::SetDiscriminant { .. } => {
|
||||
span_bug!(
|
||||
stmt.source_info.span,
|
||||
"SetDiscriminant should not exist during borrowck"
|
||||
);
|
||||
}
|
||||
StatementKind::Retag { .. } |
|
||||
StatementKind::AscribeUserType(..) |
|
||||
StatementKind::Nop => {}
|
||||
StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Nop => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
|
||||
match *rvalue {
|
||||
Rvalue::Use(ref operand) |
|
||||
Rvalue::Repeat(ref operand, _) |
|
||||
Rvalue::Cast(_, ref operand, _) |
|
||||
Rvalue::UnaryOp(_, ref operand) => {
|
||||
self.gather_operand(operand)
|
||||
}
|
||||
Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs) |
|
||||
Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
|
||||
Rvalue::Use(ref operand)
|
||||
| Rvalue::Repeat(ref operand, _)
|
||||
| Rvalue::Cast(_, ref operand, _)
|
||||
| Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
|
||||
Rvalue::BinaryOp(ref _binop, ref lhs, ref rhs)
|
||||
| Rvalue::CheckedBinaryOp(ref _binop, ref lhs, ref rhs) => {
|
||||
self.gather_operand(lhs);
|
||||
self.gather_operand(rhs);
|
||||
}
|
||||
|
|
@ -325,11 +325,11 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
self.gather_operand(operand);
|
||||
}
|
||||
}
|
||||
Rvalue::Ref(..) |
|
||||
Rvalue::Discriminant(..) |
|
||||
Rvalue::Len(..) |
|
||||
Rvalue::NullaryOp(NullOp::SizeOf, _) |
|
||||
Rvalue::NullaryOp(NullOp::Box, _) => {
|
||||
Rvalue::Ref(..)
|
||||
| Rvalue::Discriminant(..)
|
||||
| Rvalue::Len(..)
|
||||
| Rvalue::NullaryOp(NullOp::SizeOf, _)
|
||||
| Rvalue::NullaryOp(NullOp::Box, _) => {
|
||||
// This returns an rvalue with uninitialized contents. We can't
|
||||
// move out of it here because it is an rvalue - assignments always
|
||||
// completely initialize their place.
|
||||
|
|
@ -346,13 +346,13 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
|
||||
fn gather_terminator(&mut self, term: &Terminator<'tcx>) {
|
||||
match term.kind {
|
||||
TerminatorKind::Goto { target: _ } |
|
||||
TerminatorKind::Resume |
|
||||
TerminatorKind::Abort |
|
||||
TerminatorKind::GeneratorDrop |
|
||||
TerminatorKind::FalseEdges { .. } |
|
||||
TerminatorKind::FalseUnwind { .. } |
|
||||
TerminatorKind::Unreachable => { }
|
||||
TerminatorKind::Goto { target: _ }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::GeneratorDrop
|
||||
| TerminatorKind::FalseEdges { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| TerminatorKind::Unreachable => {}
|
||||
|
||||
TerminatorKind::Return => {
|
||||
self.gather_move(&Place::RETURN_PLACE);
|
||||
|
|
@ -399,9 +399,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
|
||||
fn gather_operand(&mut self, operand: &Operand<'tcx>) {
|
||||
match *operand {
|
||||
Operand::Constant(..) |
|
||||
Operand::Copy(..) => {} // not-a-move
|
||||
Operand::Move(ref place) => { // a move
|
||||
Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move
|
||||
Operand::Move(ref place) => {
|
||||
// a move
|
||||
self.gather_move(place);
|
||||
}
|
||||
}
|
||||
|
|
@ -419,8 +419,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
};
|
||||
let move_out = self.builder.data.moves.push(MoveOut { path: path, source: self.loc });
|
||||
|
||||
debug!("gather_move({:?}, {:?}): adding move {:?} of {:?}",
|
||||
self.loc, place, move_out, path);
|
||||
debug!(
|
||||
"gather_move({:?}, {:?}): adding move {:?} of {:?}",
|
||||
self.loc, place, move_out, path
|
||||
);
|
||||
|
||||
self.builder.data.path_map[path].push(move_out);
|
||||
self.builder.data.loc_map[self.loc].push(move_out);
|
||||
|
|
@ -452,8 +454,10 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
kind,
|
||||
});
|
||||
|
||||
debug!("gather_init({:?}, {:?}): adding init {:?} of {:?}",
|
||||
self.loc, place, init, path);
|
||||
debug!(
|
||||
"gather_init({:?}, {:?}): adding init {:?} of {:?}",
|
||||
self.loc, place, init, path
|
||||
);
|
||||
|
||||
self.builder.data.init_path_map[path].push(init);
|
||||
self.builder.data.init_loc_map[self.loc].push(init);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
use rustc::ty::{Ty, TyCtxt};
|
||||
use core::slice::Iter;
|
||||
use rustc::mir::*;
|
||||
use rustc::ty::{Ty, TyCtxt};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
|
||||
use rustc_data_structures::indexed_vec::{Enumerated, Idx, IndexVec};
|
||||
use smallvec::SmallVec;
|
||||
use syntax_pos::{Span};
|
||||
use syntax_pos::Span;
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
|
@ -137,12 +138,17 @@ impl<T> IndexMut<Location> for LocationMap<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> LocationMap<T> where T: Default + Clone {
|
||||
impl<T> LocationMap<T>
|
||||
where
|
||||
T: Default + Clone,
|
||||
{
|
||||
fn new(body: &Body<'_>) -> Self {
|
||||
LocationMap {
|
||||
map: body.basic_blocks().iter().map(|block| {
|
||||
vec![T::default(); block.statements.len()+1]
|
||||
}).collect()
|
||||
map: body
|
||||
.basic_blocks()
|
||||
.iter()
|
||||
.map(|block| vec![T::default(); block.statements.len() + 1])
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,7 +184,6 @@ pub struct Init {
|
|||
pub kind: InitKind,
|
||||
}
|
||||
|
||||
|
||||
/// Initializations can be from an argument or from a statement. Arguments
|
||||
/// do not have locations, in those cases the `Local` is kept..
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
|
@ -224,7 +229,7 @@ pub struct MovePathLookup {
|
|||
/// subsequent search so that it is solely relative to that
|
||||
/// base-place). For the remaining lookup, we map the projection
|
||||
/// elem to the associated MovePathIndex.
|
||||
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>
|
||||
projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex>,
|
||||
}
|
||||
|
||||
mod builder;
|
||||
|
|
@ -232,7 +237,7 @@ mod builder;
|
|||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum LookupResult {
|
||||
Exact(MovePathIndex),
|
||||
Parent(Option<MovePathIndex>)
|
||||
Parent(Option<MovePathIndex>),
|
||||
}
|
||||
|
||||
impl MovePathLookup {
|
||||
|
|
@ -262,6 +267,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)]
|
||||
|
|
@ -289,7 +300,7 @@ pub(crate) enum IllegalMoveOriginKind<'tcx> {
|
|||
InteriorOfTypeWithDestructor { container_ty: Ty<'tcx> },
|
||||
|
||||
/// Illegal move due to attempt to move out of a slice or array.
|
||||
InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool, },
|
||||
InteriorOfSliceOrArray { ty: Ty<'tcx>, is_index: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -318,11 +329,15 @@ impl<'tcx> MoveData<'tcx> {
|
|||
pub fn base_local(&self, mut mpi: MovePathIndex) -> Option<Local> {
|
||||
loop {
|
||||
let path = &self.move_paths[mpi];
|
||||
if let Place {
|
||||
base: PlaceBase::Local(l),
|
||||
projection: None,
|
||||
} = path.place { return Some(l); }
|
||||
if let Some(parent) = path.parent { mpi = parent; continue } else { return None }
|
||||
if let Place { base: PlaceBase::Local(l), projection: None } = path.place {
|
||||
return Some(l);
|
||||
}
|
||||
if let Some(parent) = path.parent {
|
||||
mpi = parent;
|
||||
continue;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue