@@ -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,23 +94,58 @@ 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 ;
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+ }
102+
103+ match DefUse :: for_place ( * place, context) {
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 ) ,
118+ None => { }
119+ }
102120
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`.
105121 self . visit_projection ( place. as_ref ( ) , context, location) ;
122+ }
106123
107- match DefUse :: for_place ( * place, context) {
124+ fn visit_local ( & mut self , local : Local , context : PlaceContext , _: Location ) {
125+ match DefUse :: for_place ( local. into ( ) , context) {
108126 Some ( DefUse :: Def ) => self . 0 . kill ( local) ,
109127 Some ( DefUse :: Use ) => self . 0 . gen ( local) ,
110128 None => { }
111129 }
112130 }
131+ }
132+
133+ struct YieldResumeEffect < ' a , T > ( & ' a mut T ) ;
134+
135+ impl < ' tcx , T > Visitor < ' tcx > for YieldResumeEffect < ' _ , T >
136+ where
137+ T : GenKill < Local > ,
138+ {
139+ fn visit_place ( & mut self , place : & mir:: Place < ' tcx > , context : PlaceContext , location : Location ) {
140+ match DefUse :: for_place ( * place, context) {
141+ Some ( DefUse :: Def ) => self . 0 . kill ( place. local ) ,
142+ Some ( DefUse :: Use ) => self . 0 . gen ( place. local ) ,
143+ None => { }
144+ }
145+ self . visit_projection ( place. as_ref ( ) , context, location) ;
146+ }
113147
114148 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.
118149 match DefUse :: for_place ( local. into ( ) , context) {
119150 Some ( DefUse :: Def ) => self . 0 . kill ( local) ,
120151 Some ( DefUse :: Use ) => self . 0 . gen ( local) ,
@@ -134,7 +165,13 @@ impl DefUse {
134165 match context {
135166 PlaceContext :: NonUse ( _) => None ,
136167
137- PlaceContext :: MutatingUse ( MutatingUseContext :: Store | MutatingUseContext :: Deinit ) => {
168+ PlaceContext :: MutatingUse (
169+ MutatingUseContext :: Call
170+ | MutatingUseContext :: Yield
171+ | MutatingUseContext :: AsmOutput
172+ | MutatingUseContext :: Store
173+ | MutatingUseContext :: Deinit ,
174+ ) => {
138175 if place. is_indirect ( ) {
139176 // Treat derefs as a use of the base local. `*p = 4` is not a def of `p` but a
140177 // use.
@@ -152,16 +189,6 @@ impl DefUse {
152189 place. is_indirect ( ) . then_some ( DefUse :: Use )
153190 }
154191
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-
165192 // All other contexts are uses...
166193 PlaceContext :: MutatingUse (
167194 MutatingUseContext :: AddressOf
@@ -290,8 +317,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
290317 _resume_block : mir:: BasicBlock ,
291318 resume_place : mir:: Place < ' tcx > ,
292319 ) {
293- if let Some ( local) = resume_place. as_local ( ) {
294- trans. remove ( local) ;
295- }
320+ YieldResumeEffect ( trans) . visit_place (
321+ & resume_place,
322+ PlaceContext :: MutatingUse ( MutatingUseContext :: Yield ) ,
323+ Location :: START ,
324+ )
296325 }
297326}
0 commit comments