]>
Commit | Line | Data |
---|---|---|
c295e0f8 | 1 | use super::*; |
2c00a5a8 | 2 | |
a2a8927a | 3 | use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis}; |
ba9703b0 XL |
4 | use rustc_middle::mir::visit::Visitor; |
5 | use 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. |
13 | pub struct MaybeBorrowedLocals { | |
74b04a01 XL |
14 | ignore_borrow_on_drop: bool, |
15 | } | |
16 | ||
17 | impl 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 | 25 | impl 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 | 48 | impl<'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 | 62 | impl<'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 | 93 | struct TransferFunction<'a, T> { |
74b04a01 | 94 | trans: &'a mut T, |
74b04a01 XL |
95 | ignore_borrow_on_drop: bool, |
96 | } | |
b7449926 | 97 | |
a2a8927a | 98 | impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> |
74b04a01 XL |
99 | where |
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 | } |