diff options
Diffstat (limited to 'compiler/rustc_borrowck/src/polonius/legacy/mod.rs')
| -rw-r--r-- | compiler/rustc_borrowck/src/polonius/legacy/mod.rs | 117 |
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) + }), + ) + } + }, + )); } |
