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/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
8/// to a given local. This analysis ignores fake borrows, so it should not be used by
9/// borrowck.
10///
11/// At present, this is used as a very limited form of alias analysis. For example,
12/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
13/// immovable coroutines.
14#[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        // bottom = unborrowed
29        DenseBitSet::new_empty(body.local_decls().len())
30    }
31
32    fn initialize_start_block(&self, _: &Body<'tcx>, _: &mut Self::Domain) {
33        // No locals are aliased on function entry
34    }
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
56/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
57pub(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        // When we reach a `StorageDead` statement, we can assume that any pointers to this memory
69        // are now invalid.
70        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            // We ignore fake borrows as these get removed after analysis and shouldn't effect
80            // the layout of generators.
81            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                // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut
111                // self` as a parameter. In the general case, a drop impl could launder that
112                // reference into the surrounding environment through a raw pointer, thus creating
113                // a valid `*mut` pointing to the dropped local. We are not yet willing to declare
114                // this particular case UB, so we must treat all dropped locals as mutably borrowed
115                // for now. See discussion on [#61069].
116                //
117                // [#61069]: https://github.com/rust-lang/rust/pull/61069
118                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
141/// The set of locals that are borrowed at some point in the MIR body.
142pub 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            // Ignore borrow invalidation.
153        }
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}