]> git.lizzy.rs Git - rust.git/commitdiff
Polonius: emit initialization/move tracking facts
authorAlbin Stjerna <albin.stjerna@gmail.com>
Fri, 19 Jul 2019 13:38:54 +0000 (15:38 +0200)
committerAlbin Stjerna <albin.stjerna@gmail.com>
Wed, 4 Sep 2019 07:46:44 +0000 (09:46 +0200)
- var_starts_path
- parent
- initialized_at
- moved_out_at

This also switches to the intended emission of `var_drop_used` fact emission,
where that fact is always emitted on a drop-use of a variable, regardless of its
initialization status, as Polonius now handles that.

src/librustc_mir/borrow_check/nll/mod.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/polonius.rs
src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs
src/librustc_mir/dataflow/move_paths/mod.rs

index 19a3d0eb03d561c22a44b7a240c072b6a8ac71f0..9b920eb15599dd968789884afc18d05e465b7f01 100644 (file)
@@ -4,14 +4,14 @@
 use crate::borrow_check::nll::type_check::{MirTypeckResults, MirTypeckRegionConstraints};
 use crate::borrow_check::nll::region_infer::values::RegionValueElements;
 use crate::dataflow::indexes::BorrowIndex;
-use crate::dataflow::move_paths::{MoveData, MovePathIndex};
+use crate::dataflow::move_paths::{InitLocation, MoveData, MovePathIndex, InitKind};
 use crate::dataflow::FlowAtLocation;
 use crate::dataflow::MaybeInitializedPlaces;
 use crate::transform::MirSource;
 use crate::borrow_check::Upvar;
 use rustc::hir::def_id::DefId;
 use rustc::infer::InferCtxt;
-use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Body, Promoted};
+use rustc::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, Local, Location, Body, LocalKind, BasicBlock, Promoted};
 use rustc::ty::{self, RegionKind, RegionVid};
 use rustc_data_structures::indexed_vec::IndexVec;
 use rustc_errors::Diagnostic;
@@ -69,6 +69,61 @@ pub(in crate::borrow_check) fn replace_regions_in_mir<'cx, 'tcx>(
     universal_regions
 }
 
+
+// This function populates an AllFacts instance with base facts related to
+// MovePaths and needed for the move analysis.
+fn populate_polonius_move_facts(all_facts: &mut AllFacts, move_data: &MoveData<'_>, location_table: &LocationTable, body: &Body<'_>) {
+    all_facts.var_starts_path.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(v, &m)| (v, m)));
+
+    for (idx, move_path) in move_data.move_paths.iter_enumerated() {
+        all_facts.parent.extend(move_path.parents(&move_data.move_paths).iter().map(|&parent| (parent, idx)));
+    }
+
+    // initialized_at
+    for init in move_data.inits.iter() {
+
+        match init.location {
+            InitLocation::Statement(location) => {
+                let block_data = &body[location.block];
+                let is_terminator = location.statement_index == block_data.statements.len();
+
+                if is_terminator && init.kind == InitKind::NonPanicPathOnly {
+                    // We are at the terminator of an init that has a panic path,
+                    // and where the init should not happen on panic
+
+                    for &successor in block_data.terminator().successors() {
+                        if body[successor].is_cleanup {
+                            continue;
+                        }
+
+                        // The initialization happened in (or rather, when arriving at)
+                        // the successors, but not in the unwind block.
+                        let first_statement = Location { block: successor, statement_index: 0};
+                        all_facts.initialized_at.push((init.path, location_table.start_index(first_statement)));
+                    }
+
+                } else {
+                    // In all other cases, the initialization just happens at the
+                    // midpoint, like any other effect.
+                    all_facts.initialized_at.push((init.path, location_table.mid_index(location)));
+                }
+            },
+            // Arguments are initialized on function entry
+            InitLocation::Argument(local) => {
+                assert!(body.local_kind(local) == LocalKind::Arg);
+                let fn_entry = Location {block: BasicBlock::from_u32(0u32), statement_index: 0 };
+                all_facts.initialized_at.push((init.path, location_table.start_index(fn_entry)));
+
+            }
+        }
+    }
+
+
+    // moved_out_at
+    // deinitialisation is assumed to always happen!
+    all_facts.moved_out_at.extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
+}
+
 /// Computes the (non-lexical) regions from the input MIR.
 ///
 /// This may result in errors being reported.
@@ -123,6 +178,7 @@ pub(in crate::borrow_check) fn compute_regions<'cx, 'tcx>(
         all_facts
             .universal_region
             .extend(universal_regions.universal_regions());
+        populate_polonius_move_facts(all_facts, move_data, location_table, body);
     }
 
     // Create the region inference context, taking ownership of the
index 20d7ec55e3e84f0330bd9af69b5ad15f8854b493..dcdacbbe5be06b5a7b07d86ac737ffe1191b375b 100644 (file)
@@ -13,6 +13,7 @@ struct LivenessPointFactsExtractor<'me> {
     var_defined: &'me mut VarPointRelations,
     var_used: &'me mut VarPointRelations,
     location_table: &'me LocationTable,
+    var_drop_used: &'me mut VarPointRelations,
 }
 
 // A Visitor to walk through the MIR and extract point-wise facts
@@ -30,6 +31,11 @@ fn insert_use(&mut self, local: Local, location: Location) {
         debug!("LivenessFactsExtractor::insert_use()");
         self.var_used.push((local, self.location_to_index(location)));
     }
+
+    fn insert_drop_use(&mut self, local: Local, location: Location) {
+        debug!("LivenessFactsExtractor::insert_drop_use()");
+        self.var_drop_used.push((local, self.location_to_index(location)));
+    }
 }
 
 impl Visitor<'tcx> for LivenessPointFactsExtractor<'_> {
@@ -37,8 +43,8 @@ fn visit_local(&mut self, &local: &Local, context: PlaceContext, location: Locat
         match categorize(context) {
             Some(DefUse::Def) => self.insert_def(local, location),
             Some(DefUse::Use) => self.insert_use(local, location),
+            Some(DefUse::Drop) => self.insert_drop_use(local, location),
             _ => (),
-            // NOTE: Drop handling is now done in trace()
         }
     }
 }
@@ -65,6 +71,7 @@ pub(super) fn populate_var_liveness_facts(
         LivenessPointFactsExtractor {
             var_defined: &mut facts.var_defined,
             var_used: &mut facts.var_used,
+            var_drop_used: &mut facts.var_drop_used,
             location_table,
         }
         .visit_body(mir);
index de085fc480a0ef08fe5808c30d46f4300b919bb5..1e1768a8e460177925a227505b2c79bcdd08f8bf 100644 (file)
@@ -273,11 +273,6 @@ fn compute_drop_live_points_for(&mut self, local: Local) {
             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);
index e5a19572170a7053856a8e5e04e2cc113cefbc22..07b9b662a07aa89db9b10a451796aedb0e8056b0 100644 (file)
@@ -1,9 +1,10 @@
 use rustc::ty::{Ty, TyCtxt};
 use rustc::mir::*;
 use rustc::util::nodemap::FxHashMap;
-use rustc_data_structures::indexed_vec::{Idx, IndexVec};
+use rustc_data_structures::indexed_vec::{Idx, IndexVec, Enumerated};
 use smallvec::SmallVec;
 use syntax_pos::{Span};
+use core::slice::Iter;
 
 use std::fmt;
 use std::ops::{Index, IndexMut};
@@ -262,6 +263,12 @@ pub fn find(&self, place_ref: PlaceRef<'_, '_>) -> LookupResult {
     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)]