about summary refs log tree commit diff
path: root/src/librustc_mir/borrow_check
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-10-04 07:24:33 +0200
committerGitHub <noreply@github.com>2019-10-04 07:24:33 +0200
commit314fbf48cf15bcddea29e17158996a56326aa264 (patch)
treec869cec100115cc308f01b0cf256c261a878b5da /src/librustc_mir/borrow_check
parent31d75c4e9c5318e880601d3c2cc71e5df094a120 (diff)
parent2180c243214ebce29c45c37020e929924a8520d8 (diff)
downloadrust-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')
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/local_use_map.rs4
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/mod.rs52
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs11
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs37
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs64
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