@@ -23,12 +23,6 @@ use crate::{Analysis, AnalysisDomain, Backward, CallReturnPlaces, GenKill, GenKi
2323/// [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
2424pub struct MaybeLiveLocals ;
2525
26- impl MaybeLiveLocals {
27- fn transfer_function < ' a , T > ( & self , trans : & ' a mut T ) -> TransferFunction < ' a , T > {
28- TransferFunction ( trans)
29- }
30- }
31-
3226impl < ' tcx > AnalysisDomain < ' tcx > for MaybeLiveLocals {
3327 type Domain = ChunkedBitSet < Local > ;
3428 type Direction = Backward ;
@@ -54,7 +48,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
5448 statement : & mir:: Statement < ' tcx > ,
5549 location : Location ,
5650 ) {
57- self . transfer_function ( trans) . visit_statement ( statement, location) ;
51+ TransferFunction ( trans) . visit_statement ( statement, location) ;
5852 }
5953
6054 fn terminator_effect (
@@ -63,7 +57,7 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
6357 terminator : & mir:: Terminator < ' tcx > ,
6458 location : Location ,
6559 ) {
66- self . transfer_function ( trans) . visit_terminator ( terminator, location) ;
60+ TransferFunction ( trans) . visit_terminator ( terminator, location) ;
6761 }
6862
6963 fn call_return_effect (
@@ -85,9 +79,11 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeLiveLocals {
8579 _resume_block : mir:: BasicBlock ,
8680 resume_place : mir:: Place < ' tcx > ,
8781 ) {
88- if let Some ( local) = resume_place. as_local ( ) {
89- trans. kill ( local) ;
90- }
82+ YieldResumeEffect ( trans) . visit_place (
83+ & resume_place,
84+ PlaceContext :: MutatingUse ( MutatingUseContext :: Yield ) ,
85+ Location :: START ,
86+ )
9187 }
9288}
9389
@@ -98,28 +94,51 @@ where
9894 T : GenKill < Local > ,
9995{
10096 fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , context : PlaceContext , location : Location ) {
101- let local = place . local ;
102-
103- // We purposefully do not call `super_place` here to avoid calling `visit_local` for this
104- // place with one of the `Projection` variants of `PlaceContext`.
105- self . visit_projection ( place . as_ref ( ) , context , location ) ;
97+ if let PlaceContext :: MutatingUse ( MutatingUseContext :: Yield ) = context {
98+ // The resume place is evaluated and assigned to only after generator resumes, so its
99+ // effect is handled separately in `yield_resume_effect`.
100+ return ;
101+ }
106102
107103 match DefUse :: for_place ( * place, context) {
108- Some ( DefUse :: Def ) => self . 0 . kill ( local) ,
109- Some ( DefUse :: Use ) => self . 0 . gen ( local) ,
104+ Some ( DefUse :: Def ) => {
105+ if let PlaceContext :: MutatingUse (
106+ MutatingUseContext :: Call | MutatingUseContext :: AsmOutput ,
107+ ) = context
108+ {
109+ // For the associated terminators, this is only a `Def` when the terminator returns
110+ // "successfully." As such, we handle this case separately in `call_return_effect`
111+ // above. However, if the place looks like `*_5`, this is still unconditionally a use of
112+ // `_5`.
113+ } else {
114+ self . 0 . kill ( place. local ) ;
115+ }
116+ }
117+ Some ( DefUse :: Use ) => self . 0 . gen ( place. local ) ,
110118 None => { }
111119 }
120+
121+ self . visit_projection ( place. as_ref ( ) , context, location) ;
112122 }
113123
114124 fn visit_local ( & mut self , local : Local , context : PlaceContext , _: Location ) {
115- // Because we do not call `super_place` above, `visit_local` is only called for locals that
116- // do not appear as part of a `Place` in the MIR. This handles cases like the implicit use
117- // of the return place in a `Return` terminator or the index in an `Index` projection.
118- match DefUse :: for_place ( local. into ( ) , context) {
119- Some ( DefUse :: Def ) => self . 0 . kill ( local) ,
120- Some ( DefUse :: Use ) => self . 0 . gen ( local) ,
121- None => { }
122- }
125+ DefUse :: apply ( self . 0 , local. into ( ) , context) ;
126+ }
127+ }
128+
129+ struct YieldResumeEffect < ' a , T > ( & ' a mut T ) ;
130+
131+ impl < ' tcx , T > Visitor < ' tcx > for YieldResumeEffect < ' _ , T >
132+ where
133+ T : GenKill < Local > ,
134+ {
135+ fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , context : PlaceContext , location : Location ) {
136+ DefUse :: apply ( self . 0 , * place, context) ;
137+ self . visit_projection ( place. as_ref ( ) , context, location) ;
138+ }
139+
140+ fn visit_local ( & mut self , local : Local , context : PlaceContext , _: Location ) {
141+ DefUse :: apply ( self . 0 , local. into ( ) , context) ;
123142 }
124143}
125144
@@ -130,11 +149,25 @@ enum DefUse {
130149}
131150
132151impl DefUse {
152+ fn apply < ' tcx > ( trans : & mut impl GenKill < Local > , place : Place < ' tcx > , context : PlaceContext ) {
153+ match DefUse :: for_place ( place, context) {
154+ Some ( DefUse :: Def ) => trans. kill ( place. local ) ,
155+ Some ( DefUse :: Use ) => trans. gen ( place. local ) ,
156+ None => { }
157+ }
158+ }
159+
133160 fn for_place < ' tcx > ( place : Place < ' tcx > , context : PlaceContext ) -> Option < DefUse > {
134161 match context {
135162 PlaceContext :: NonUse ( _) => None ,
136163
137- PlaceContext :: MutatingUse ( MutatingUseContext :: Store | MutatingUseContext :: Deinit ) => {
164+ PlaceContext :: MutatingUse (
165+ MutatingUseContext :: Call
166+ | MutatingUseContext :: Yield
167+ | MutatingUseContext :: AsmOutput
168+ | MutatingUseContext :: Store
169+ | MutatingUseContext :: Deinit ,
170+ ) => {
138171 if place. is_indirect ( ) {
139172 // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a
140173 // use.
@@ -152,16 +185,6 @@ impl DefUse {
152185 place. is_indirect ( ) . then_some ( DefUse :: Use )
153186 }
154187
155- // For the associated terminators, this is only a `Def` when the terminator returns
156- // "successfully." As such, we handle this case separately in `call_return_effect`
157- // above. However, if the place looks like `*_5`, this is still unconditionally a use of
158- // `_5`.
159- PlaceContext :: MutatingUse (
160- MutatingUseContext :: Call
161- | MutatingUseContext :: Yield
162- | MutatingUseContext :: AsmOutput ,
163- ) => place. is_indirect ( ) . then_some ( DefUse :: Use ) ,
164-
165188 // All other contexts are uses...
166189 PlaceContext :: MutatingUse (
167190 MutatingUseContext :: AddressOf
@@ -290,8 +313,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
290313 _resume_block : mir:: BasicBlock ,
291314 resume_place : mir:: Place < ' tcx > ,
292315 ) {
293- if let Some ( local) = resume_place. as_local ( ) {
294- trans. remove ( local) ;
295- }
316+ YieldResumeEffect ( trans) . visit_place (
317+ & resume_place,
318+ PlaceContext :: MutatingUse ( MutatingUseContext :: Yield ) ,
319+ Location :: START ,
320+ )
296321 }
297322}
0 commit comments