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
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::BinaryOp(..)
95 | Rvalue::NullaryOp(..)
96 | Rvalue::UnaryOp(..)
97 | Rvalue::Discriminant(..)
98 | Rvalue::Aggregate(..)
99 | Rvalue::CopyForDeref(..)
100 | Rvalue::WrapUnsafeBinder(..) => {}
101 }
102 }
103
104 fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
105 self.super_terminator(terminator, location);
106
107 match terminator.kind {
108 TerminatorKind::Drop { place: dropped_place, .. } => {
109 if !dropped_place.is_indirect() {
118 self.trans.gen_(dropped_place.local);
119 }
120 }
121
122 TerminatorKind::UnwindTerminate(_)
123 | TerminatorKind::Assert { .. }
124 | TerminatorKind::Call { .. }
125 | TerminatorKind::FalseEdge { .. }
126 | TerminatorKind::FalseUnwind { .. }
127 | TerminatorKind::CoroutineDrop
128 | TerminatorKind::Goto { .. }
129 | TerminatorKind::InlineAsm { .. }
130 | TerminatorKind::UnwindResume
131 | TerminatorKind::Return
132 | TerminatorKind::TailCall { .. }
133 | TerminatorKind::SwitchInt { .. }
134 | TerminatorKind::Unreachable
135 | TerminatorKind::Yield { .. } => {}
136 }
137 }
138}
139
140pub fn borrowed_locals(body: &Body<'_>) -> DenseBitSet<Local> {
142 struct Borrowed(DenseBitSet<Local>);
143
144 impl GenKill<Local> for Borrowed {
145 #[inline]
146 fn gen_(&mut self, elem: Local) {
147 self.0.gen_(elem)
148 }
149 #[inline]
150 fn kill(&mut self, _: Local) {
151 }
153 }
154
155 let mut borrowed = Borrowed(DenseBitSet::new_empty(body.local_decls.len()));
156 TransferFunction { trans: &mut borrowed }.visit_body(body);
157 borrowed.0
158}