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