rustc_borrowck/polonius/legacy/
loan_kills.rs
1use rustc_middle::mir::visit::Visitor;
2use rustc_middle::mir::{
3 Body, Local, Location, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind,
4 Terminator, TerminatorKind,
5};
6use rustc_middle::ty::TyCtxt;
7use tracing::debug;
8
9use super::{PoloniusFacts, PoloniusLocationTable};
10use crate::borrow_set::BorrowSet;
11use crate::places_conflict;
12
13pub(super) fn emit_loan_kills<'tcx>(
15 tcx: TyCtxt<'tcx>,
16 facts: &mut PoloniusFacts,
17 body: &Body<'tcx>,
18 location_table: &PoloniusLocationTable,
19 borrow_set: &BorrowSet<'tcx>,
20) {
21 let mut visitor = LoanKillsGenerator { borrow_set, tcx, location_table, facts, body };
22 for (bb, data) in body.basic_blocks.iter_enumerated() {
23 visitor.visit_basic_block_data(bb, data);
24 }
25}
26
27struct LoanKillsGenerator<'a, 'tcx> {
28 tcx: TyCtxt<'tcx>,
29 facts: &'a mut PoloniusFacts,
30 location_table: &'a PoloniusLocationTable,
31 borrow_set: &'a BorrowSet<'tcx>,
32 body: &'a Body<'tcx>,
33}
34
35impl<'a, 'tcx> Visitor<'tcx> for LoanKillsGenerator<'a, 'tcx> {
36 fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
37 self.facts.cfg_edge.push((
39 self.location_table.start_index(location),
40 self.location_table.mid_index(location),
41 ));
42
43 self.facts.cfg_edge.push((
44 self.location_table.mid_index(location),
45 self.location_table.start_index(location.successor_within_block()),
46 ));
47
48 if let StatementKind::StorageDead(local) = statement.kind {
50 self.record_killed_borrows_for_local(local, location);
51 }
52
53 self.super_statement(statement, location);
54 }
55
56 fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) {
57 self.record_killed_borrows_for_place(*place, location);
60 self.super_assign(place, rvalue, location);
61 }
62
63 fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
64 self.facts.cfg_edge.push((
66 self.location_table.start_index(location),
67 self.location_table.mid_index(location),
68 ));
69
70 let successor_blocks = terminator.successors();
71 self.facts.cfg_edge.reserve(successor_blocks.size_hint().0);
72 for successor_block in successor_blocks {
73 self.facts.cfg_edge.push((
74 self.location_table.mid_index(location),
75 self.location_table.start_index(successor_block.start_location()),
76 ));
77 }
78
79 if let TerminatorKind::Call { destination, .. } = terminator.kind {
82 self.record_killed_borrows_for_place(destination, location);
83 }
84
85 self.super_terminator(terminator, location);
86 }
87}
88
89impl<'tcx> LoanKillsGenerator<'_, 'tcx> {
90 fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) {
93 match place.as_ref() {
100 PlaceRef { local, projection: &[] }
101 | PlaceRef { local, projection: &[ProjectionElem::Deref] } => {
102 debug!(
103 "Recording `killed` facts for borrows of local={:?} at location={:?}",
104 local, location
105 );
106
107 self.record_killed_borrows_for_local(local, location);
108 }
109
110 PlaceRef { local, projection: &[.., _] } => {
111 debug!(
113 "Recording `killed` facts for borrows of \
114 innermost projected local={:?} at location={:?}",
115 local, location
116 );
117
118 if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
119 for &borrow_index in borrow_indices {
120 let places_conflict = places_conflict::places_conflict(
121 self.tcx,
122 self.body,
123 self.borrow_set[borrow_index].borrowed_place,
124 place,
125 places_conflict::PlaceConflictBias::NoOverlap,
126 );
127
128 if places_conflict {
129 let location_index = self.location_table.mid_index(location);
130 self.facts.loan_killed_at.push((borrow_index, location_index));
131 }
132 }
133 }
134 }
135 }
136 }
137
138 fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) {
140 if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) {
141 let location_index = self.location_table.mid_index(location);
142 self.facts.loan_killed_at.reserve(borrow_indices.len());
143 for &borrow_index in borrow_indices {
144 self.facts.loan_killed_at.push((borrow_index, location_index));
145 }
146 }
147 }
148}