]>
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 | 12 | /// immovable generators. |
5e7ed085 | 13 | pub struct MaybeBorrowedLocals; |
2c00a5a8 | 14 | |
3c0e092e | 15 | impl MaybeBorrowedLocals { |
3c0e092e | 16 | fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> { |
5e7ed085 | 17 | TransferFunction { trans } |
2c00a5a8 XL |
18 | } |
19 | } | |
20 | ||
a2a8927a | 21 | impl<'tcx> AnalysisDomain<'tcx> for MaybeBorrowedLocals { |
1b1a35ee | 22 | type Domain = BitSet<Local>; |
3c0e092e | 23 | const NAME: &'static str = "maybe_borrowed_locals"; |
74b04a01 | 24 | |
1b1a35ee XL |
25 | fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain { |
26 | // bottom = unborrowed | |
27 | BitSet::new_empty(body.local_decls().len()) | |
74b04a01 XL |
28 | } |
29 | ||
1b1a35ee | 30 | fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { |
74b04a01 XL |
31 | // No locals are aliased on function entry |
32 | } | |
33 | } | |
34 | ||
a2a8927a | 35 | impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals { |
1b1a35ee XL |
36 | type Idx = Local; |
37 | ||
74b04a01 XL |
38 | fn statement_effect( |
39 | &self, | |
40 | trans: &mut impl GenKill<Self::Idx>, | |
41 | statement: &mir::Statement<'tcx>, | |
42 | location: Location, | |
43 | ) { | |
44 | self.transfer_function(trans).visit_statement(statement, location); | |
dfeec247 | 45 | } |
74b04a01 XL |
46 | |
47 | fn terminator_effect( | |
48 | &self, | |
49 | trans: &mut impl GenKill<Self::Idx>, | |
50 | terminator: &mir::Terminator<'tcx>, | |
51 | location: Location, | |
52 | ) { | |
53 | self.transfer_function(trans).visit_terminator(terminator, location); | |
2c00a5a8 XL |
54 | } |
55 | ||
74b04a01 XL |
56 | fn call_return_effect( |
57 | &self, | |
58 | _trans: &mut impl GenKill<Self::Idx>, | |
59 | _block: mir::BasicBlock, | |
a2a8927a | 60 | _return_places: CallReturnPlaces<'_, 'tcx>, |
74b04a01 | 61 | ) { |
2c00a5a8 | 62 | } |
74b04a01 XL |
63 | } |
64 | ||
74b04a01 | 65 | /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. |
3c0e092e | 66 | struct TransferFunction<'a, T> { |
74b04a01 | 67 | trans: &'a mut T, |
74b04a01 | 68 | } |
b7449926 | 69 | |
a2a8927a | 70 | impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T> |
74b04a01 XL |
71 | where |
72 | T: GenKill<Local>, | |
74b04a01 XL |
73 | { |
74 | fn visit_statement(&mut self, stmt: &Statement<'tcx>, location: Location) { | |
75 | self.super_statement(stmt, location); | |
b7449926 | 76 | |
74b04a01 XL |
77 | // When we reach a `StorageDead` statement, we can assume that any pointers to this memory |
78 | // are now invalid. | |
79 | if let StatementKind::StorageDead(local) = stmt.kind { | |
80 | self.trans.kill(local); | |
b7449926 | 81 | } |
2c00a5a8 XL |
82 | } |
83 | ||
74b04a01 XL |
84 | fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { |
85 | self.super_rvalue(rvalue, location); | |
86 | ||
87 | match rvalue { | |
923072b8 | 88 | mir::Rvalue::AddressOf(_, borrowed_place) | mir::Rvalue::Ref(_, _, borrowed_place) => { |
3c0e092e | 89 | if !borrowed_place.is_indirect() { |
74b04a01 XL |
90 | self.trans.gen(borrowed_place.local); |
91 | } | |
92 | } | |
93 | ||
94 | mir::Rvalue::Cast(..) | |
c295e0f8 | 95 | | mir::Rvalue::ShallowInitBox(..) |
74b04a01 | 96 | | mir::Rvalue::Use(..) |
f9f354fc | 97 | | mir::Rvalue::ThreadLocalRef(..) |
74b04a01 XL |
98 | | mir::Rvalue::Repeat(..) |
99 | | mir::Rvalue::Len(..) | |
100 | | mir::Rvalue::BinaryOp(..) | |
101 | | mir::Rvalue::CheckedBinaryOp(..) | |
102 | | mir::Rvalue::NullaryOp(..) | |
103 | | mir::Rvalue::UnaryOp(..) | |
104 | | mir::Rvalue::Discriminant(..) | |
064997fb FG |
105 | | mir::Rvalue::Aggregate(..) |
106 | | mir::Rvalue::CopyForDeref(..) => {} | |
dc9dc135 | 107 | } |
2c00a5a8 XL |
108 | } |
109 | ||
74b04a01 XL |
110 | fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { |
111 | self.super_terminator(terminator, location); | |
112 | ||
113 | match terminator.kind { | |
f035d41b XL |
114 | mir::TerminatorKind::Drop { place: dropped_place, .. } |
115 | | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => { | |
5e7ed085 FG |
116 | // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut |
117 | // self` as a parameter. In the general case, a drop impl could launder that | |
118 | // reference into the surrounding environment through a raw pointer, thus creating | |
119 | // a valid `*mut` pointing to the dropped local. We are not yet willing to declare | |
120 | // this particular case UB, so we must treat all dropped locals as mutably borrowed | |
121 | // for now. See discussion on [#61069]. | |
122 | // | |
123 | // [#61069]: https://github.com/rust-lang/rust/pull/61069 | |
124 | self.trans.gen(dropped_place.local); | |
74b04a01 XL |
125 | } |
126 | ||
127 | TerminatorKind::Abort | |
128 | | TerminatorKind::Assert { .. } | |
129 | | TerminatorKind::Call { .. } | |
f035d41b | 130 | | TerminatorKind::FalseEdge { .. } |
74b04a01 XL |
131 | | TerminatorKind::FalseUnwind { .. } |
132 | | TerminatorKind::GeneratorDrop | |
133 | | TerminatorKind::Goto { .. } | |
f9f354fc | 134 | | TerminatorKind::InlineAsm { .. } |
74b04a01 XL |
135 | | TerminatorKind::Resume |
136 | | TerminatorKind::Return | |
137 | | TerminatorKind::SwitchInt { .. } | |
138 | | TerminatorKind::Unreachable | |
139 | | TerminatorKind::Yield { .. } => {} | |
140 | } | |
2c00a5a8 XL |
141 | } |
142 | } | |
923072b8 FG |
143 | |
144 | /// The set of locals that are borrowed at some point in the MIR body. | |
145 | pub fn borrowed_locals(body: &Body<'_>) -> BitSet<Local> { | |
146 | struct Borrowed(BitSet<Local>); | |
147 | ||
148 | impl GenKill<Local> for Borrowed { | |
149 | #[inline] | |
150 | fn gen(&mut self, elem: Local) { | |
151 | self.0.gen(elem) | |
152 | } | |
153 | #[inline] | |
154 | fn kill(&mut self, _: Local) { | |
155 | // Ignore borrow invalidation. | |
156 | } | |
157 | } | |
158 | ||
159 | let mut borrowed = Borrowed(BitSet::new_empty(body.local_decls.len())); | |
160 | TransferFunction { trans: &mut borrowed }.visit_body(body); | |
161 | borrowed.0 | |
162 | } |