@@ -330,14 +330,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyLocals {
330330 // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
331331 // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
332332 // fixedpoint where there are no more unused locals.
333- loop {
334- let mut remove_statements = RemoveStatements :: new ( & mut used_locals, tcx) ;
335- remove_statements. visit_body ( body) ;
336-
337- if !remove_statements. modified {
338- break ;
339- }
340- }
333+ remove_unused_definitions ( & mut used_locals, body) ;
341334
342335 // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
343336 let map = make_local_map ( & mut body. local_decls , & used_locals) ;
@@ -487,44 +480,40 @@ impl Visitor<'_> for UsedLocals {
487480 }
488481}
489482
490- struct RemoveStatements < ' a , ' tcx > {
483+ /// Removes unused definitions. Updates the used locals to reflect the changes made.
484+ fn remove_unused_definitions < ' a , ' tcx > (
491485 used_locals : & ' a mut UsedLocals ,
492- tcx : TyCtxt < ' tcx > ,
493- modified : bool ,
494- }
495-
496- impl < ' a , ' tcx > RemoveStatements < ' a , ' tcx > {
497- fn new ( used_locals : & ' a mut UsedLocals , tcx : TyCtxt < ' tcx > ) -> Self {
498- Self { used_locals, tcx, modified : false }
499- }
500- }
501-
502- impl < ' a , ' tcx > MutVisitor < ' tcx > for RemoveStatements < ' a , ' tcx > {
503- fn tcx ( & self ) -> TyCtxt < ' tcx > {
504- self . tcx
505- }
486+ body : & mut Body < ' tcx > ,
487+ ) {
488+ // The use counts are updated as we remove the statements. A local might become unused
489+ // during the retain operation, leading to a temporary inconsistency (storage statements or
490+ // definitions referencing the local might remain). For correctness it is crucial that this
491+ // computation reaches a fixed point.
492+
493+ let mut modified = true ;
494+ while modified {
495+ modified = false ;
496+
497+ for data in body. basic_blocks_mut ( ) {
498+ // Remove unnecessary StorageLive and StorageDead annotations.
499+ data. statements . retain ( |statement| {
500+ let keep = match & statement. kind {
501+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
502+ used_locals. is_used ( * local)
503+ }
504+ StatementKind :: Assign ( box ( place, _) ) => used_locals. is_used ( place. local ) ,
505+ _ => true ,
506+ } ;
506507
507- fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
508- // Remove unnecessary StorageLive and StorageDead annotations.
509- data. statements . retain ( |statement| {
510- let keep = match & statement. kind {
511- StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
512- self . used_locals . is_used ( * local)
508+ if !keep {
509+ trace ! ( "removing statement {:?}" , statement) ;
510+ modified = true ;
511+ used_locals. statement_removed ( statement) ;
513512 }
514- StatementKind :: Assign ( box ( place, _) ) => self . used_locals . is_used ( place. local ) ,
515- _ => true ,
516- } ;
517-
518- if !keep {
519- trace ! ( "removing statement {:?}" , statement) ;
520- self . modified = true ;
521- self . used_locals . statement_removed ( statement) ;
522- }
523513
524- keep
525- } ) ;
526-
527- self . super_basic_block_data ( block, data) ;
514+ keep
515+ } ) ;
516+ }
528517 }
529518}
530519
0 commit comments