1
1
use rustc_index:: bit_set:: DenseBitSet ;
2
- use rustc_middle:: mir:: visit:: { MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor } ;
2
+ use rustc_middle:: mir:: visit:: {
3
+ MutatingUseContext , NonMutatingUseContext , PlaceContext , VisitPlacesWith , Visitor ,
4
+ } ;
3
5
use rustc_middle:: mir:: {
4
- self , CallReturnPlaces , Local , Location , Place , StatementKind , TerminatorEdges ,
6
+ self , CallReturnPlaces , Local , Location , Place , StatementKind , TerminatorEdges , TerminatorKind ,
5
7
} ;
6
8
7
9
use crate :: { Analysis , Backward , GenKill } ;
@@ -23,9 +25,13 @@ use crate::{Analysis, Backward, GenKill};
23
25
/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
24
26
/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
25
27
/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
26
- pub struct MaybeLiveLocals ;
28
+ pub struct MaybeLiveLocals < F > ( pub F ) ;
27
29
28
- impl < ' tcx > Analysis < ' tcx > for MaybeLiveLocals {
30
+ impl < ' tcx , F , I > Analysis < ' tcx > for MaybeLiveLocals < F >
31
+ where
32
+ F : Fn ( Location ) -> I ,
33
+ I : Iterator < Item = Local > ,
34
+ {
29
35
type Domain = DenseBitSet < Local > ;
30
36
type Direction = Backward ;
31
37
@@ -40,6 +46,26 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
40
46
// No variables are live until we observe a use
41
47
}
42
48
49
+ fn apply_early_statement_effect (
50
+ & mut self ,
51
+ state : & mut Self :: Domain ,
52
+ statement : & mir:: Statement < ' tcx > ,
53
+ location : Location ,
54
+ ) {
55
+ let mut accesses_indirect = false ;
56
+ VisitPlacesWith ( |place : Place < ' tcx > , _: PlaceContext | {
57
+ accesses_indirect |= place. is_indirect ( ) ;
58
+ } )
59
+ . visit_statement ( statement, location) ;
60
+ if accesses_indirect {
61
+ // We do not track what happens to the addresses of borrowed locals. This means
62
+ // that this indirect read/write may be to any borrowed local.
63
+ for local in ( self . 0 ) ( location) {
64
+ state. gen_ ( local) ;
65
+ }
66
+ }
67
+ }
68
+
43
69
fn apply_primary_statement_effect (
44
70
& mut self ,
45
71
state : & mut Self :: Domain ,
@@ -49,6 +75,44 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
49
75
TransferFunction ( state) . visit_statement ( statement, location) ;
50
76
}
51
77
78
+ fn apply_early_terminator_effect < ' mir > (
79
+ & mut self ,
80
+ state : & mut Self :: Domain ,
81
+ terminator : & ' mir mir:: Terminator < ' tcx > ,
82
+ location : Location ,
83
+ ) {
84
+ let may_access_borrowed_locals = match terminator. kind {
85
+ TerminatorKind :: CoroutineDrop
86
+ | TerminatorKind :: FalseEdge { .. }
87
+ | TerminatorKind :: FalseUnwind { .. }
88
+ | TerminatorKind :: Goto { .. }
89
+ | TerminatorKind :: Return
90
+ | TerminatorKind :: Unreachable
91
+ | TerminatorKind :: UnwindResume
92
+ | TerminatorKind :: UnwindTerminate ( _) => false ,
93
+
94
+ TerminatorKind :: Assert { cond : ref operand, .. }
95
+ | TerminatorKind :: SwitchInt { discr : ref operand, .. } => {
96
+ operand. place ( ) . is_some_and ( |place| place. is_indirect ( ) )
97
+ }
98
+
99
+ // Those terminators may call arbitrary code.
100
+ TerminatorKind :: Call { .. }
101
+ | TerminatorKind :: Drop { .. }
102
+ | TerminatorKind :: InlineAsm { .. }
103
+ | TerminatorKind :: TailCall { .. }
104
+ | TerminatorKind :: Yield { .. } => true ,
105
+ } ;
106
+ if may_access_borrowed_locals {
107
+ // We do not track what happens to the addresses of borrowed locals. This means that this
108
+ // terminator may know the address of any borrowed local. And it may do anything with it
109
+ // including reading and writing to it.
110
+ for local in ( self . 0 ) ( location) {
111
+ state. gen_ ( local) ;
112
+ }
113
+ }
114
+ }
115
+
52
116
fn apply_primary_terminator_effect < ' mir > (
53
117
& mut self ,
54
118
state : & mut Self :: Domain ,
@@ -155,17 +219,17 @@ impl DefUse {
155
219
match context {
156
220
PlaceContext :: NonUse ( _) => DefUse :: NonUse ,
157
221
222
+ // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
223
+ _ if place. is_indirect ( ) => DefUse :: Use ,
224
+
158
225
PlaceContext :: MutatingUse (
159
226
MutatingUseContext :: Call
160
227
| MutatingUseContext :: Yield
161
228
| MutatingUseContext :: AsmOutput
162
229
| MutatingUseContext :: Store
163
230
| MutatingUseContext :: Deinit ,
164
231
) => {
165
- // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a use.
166
- if place. is_indirect ( ) {
167
- DefUse :: Use
168
- } else if place. projection . is_empty ( ) {
232
+ if place. projection . is_empty ( ) {
169
233
DefUse :: Def
170
234
} else {
171
235
DefUse :: PartialWrite
@@ -174,9 +238,7 @@ impl DefUse {
174
238
175
239
// Setting the discriminant is not a use because it does no reading, but it is also not
176
240
// a def because it does not overwrite the whole place
177
- PlaceContext :: MutatingUse ( MutatingUseContext :: SetDiscriminant ) => {
178
- if place. is_indirect ( ) { DefUse :: Use } else { DefUse :: PartialWrite }
179
- }
241
+ PlaceContext :: MutatingUse ( MutatingUseContext :: SetDiscriminant ) => DefUse :: PartialWrite ,
180
242
181
243
// All other contexts are uses...
182
244
PlaceContext :: MutatingUse (
0 commit comments