rustc_borrowck/polonius/legacy/
loan_kills.rs1use 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 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs:102",
"rustc_borrowck::polonius::legacy::loan_kills",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs"),
::tracing_core::__macro_support::Option::Some(102u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::polonius::legacy::loan_kills"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("Recording `killed` facts for borrows of local={0:?} at location={1:?}",
local, location) as &dyn Value))])
});
} else { ; }
};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 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs:112",
"rustc_borrowck::polonius::legacy::loan_kills",
::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_borrowck/src/polonius/legacy/loan_kills.rs"),
::tracing_core::__macro_support::Option::Some(112u32),
::tracing_core::__macro_support::Option::Some("rustc_borrowck::polonius::legacy::loan_kills"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("Recording `killed` facts for borrows of innermost projected local={0:?} at location={1:?}",
local, location) as &dyn Value))])
});
} else { ; }
};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}