diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2019-10-04 07:24:33 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-04 07:24:33 +0200 |
| commit | 314fbf48cf15bcddea29e17158996a56326aa264 (patch) | |
| tree | c869cec100115cc308f01b0cf256c261a878b5da /src/librustc_mir/borrow_check | |
| parent | 31d75c4e9c5318e880601d3c2cc71e5df094a120 (diff) | |
| parent | 2180c243214ebce29c45c37020e929924a8520d8 (diff) | |
| download | rust-314fbf48cf15bcddea29e17158996a56326aa264.tar.gz rust-314fbf48cf15bcddea29e17158996a56326aa264.zip | |
Rollup merge of #64749 - matthewjasper:liveness-opt, r=nikomatsakis
Fix most remaining Polonius test differences This fixes most of the Polonius test differences and also avoids overflow in issue-38591.rs. r? @nikomatsakis
Diffstat (limited to 'src/librustc_mir/borrow_check')
5 files changed, 118 insertions, 50 deletions
diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs index 7689ece7066..7dee00b3eca 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs @@ -70,6 +70,10 @@ impl LocalUseMap { appearances: IndexVec::new(), }; + if live_locals.is_empty() { + return local_use_map; + } + 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); diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs index 3f2ec1ba970..a01b528833b 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs @@ -36,31 +36,39 @@ pub(super) fn generate<'tcx>( ) { debug!("liveness::generate"); - let live_locals: Vec<Local> = if AllFacts::enabled(typeck.tcx()) { - // If "dump facts from NLL analysis" was requested perform - // the liveness analysis for all `Local`s. This case opens - // the possibility of the variables being analyzed in `trace` - // to be *any* `Local`, not just the "live" ones, so we can't - // make any assumptions past this point as to the characteristics - // of the `live_locals`. - // FIXME: Review "live" terminology past this point, we should - // not be naming the `Local`s as live. - body.local_decls.indices().collect() + let free_regions = regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.borrowck_context.universal_regions, + &typeck.borrowck_context.constraints.outlives_constraints, + ); + let live_locals = compute_live_locals(typeck.tcx(), &free_regions, body); + let facts_enabled = AllFacts::enabled(typeck.tcx()); + + + let polonius_drop_used = if facts_enabled { + let mut drop_used = Vec::new(); + polonius::populate_access_facts( + typeck, + body, + location_table, + move_data, + &mut drop_used, + ); + Some(drop_used) } else { - let free_regions = { - regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &typeck.borrowck_context.universal_regions, - &typeck.borrowck_context.constraints.outlives_constraints, - ) - }; - compute_live_locals(typeck.tcx(), &free_regions, body) + None }; - if !live_locals.is_empty() { - trace::trace(typeck, body, elements, flow_inits, move_data, live_locals); - - polonius::populate_access_facts(typeck, body, location_table, move_data); + if !live_locals.is_empty() || facts_enabled { + trace::trace( + typeck, + body, + elements, + flow_inits, + move_data, + live_locals, + polonius_drop_used, + ); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs index e37ddbda4be..526ad7fb905 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs @@ -16,7 +16,7 @@ struct UseFactsExtractor<'me> { var_defined: &'me mut VarPointRelations, var_used: &'me mut VarPointRelations, location_table: &'me LocationTable, - var_drop_used: &'me mut VarPointRelations, + var_drop_used: &'me mut Vec<(Local, Location)>, move_data: &'me MoveData<'me>, path_accessed_at: &'me mut MovePathPointRelations, } @@ -39,7 +39,7 @@ impl UseFactsExtractor<'_> { 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))); + self.var_drop_used.push((local, location)); } fn insert_path_access(&mut self, path: MovePathIndex, location: Location) { @@ -100,6 +100,7 @@ pub(super) fn populate_access_facts( body: &Body<'tcx>, location_table: &LocationTable, move_data: &MoveData<'_>, + drop_used: &mut Vec<(Local, Location)>, ) { debug!("populate_var_liveness_facts()"); @@ -107,12 +108,16 @@ pub(super) fn populate_access_facts( UseFactsExtractor { var_defined: &mut facts.var_defined, var_used: &mut facts.var_used, - var_drop_used: &mut facts.var_drop_used, + var_drop_used: drop_used, path_accessed_at: &mut facts.path_accessed_at, location_table, move_data, } .visit_body(body); + + facts.var_drop_used.extend(drop_used.iter().map(|&(local, location)| { + (local, location_table.mid_index(location)) + })); } for (local, local_decl) in body.local_decls.iter_enumerated() { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 36482a7b135..eacc4d084db 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -13,7 +13,7 @@ use rustc::traits::query::type_op::outlives::DropckOutlives; use rustc::traits::query::type_op::TypeOp; use rustc::ty::{Ty, TypeFoldable}; use rustc_index::bit_set::HybridBitSet; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use std::rc::Rc; /// This is the heart of the liveness computation. For each variable X @@ -37,6 +37,7 @@ pub(super) fn trace( flow_inits: &mut FlowAtLocation<'tcx, MaybeInitializedPlaces<'_, 'tcx>>, move_data: &MoveData<'tcx>, live_locals: Vec<Local>, + polonius_drop_used: Option<Vec<(Local, Location)>>, ) { debug!("trace()"); @@ -52,7 +53,13 @@ pub(super) fn trace( drop_data: FxHashMap::default(), }; - LivenessResults::new(cx).compute_for_all_locals(live_locals); + let mut results = LivenessResults::new(cx); + + if let Some(drop_used) = polonius_drop_used { + results.add_extra_drop_facts(drop_used, live_locals.iter().copied().collect()) + } + + results.compute_for_all_locals(live_locals); } /// Contextual state for the type-liveness generator. @@ -145,6 +152,32 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } + /// Add extra drop facts needed for Polonius. + /// + /// Add facts for all locals with free regions, since regions may outlive + /// the function body only at certain nodes in the CFG. + fn add_extra_drop_facts( + &mut self, + drop_used: Vec<(Local, Location)>, + live_locals: FxHashSet<Local>, + ) { + let locations = HybridBitSet::new_empty(self.cx.elements.num_points()); + + for (local, location) in drop_used { + if !live_locals.contains(&local) { + let local_ty = self.cx.body.local_decls[local].ty; + if local_ty.has_free_regions() { + self.cx.add_drop_live_facts_for( + local, + local_ty, + &[location], + &locations, + ); + } + } + } + } + /// Clear the value of fields that are "per local variable". fn reset_local_state(&mut self) { self.defs.clear(); diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index b24ba596d7e..adc3381a1e7 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -276,7 +276,17 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) { self.super_constant(constant, location); - self.sanitize_type(constant, constant.literal.ty); + let ty = self.sanitize_type(constant, constant.literal.ty); + + self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| { + let live_region_vid = + self.cx.borrowck_context.universal_regions.to_region_vid(live_region); + self.cx + .borrowck_context + .constraints + .liveness_constraints + .add_element(live_region_vid, location); + }); if let Some(annotation_index) = constant.user_ty { if let Err(terr) = self.cx.relate_type_and_user_type( @@ -528,25 +538,37 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let parent_body = mem::replace(&mut self.body, promoted_body); + // Use new sets of constraints and closure bounds so that we can + // modify their locations. let all_facts = &mut None; let mut constraints = Default::default(); let mut closure_bounds = Default::default(); + let mut liveness_constraints = LivenessValues::new( + Rc::new(RegionValueElements::new(promoted_body)), + ); // Don't try to add borrow_region facts for the promoted MIR - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - // Use a new sets of constraints and closure bounds so that we can - // modify their locations. - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + let mut swap_constraints = |this: &mut Self| { + mem::swap(this.cx.borrowck_context.all_facts, all_facts); + mem::swap( + &mut this.cx.borrowck_context.constraints.outlives_constraints, + &mut constraints + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, + &mut closure_bounds + ); + mem::swap( + &mut this.cx.borrowck_context.constraints.liveness_constraints, + &mut liveness_constraints + ); + }; + + swap_constraints(self); self.visit_body(promoted_body); + if !self.errors_reported { // if verifier failed, don't do further checks to avoid ICEs self.cx.typeck_mir(promoted_body); @@ -554,23 +576,15 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { self.body = parent_body; // Merge the outlives constraints back in, at the given location. - mem::swap(self.cx.borrowck_context.all_facts, all_facts); - mem::swap( - &mut self.cx.borrowck_context.constraints.outlives_constraints, - &mut constraints - ); - mem::swap( - &mut self.cx.borrowck_context.constraints.closure_bounds_mapping, - &mut closure_bounds - ); + swap_constraints(self); let locations = location.to_locations(); for constraint in constraints.outlives().iter() { let mut constraint = *constraint; constraint.locations = locations; if let ConstraintCategory::Return - | ConstraintCategory::UseAsConst - | ConstraintCategory::UseAsStatic = constraint.category + | ConstraintCategory::UseAsConst + | ConstraintCategory::UseAsStatic = constraint.category { // "Returning" from a promoted is an assigment to a // temporary from the user's point of view. @@ -578,6 +592,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } + for live_region in liveness_constraints.rows() { + self.cx.borrowck_context.constraints.liveness_constraints + .add_element(live_region, location); + } if !closure_bounds.is_empty() { let combined_bounds_mapping = closure_bounds |
