]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
New upstream version 1.59.0+dfsg1
[rustc.git] / compiler / rustc_mir_dataflow / src / impls / borrowed_locals.rs
CommitLineData
c295e0f8 1use super::*;
2c00a5a8 2
a2a8927a 3use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis};
ba9703b0
XL
4use rustc_middle::mir::visit::Visitor;
5use rustc_middle::mir::*;
74b04a01
XL
6
7/// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
8/// to a given local.
9///
74b04a01
XL
10/// At present, this is used as a very limited form of alias analysis. For example,
11/// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
3c0e092e
XL
12/// immovable generators.
13pub struct MaybeBorrowedLocals {
74b04a01
XL
14 ignore_borrow_on_drop: bool,
15}
16
17impl MaybeBorrowedLocals {
18 /// A dataflow analysis that records whether a pointer or reference exists that may alias the
19 /// given local.
20 pub fn all_borrows() -> Self {
3c0e092e 21 MaybeBorrowedLocals { ignore_borrow_on_drop: false }
74b04a01 22 }
2c00a5a8
XL
23}
24
3c0e092e 25impl MaybeBorrowedLocals {
74b04a01
XL
26 /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
27 ///
28 /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
29 /// parameter. In the general case, a drop impl could launder that reference into the
30 /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
31 /// dropped local. We are not yet willing to declare this particular case UB, so we must treat
32 /// all dropped locals as mutably borrowed for now. See discussion on [#61069].
33 ///
34 /// In some contexts, we know that this borrow will never occur. For example, during
35 /// const-eval, custom drop glue cannot be run. Code that calls this should document the
36 /// assumptions that justify ignoring `Drop` terminators in this way.
37 ///
38 /// [#61069]: https://github.com/rust-lang/rust/pull/61069
39 pub fn unsound_ignore_borrow_on_drop(self) -> Self {
40 MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
2c00a5a8
XL
41 }
42
3c0e092e
XL
43 fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
44 TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
2c00a5a8
XL
45 }
46}
47
a2a8927a 48impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals {
1b1a35ee 49 type Domain = BitSet<Local>;
3c0e092e 50 const NAME: &'static str = "maybe_borrowed_locals";
74b04a01 51
1b1a35ee
XL
52 fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
53 // bottom = unborrowed
54 BitSet::new_empty(body.local_decls().len())
74b04a01
XL
55 }
56
1b1a35ee 57 fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
74b04a01
XL
58 // No locals are aliased on function entry
59 }
60}
61
a2a8927a 62impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
1b1a35ee
XL
63 type Idx = Local;
64
74b04a01
XL
65 fn statement_effect(
66 &self,
67 trans: &mut impl GenKill<Self::Idx>,
68 statement: &mir::Statement<'tcx>,
69 location: Location,
70 ) {
71 self.transfer_function(trans).visit_statement(statement, location);
dfeec247 72 }
74b04a01
XL
73
74 fn terminator_effect(
75 &self,
76 trans: &mut impl GenKill<Self::Idx>,
77 terminator: &mir::Terminator<'tcx>,
78 location: Location,
79 ) {
80 self.transfer_function(trans).visit_terminator(terminator, location);
2c00a5a8
XL
81 }
82
74b04a01
XL
83 fn call_return_effect(
84 &self,
85 _trans: &mut impl GenKill<Self::Idx>,
86 _block: mir::BasicBlock,
a2a8927a 87 _return_places: CallReturnPlaces<'_, 'tcx>,
74b04a01 88 ) {
2c00a5a8 89 }
74b04a01
XL
90}
91
74b04a01 92/// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
3c0e092e 93struct TransferFunction<'a, T> {
74b04a01 94 trans: &'a mut T,
74b04a01
XL
95 ignore_borrow_on_drop: bool,
96}
b7449926 97
a2a8927a 98impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
74b04a01
XL
99where
100 T: GenKill<Local>,
74b04a01
XL
101{
102 fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) {
103 self.super_statement(stmt, location);
b7449926 104
74b04a01
XL
105 // When we reach a `StorageDead` statement, we can assume that any pointers to this memory
106 // are now invalid.
107 if let StatementKind::StorageDead(local) = stmt.kind {
108 self.trans.kill(local);
b7449926 109 }
2c00a5a8
XL
110 }
111
74b04a01
XL
112 fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
113 self.super_rvalue(rvalue, location);
114
115 match rvalue {
3c0e092e
XL
116 mir::Rvalue::AddressOf(_mt, borrowed_place) => {
117 if !borrowed_place.is_indirect() {
74b04a01 118 self.trans.gen(borrowed_place.local);
dc9dc135
XL
119 }
120 }
74b04a01 121
3c0e092e
XL
122 mir::Rvalue::Ref(_, _kind, borrowed_place) => {
123 if !borrowed_place.is_indirect() {
74b04a01
XL
124 self.trans.gen(borrowed_place.local);
125 }
126 }
127
128 mir::Rvalue::Cast(..)
c295e0f8 129 | mir::Rvalue::ShallowInitBox(..)
74b04a01 130 | mir::Rvalue::Use(..)
f9f354fc 131 | mir::Rvalue::ThreadLocalRef(..)
74b04a01
XL
132 | mir::Rvalue::Repeat(..)
133 | mir::Rvalue::Len(..)
134 | mir::Rvalue::BinaryOp(..)
135 | mir::Rvalue::CheckedBinaryOp(..)
136 | mir::Rvalue::NullaryOp(..)
137 | mir::Rvalue::UnaryOp(..)
138 | mir::Rvalue::Discriminant(..)
139 | mir::Rvalue::Aggregate(..) => {}
dc9dc135 140 }
2c00a5a8
XL
141 }
142
74b04a01
XL
143 fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
144 self.super_terminator(terminator, location);
145
146 match terminator.kind {
f035d41b
XL
147 mir::TerminatorKind::Drop { place: dropped_place, .. }
148 | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
74b04a01
XL
149 // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
150 if !self.ignore_borrow_on_drop {
151 self.trans.gen(dropped_place.local);
152 }
153 }
154
155 TerminatorKind::Abort
156 | TerminatorKind::Assert { .. }
157 | TerminatorKind::Call { .. }
f035d41b 158 | TerminatorKind::FalseEdge { .. }
74b04a01
XL
159 | TerminatorKind::FalseUnwind { .. }
160 | TerminatorKind::GeneratorDrop
161 | TerminatorKind::Goto { .. }
f9f354fc 162 | TerminatorKind::InlineAsm { .. }
74b04a01
XL
163 | TerminatorKind::Resume
164 | TerminatorKind::Return
165 | TerminatorKind::SwitchInt { .. }
166 | TerminatorKind::Unreachable
167 | TerminatorKind::Yield { .. } => {}
168 }
2c00a5a8
XL
169 }
170}