11use 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+ } ;
35use rustc_middle:: mir:: {
4- self , CallReturnPlaces , Local , Location , Place , StatementKind , TerminatorEdges ,
6+ self , CallReturnPlaces , Local , Location , Place , StatementKind , TerminatorEdges , TerminatorKind ,
57} ;
68
79use crate :: { Analysis , Backward , GenKill } ;
@@ -23,9 +25,13 @@ use crate::{Analysis, Backward, GenKill};
2325/// [`MaybeBorrowedLocals`]: super::MaybeBorrowedLocals
2426/// [flow-test]: https://github.com/rust-lang/rust/blob/a08c47310c7d49cbdc5d7afb38408ba519967ecd/src/test/ui/mir-dataflow/liveness-ptr.rs
2527/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
26- pub struct MaybeLiveLocals ;
28+ pub struct MaybeLiveLocals < F > ( pub F ) ;
2729
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+ {
2935 type Domain = DenseBitSet < Local > ;
3036 type Direction = Backward ;
3137
@@ -40,6 +46,26 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
4046 // No variables are live until we observe a use
4147 }
4248
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+
4369 fn apply_primary_statement_effect (
4470 & mut self ,
4571 state : & mut Self :: Domain ,
@@ -49,6 +75,44 @@ impl<'tcx> Analysis<'tcx> for MaybeLiveLocals {
4975 TransferFunction ( state) . visit_statement ( statement, location) ;
5076 }
5177
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+
52116 fn apply_primary_terminator_effect < ' mir > (
53117 & mut self ,
54118 state : & mut Self :: Domain ,
@@ -155,17 +219,17 @@ impl DefUse {
155219 match context {
156220 PlaceContext :: NonUse ( _) => DefUse :: NonUse ,
157221
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+
158225 PlaceContext :: MutatingUse (
159226 MutatingUseContext :: Call
160227 | MutatingUseContext :: Yield
161228 | MutatingUseContext :: AsmOutput
162229 | MutatingUseContext :: Store
163230 | MutatingUseContext :: Deinit ,
164231 ) => {
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 ( ) {
169233 DefUse :: Def
170234 } else {
171235 DefUse :: PartialWrite
@@ -174,9 +238,7 @@ impl DefUse {
174238
175239 // Setting the discriminant is not a use because it does no reading, but it is also not
176240 // 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 ,
180242
181243 // All other contexts are uses...
182244 PlaceContext :: MutatingUse (
0 commit comments