rustc_borrowck/polonius/legacy/
mod.rs
1use std::iter;
7
8use either::Either;
9use rustc_middle::mir::{Body, Local, LocalKind, Location, START_BLOCK};
10use rustc_middle::ty::{GenericArg, TyCtxt};
11use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
12use tracing::debug;
13
14use crate::borrow_set::BorrowSet;
15use crate::constraints::OutlivesConstraint;
16use crate::type_check::MirTypeckRegionConstraints;
17use crate::type_check::free_region_relations::UniversalRegionRelations;
18use crate::universal_regions::UniversalRegions;
19
20mod accesses;
21mod loan_invalidations;
22mod loan_kills;
23mod location;
24pub use self::location::*;
25mod facts;
26pub use self::facts::*;
27
28pub(crate) fn emit_facts<'tcx>(
39 facts: &mut Option<PoloniusFacts>,
40 tcx: TyCtxt<'tcx>,
41 location_table: &PoloniusLocationTable,
42 body: &Body<'tcx>,
43 borrow_set: &BorrowSet<'tcx>,
44 move_data: &MoveData<'tcx>,
45 universal_region_relations: &UniversalRegionRelations<'tcx>,
46 constraints: &MirTypeckRegionConstraints<'tcx>,
47) {
48 let Some(facts) = facts else {
49 return;
51 };
52 let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
53 emit_move_facts(facts, body, location_table, move_data);
54 emit_universal_region_facts(facts, borrow_set, universal_region_relations);
55 loan_kills::emit_loan_kills(tcx, facts, body, location_table, borrow_set);
56 loan_invalidations::emit_loan_invalidations(tcx, facts, body, location_table, borrow_set);
57 accesses::emit_access_facts(
58 tcx,
59 facts,
60 body,
61 location_table,
62 move_data,
63 &universal_region_relations.universal_regions,
64 );
65 emit_outlives_facts(facts, location_table, constraints);
66}
67
68fn emit_move_facts(
70 facts: &mut PoloniusFacts,
71 body: &Body<'_>,
72 location_table: &PoloniusLocationTable,
73 move_data: &MoveData<'_>,
74) {
75 facts.path_is_var.extend(move_data.rev_lookup.iter_locals_enumerated().map(|(l, r)| (r, l)));
76
77 for (child, move_path) in move_data.move_paths.iter_enumerated() {
78 if let Some(parent) = move_path.parent {
79 facts.child_path.push((child, parent));
80 }
81 }
82
83 let fn_entry_start =
84 location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
85
86 for init in move_data.inits.iter() {
88 match init.location {
89 InitLocation::Statement(location) => {
90 let block_data = &body[location.block];
91 let is_terminator = location.statement_index == block_data.statements.len();
92
93 if is_terminator && init.kind == InitKind::NonPanicPathOnly {
94 for successor in block_data.terminator().successors() {
98 if body[successor].is_cleanup {
99 continue;
100 }
101
102 let first_statement = Location { block: successor, statement_index: 0 };
105 facts
106 .path_assigned_at_base
107 .push((init.path, location_table.start_index(first_statement)));
108 }
109 } else {
110 facts
113 .path_assigned_at_base
114 .push((init.path, location_table.mid_index(location)));
115 }
116 }
117 InitLocation::Argument(local) => {
119 assert!(body.local_kind(local) == LocalKind::Arg);
120 facts.path_assigned_at_base.push((init.path, fn_entry_start));
121 }
122 }
123 }
124
125 for (local, path) in move_data.rev_lookup.iter_locals_enumerated() {
126 if body.local_kind(local) != LocalKind::Arg {
127 facts.path_moved_at_base.push((path, fn_entry_start));
130 }
131 }
132
133 facts
136 .path_moved_at_base
137 .extend(move_data.moves.iter().map(|mo| (mo.path, location_table.mid_index(mo.source))));
138}
139
140fn emit_universal_region_facts(
142 facts: &mut PoloniusFacts,
143 borrow_set: &BorrowSet<'_>,
144 universal_region_relations: &UniversalRegionRelations<'_>,
145) {
146 let universal_regions = &universal_region_relations.universal_regions;
153 facts
154 .universal_region
155 .extend(universal_regions.universal_regions_iter().map(PoloniusRegionVid::from));
156 let borrow_count = borrow_set.len();
157 debug!(
158 "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
159 universal_regions.len(),
160 borrow_count
161 );
162
163 for universal_region in universal_regions.universal_regions_iter() {
164 let universal_region_idx = universal_region.index();
165 let placeholder_loan_idx = borrow_count + universal_region_idx;
166 facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
167 }
168
169 for (fr1, fr2) in universal_region_relations.known_outlives() {
172 if fr1 != fr2 {
173 debug!(
174 "emit_universal_region_facts: emitting polonius `known_placeholder_subset` \
175 fr1={:?}, fr2={:?}",
176 fr1, fr2
177 );
178 facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
179 }
180 }
181}
182
183pub(crate) fn emit_drop_facts<'tcx>(
186 tcx: TyCtxt<'tcx>,
187 local: Local,
188 kind: &GenericArg<'tcx>,
189 universal_regions: &UniversalRegions<'tcx>,
190 facts: &mut Option<PoloniusFacts>,
191) {
192 debug!("emit_drop_facts(local={:?}, kind={:?}", local, kind);
193 let Some(facts) = facts.as_mut() else { return };
194 let _prof_timer = tcx.prof.generic_activity("polonius_fact_generation");
195 tcx.for_each_free_region(kind, |drop_live_region| {
196 let region_vid = universal_regions.to_region_vid(drop_live_region);
197 facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
198 });
199}
200
201fn emit_outlives_facts<'tcx>(
204 facts: &mut PoloniusFacts,
205 location_table: &PoloniusLocationTable,
206 constraints: &MirTypeckRegionConstraints<'tcx>,
207) {
208 facts.subset_base.extend(constraints.outlives_constraints.outlives().iter().flat_map(
209 |constraint: &OutlivesConstraint<'_>| {
210 if let Some(from_location) = constraint.locations.from_location() {
211 Either::Left(iter::once((
212 constraint.sup.into(),
213 constraint.sub.into(),
214 location_table.mid_index(from_location),
215 )))
216 } else {
217 Either::Right(
218 location_table.all_points().map(move |location| {
219 (constraint.sup.into(), constraint.sub.into(), location)
220 }),
221 )
222 }
223 },
224 ));
225}