about summary refs log tree commit diff
path: root/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_borrowck/src/polonius/legacy/mod.rs')
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/mod.rs117
1 files changed, 78 insertions, 39 deletions
diff --git a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
index 9fccc00bdaf..60fd2afe63e 100644
--- a/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/mod.rs
@@ -3,16 +3,23 @@
 //! Will be removed in the future, once the in-tree `-Zpolonius=next` implementation reaches feature
 //! parity.
 
-use rustc_middle::mir::{Body, LocalKind, Location, START_BLOCK};
-use rustc_middle::ty::TyCtxt;
+use std::iter;
+
+use either::Either;
+use rustc_middle::mir::{Body, Local, LocalKind, Location, START_BLOCK};
+use rustc_middle::ty::{GenericArg, TyCtxt};
 use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
 use tracing::debug;
 
 use crate::borrow_set::BorrowSet;
+use crate::constraints::OutlivesConstraint;
 use crate::facts::{AllFacts, PoloniusRegionVid};
 use crate::location::LocationTable;
+use crate::type_check::MirTypeckRegionConstraints;
 use crate::type_check::free_region_relations::UniversalRegionRelations;
+use crate::universal_regions::UniversalRegions;
 
+mod accesses;
 mod loan_invalidations;
 mod loan_kills;
 
@@ -22,6 +29,8 @@ mod loan_kills;
 /// - CFG points and edges
 /// - loan kills
 /// - loan invalidations
+/// - access facts such as variable definitions, uses, drops, and path accesses
+/// - outlives constraints
 ///
 /// The rest of the facts are emitted during typeck and liveness.
 pub(crate) fn emit_facts<'tcx>(
@@ -30,34 +39,42 @@ pub(crate) fn emit_facts<'tcx>(
     location_table: &LocationTable,
     body: &Body<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    move_data: &MoveData<'_>,
-    universal_region_relations: &UniversalRegionRelations<'_>,
+    move_data: &MoveData<'tcx>,
+    universal_region_relations: &UniversalRegionRelations<'tcx>,
+    constraints: &MirTypeckRegionConstraints<'tcx>,
 ) {
-    let Some(all_facts) = all_facts else {
+    let Some(facts) = all_facts else {
         // We don't do anything if there are no facts to fill.
         return;
     };
     let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
-    emit_move_facts(all_facts, move_data, location_table, body);
-    emit_universal_region_facts(all_facts, borrow_set, universal_region_relations);
-    emit_cfg_and_loan_kills_facts(all_facts, tcx, location_table, body, borrow_set);
-    emit_loan_invalidations_facts(all_facts, tcx, location_table, body, borrow_set);
+    emit_move_facts(facts, body, location_table, move_data);
+    emit_universal_region_facts(facts, borrow_set, universal_region_relations);
+    loan_kills::emit_loan_kills(tcx, facts, body, location_table, borrow_set);
+    loan_invalidations::emit_loan_invalidations(tcx, facts, body, location_table, borrow_set);
+    accesses::emit_access_facts(
+        tcx,
+        facts,
+        body,
+        location_table,
+        move_data,
+        &universal_region_relations.universal_regions,
+    );
+    emit_outlives_facts(facts, location_table, constraints);
 }
 
 /// Emit facts needed for move/init analysis: moves and assignments.
 fn emit_move_facts(
-    all_facts: &mut AllFacts,
-    move_data: &MoveData<'_>,
-    location_table: &LocationTable,
+    facts: &mut AllFacts,
     body: &Body<'_>,
+    location_table: &LocationTable,
+    move_data: &MoveData<'_>,
 ) {
-    all_facts
-        .path_is_var
-        .extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
+    facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
 
     for (child, move_path) in move_data.move_paths.iter_enumerated() {
         if let Some(parent) = move_path.parent {
-            all_facts.child_path.push((child, parent));
+            facts.child_path.push((child, parent));
         }
     }
 
@@ -83,14 +100,14 @@ fn emit_move_facts(
                         // 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
+                        facts
                             .path_assigned_at_base
                             .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
+                    facts
                         .path_assigned_at_base
                         .push((init.path, location_table.mid_index(location)));
                 }
@@ -98,7 +115,7 @@ fn emit_move_facts(
             // Arguments are initialized on function entry
             InitLocation::Argument(local) => {
                 assert!(body.local_kind(local) == LocalKind::Arg);
-                all_facts.path_assigned_at_base.push((init.path, fn_entry_start));
+                facts.path_assigned_at_base.push((init.path, fn_entry_start));
             }
         }
     }
@@ -107,20 +124,20 @@ fn emit_move_facts(
         if body.local_kind(local) != LocalKind::Arg {
             // Non-arguments start out deinitialised; we simulate this with an
             // initial move:
-            all_facts.path_moved_at_base.push((path, fn_entry_start));
+            facts.path_moved_at_base.push((path, fn_entry_start));
         }
     }
 
     // moved_out_at
     // deinitialisation is assumed to always happen!
-    all_facts
+    facts
         .path_moved_at_base
         .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
 }
 
 /// Emit universal regions facts, and their relations.
 fn emit_universal_region_facts(
-    all_facts: &mut AllFacts,
+    facts: &mut AllFacts,
     borrow_set: &BorrowSet<'_>,
     universal_region_relations: &UniversalRegionRelations<'_>,
 ) {
@@ -131,7 +148,7 @@ fn emit_universal_region_facts(
     //   added to the existing number of loans, as if they succeeded them in the set.
     //
     let universal_regions = &universal_region_relations.universal_regions;
-    all_facts
+    facts
         .universal_region
         .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
     let borrow_count = borrow_set.len();
@@ -144,7 +161,7 @@ fn emit_universal_region_facts(
     for universal_region in universal_regions.universal_regions_iter() {
         let universal_region_idx = universal_region.index();
         let placeholder_loan_idx = borrow_count + universal_region_idx;
-        all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
+        facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
     }
 
     // 2: the universal region relations `outlives` constraints are emitted as
@@ -156,29 +173,51 @@ fn emit_universal_region_facts(
                      fr1={:?}, fr2={:?}",
                 fr1, fr2
             );
-            all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
+            facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
         }
     }
 }
 
-/// Emit facts about loan invalidations.
-fn emit_loan_invalidations_facts<'tcx>(
-    all_facts: &mut AllFacts,
+/// For every potentially drop()-touched region `region` in `local`'s type
+/// (`kind`), emit a `drop_of_var_derefs_origin(local, origin)` fact.
+pub(crate) fn emit_drop_facts<'tcx>(
     tcx: TyCtxt<'tcx>,
-    location_table: &LocationTable,
-    body: &Body<'tcx>,
-    borrow_set: &BorrowSet<'tcx>,
+    local: Local,
+    kind: &GenericArg<'tcx>,
+    universal_regions: &UniversalRegions<'tcx>,
+    all_facts: &mut Option<AllFacts>,
 ) {
-    loan_invalidations::emit_loan_invalidations(tcx, all_facts, location_table, body, borrow_set);
+    debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
+    let Some(facts) = all_facts.as_mut() else { return };
+    let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
+    tcx.for_each_free_region(kind, |drop_live_region| {
+        let region_vid = universal_regions.to_region_vid(drop_live_region);
+        facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
+    });
 }
 
-/// Emit facts about CFG points and edges, as well as locations where loans are killed.
-fn emit_cfg_and_loan_kills_facts<'tcx>(
-    all_facts: &mut AllFacts,
-    tcx: TyCtxt<'tcx>,
+/// Emit facts about the outlives constraints: the `subset` base relation, i.e. not a transitive
+/// closure.
+fn emit_outlives_facts<'tcx>(
+    facts: &mut AllFacts,
     location_table: &LocationTable,
-    body: &Body<'tcx>,
-    borrow_set: &BorrowSet<'tcx>,
+    constraints: &MirTypeckRegionConstraints<'tcx>,
 ) {
-    loan_kills::emit_loan_kills(tcx, all_facts, location_table, body, borrow_set);
+    facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
+        |constraint: &OutlivesConstraint<'_>| {
+            if let Some(from_location) = constraint.locations.from_location() {
+                Either::Left(iter::once((
+                    constraint.sup.into(),
+                    constraint.sub.into(),
+                    location_table.mid_index(from_location),
+                )))
+            } else {
+                Either::Right(
+                    location_table.all_points().map(move |location| {
+                        (constraint.sup.into(), constraint.sub.into(), location)
+                    }),
+                )
+            }
+        },
+    ));
 }