3 use crate::{AnalysisDomain, CallReturnPlaces, GenKill, GenKillAnalysis}
;
4 use rustc_middle
::mir
::visit
::Visitor
;
5 use rustc_middle
::mir
::*;
7 /// A dataflow analysis that tracks whether a pointer or reference could possibly exist that points
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
12 /// immovable generators.
13 pub struct MaybeBorrowedLocals
;
15 impl MaybeBorrowedLocals
{
16 fn transfer_function
<'a
, T
>(&'a
self, trans
: &'a
mut T
) -> TransferFunction
<'a
, T
> {
17 TransferFunction { trans }
21 impl<'tcx
> AnalysisDomain
<'tcx
> for MaybeBorrowedLocals
{
22 type Domain
= BitSet
<Local
>;
23 const NAME
: &'
static str = "maybe_borrowed_locals";
25 fn bottom_value(&self, body
: &mir
::Body
<'tcx
>) -> Self::Domain
{
26 // bottom = unborrowed
27 BitSet
::new_empty(body
.local_decls().len())
30 fn initialize_start_block(&self, _
: &mir
::Body
<'tcx
>, _
: &mut Self::Domain
) {
31 // No locals are aliased on function entry
35 impl<'tcx
> GenKillAnalysis
<'tcx
> for MaybeBorrowedLocals
{
40 trans
: &mut impl GenKill
<Self::Idx
>,
41 statement
: &mir
::Statement
<'tcx
>,
44 self.transfer_function(trans
).visit_statement(statement
, location
);
49 trans
: &mut impl GenKill
<Self::Idx
>,
50 terminator
: &mir
::Terminator
<'tcx
>,
53 self.transfer_function(trans
).visit_terminator(terminator
, location
);
56 fn call_return_effect(
58 _trans
: &mut impl GenKill
<Self::Idx
>,
59 _block
: mir
::BasicBlock
,
60 _return_places
: CallReturnPlaces
<'_
, 'tcx
>,
65 /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
66 struct TransferFunction
<'a
, T
> {
70 impl<'tcx
, T
> Visitor
<'tcx
> for TransferFunction
<'_
, T
>
74 fn visit_statement(&mut self, stmt
: &Statement
<'tcx
>, location
: Location
) {
75 self.super_statement(stmt
, location
);
77 // When we reach a `StorageDead` statement, we can assume that any pointers to this memory
79 if let StatementKind
::StorageDead(local
) = stmt
.kind
{
80 self.trans
.kill(local
);
84 fn visit_rvalue(&mut self, rvalue
: &mir
::Rvalue
<'tcx
>, location
: Location
) {
85 self.super_rvalue(rvalue
, location
);
88 mir
::Rvalue
::AddressOf(_
, borrowed_place
) | mir
::Rvalue
::Ref(_
, _
, borrowed_place
) => {
89 if !borrowed_place
.is_indirect() {
90 self.trans
.gen(borrowed_place
.local
);
95 | mir
::Rvalue
::ShallowInitBox(..)
96 | mir
::Rvalue
::Use(..)
97 | mir
::Rvalue
::ThreadLocalRef(..)
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(..)
105 | mir
::Rvalue
::Aggregate(..)
106 | mir
::Rvalue
::CopyForDeref(..) => {}
110 fn visit_terminator(&mut self, terminator
: &mir
::Terminator
<'tcx
>, location
: Location
) {
111 self.super_terminator(terminator
, location
);
113 match terminator
.kind
{
114 mir
::TerminatorKind
::Drop { place: dropped_place, .. }
115 | mir
::TerminatorKind
::DropAndReplace { place: dropped_place, .. }
=> {
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].
123 // [#61069]: https://github.com/rust-lang/rust/pull/61069
124 self.trans
.gen(dropped_place
.local
);
127 TerminatorKind
::Abort
128 | TerminatorKind
::Assert { .. }
129 | TerminatorKind
::Call { .. }
130 | TerminatorKind
::FalseEdge { .. }
131 | TerminatorKind
::FalseUnwind { .. }
132 | TerminatorKind
::GeneratorDrop
133 | TerminatorKind
::Goto { .. }
134 | TerminatorKind
::InlineAsm { .. }
135 | TerminatorKind
::Resume
136 | TerminatorKind
::Return
137 | TerminatorKind
::SwitchInt { .. }
138 | TerminatorKind
::Unreachable
139 | TerminatorKind
::Yield { .. }
=> {}
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
>);
148 impl GenKill
<Local
> for Borrowed
{
150 fn gen(&mut self, elem
: Local
) {
154 fn kill(&mut self, _
: Local
) {
155 // Ignore borrow invalidation.
159 let mut borrowed
= Borrowed(BitSet
::new_empty(body
.local_decls
.len()));
160 TransferFunction { trans: &mut borrowed }
.visit_body(body
);