rustc_mir_dataflow/impls/
borrowed_locals.rs
1use rustc_index::bit_set::DenseBitSet;
2use rustc_middle::mir::visit::Visitor;
3use rustc_middle::mir::*;
4
5use crate::{Analysis, GenKill};
6
7#[derive(Clone)]
15pub struct MaybeBorrowedLocals;
16
17impl MaybeBorrowedLocals {
18 pub(super) fn transfer_function<'a, T>(trans: &'a mut T) -> TransferFunction<'a, T> {
19 TransferFunction { trans }
20 }
21}
22
23impl<'tcx> Analysis<'tcx> for MaybeBorrowedLocals {
24 type Domain = DenseBitSet<Local>;
25 const NAME: &'static str = "maybe_borrowed_locals";
26
27 fn bottom_value(&self, body: &Body<'tcx>) -> Self::Domain {
28 DenseBitSet::new_empty(body.local_decls().len())
30 }
31
32 fn initialize_start_block(&self, _: &Body<'tcx>, _: &mut Self::Domain) {
33 }
35
36 fn apply_primary_statement_effect(
37 &mut self,
38 state: &mut Self::Domain,
39 statement: &Statement<'tcx>,
40 location: Location,
41 ) {
42 Self::transfer_function(state).visit_statement(statement, location);
43 }
44
45 fn apply_primary_terminator_effect<'mir>(
46 &mut self,
47 state: &mut Self::Domain,
48 terminator: &'mir Terminator<'tcx>,
49 location: Location,
50 ) -> TerminatorEdges<'mir, 'tcx> {
51 Self::transfer_function(state).visit_terminator(terminator, location);
52 terminator.edges()
53 }
54}
55
56pub(super) struct TransferFunction<'a, T> {
58 trans: &'a mut T,
59}
60
61impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
62where
63 T: GenKill<Local>,
64{
65 fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
66 self.super_statement(stmt, location);
67
68 if let StatementKind::StorageDead(local) = stmt.kind {
71 self.trans.kill(local);
72 }
73 }
74
75 fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
76 self.super_rvalue(rvalue, location);
77
78 match rvalue {
79 Rvalue::RawPtr(_, borrowed_place)
82 | Rvalue::Ref(_, BorrowKind::Mut { .. } | BorrowKind::Shared, borrowed_place) => {
83 if !borrowed_place.is_indirect() {
84 self.trans.gen_(borrowed_place.local);
85 }
86 }
87
88 Rvalue::Cast(..)
89 | Rvalue::Ref(_, BorrowKind::Fake(_), _)
90 | Rvalue::ShallowInitBox(..)
91 | Rvalue::Use(..)
92 | Rvalue::ThreadLocalRef(..)
93 | Rvalue::Repeat(..)
94 | Rvalue::Len(..)
95 | Rvalue::BinaryOp(..)
96 | Rvalue::NullaryOp(..)
97 | Rvalue::UnaryOp(..)
98 | Rvalue::Discriminant(..)
99 | Rvalue::Aggregate(..)
100 | Rvalue::CopyForDeref(..)
101 | Rvalue::WrapUnsafeBinder(..) => {}
102 }
103 }
104
105 fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
106 self.super_terminator(terminator, location);
107
108 match terminator.kind {
109 TerminatorKind::Drop { place: dropped_place, .. } => {
110 if !dropped_place.is_indirect() {
119 self.trans.gen_(dropped_place.local);
120 }
121 }
122
123 TerminatorKind::UnwindTerminate(_)
124 | TerminatorKind::Assert { .. }
125 | TerminatorKind::Call { .. }
126 | TerminatorKind::FalseEdge { .. }
127 | TerminatorKind::FalseUnwind { .. }
128 | TerminatorKind::CoroutineDrop
129 | TerminatorKind::Goto { .. }
130 | TerminatorKind::InlineAsm { .. }
131 | TerminatorKind::UnwindResume
132 | TerminatorKind::Return
133 | TerminatorKind::TailCall { .. }
134 | TerminatorKind::SwitchInt { .. }
135 | TerminatorKind::Unreachable
136 | TerminatorKind::Yield { .. } => {}
137 }
138 }
139}
140
141pub fn borrowed_locals(body: &Body<'_>) -> DenseBitSet<Local> {
143 struct Borrowed(DenseBitSet<Local>);
144
145 impl GenKill<Local> for Borrowed {
146 #[inline]
147 fn gen_(&mut self, elem: Local) {
148 self.0.gen_(elem)
149 }
150 #[inline]
151 fn kill(&mut self, _: Local) {
152 }
154 }
155
156 let mut borrowed = Borrowed(DenseBitSet::new_empty(body.local_decls.len()));
157 TransferFunction { trans: &mut borrowed }.visit_body(body);
158 borrowed.0
159}