@@ -56,12 +56,13 @@ use crate::transform::simplify;
5656use crate :: transform:: { MirPass , MirSource } ;
5757use crate :: util:: dump_mir;
5858use crate :: util:: liveness;
59+ use crate :: util:: storage;
5960use rustc_data_structures:: fx:: FxHashMap ;
6061use rustc_hir as hir;
6162use rustc_hir:: def_id:: DefId ;
6263use rustc_index:: bit_set:: { BitMatrix , BitSet } ;
6364use rustc_index:: vec:: { Idx , IndexVec } ;
64- use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext , Visitor } ;
65+ use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext } ;
6566use rustc_middle:: mir:: * ;
6667use rustc_middle:: ty:: subst:: SubstsRef ;
6768use rustc_middle:: ty:: GeneratorSubsts ;
@@ -222,6 +223,9 @@ struct TransformVisitor<'tcx> {
222223 // A list of suspension points, generated during the transform
223224 suspension_points : Vec < SuspensionPoint < ' tcx > > ,
224225
226+ // The set of locals that have no `StorageLive`/`StorageDead` annotations.
227+ always_live_locals : storage:: AlwaysLiveLocals ,
228+
225229 // The original RETURN_PLACE local
226230 new_ret_local : Local ,
227231}
@@ -416,19 +420,6 @@ fn replace_local<'tcx>(
416420 new_local
417421}
418422
419- struct StorageIgnored ( liveness:: LiveVarSet ) ;
420-
421- impl < ' tcx > Visitor < ' tcx > for StorageIgnored {
422- fn visit_statement ( & mut self , statement : & Statement < ' tcx > , _location : Location ) {
423- match statement. kind {
424- StatementKind :: StorageLive ( l) | StatementKind :: StorageDead ( l) => {
425- self . 0 . remove ( l) ;
426- }
427- _ => ( ) ,
428- }
429- }
430- }
431-
432423struct LivenessInfo {
433424 /// Which locals are live across any suspension point.
434425 ///
@@ -454,23 +445,19 @@ fn locals_live_across_suspend_points(
454445 tcx : TyCtxt < ' tcx > ,
455446 body : ReadOnlyBodyAndCache < ' _ , ' tcx > ,
456447 source : MirSource < ' tcx > ,
448+ always_live_locals : & storage:: AlwaysLiveLocals ,
457449 movable : bool ,
458450) -> LivenessInfo {
459451 let def_id = source. def_id ( ) ;
460452 let body_ref: & Body < ' _ > = & body;
461453
462454 // Calculate when MIR locals have live storage. This gives us an upper bound of their
463455 // lifetimes.
464- let mut storage_live = MaybeStorageLive
456+ let mut storage_live = MaybeStorageLive :: new ( always_live_locals . clone ( ) )
465457 . into_engine ( tcx, body_ref, def_id)
466458 . iterate_to_fixpoint ( )
467459 . into_results_cursor ( body_ref) ;
468460
469- // Find the MIR locals which do not use StorageLive/StorageDead statements.
470- // The storage of these locals are always live.
471- let mut ignored = StorageIgnored ( BitSet :: new_filled ( body. local_decls . len ( ) ) ) ;
472- ignored. visit_body ( & body) ;
473-
474461 // Calculate the MIR locals which have been previously
475462 // borrowed (even if they are still active).
476463 let borrowed_locals_results =
@@ -515,11 +502,14 @@ fn locals_live_across_suspend_points(
515502 }
516503
517504 storage_live. seek_before ( loc) ;
518- let storage_liveness = storage_live. get ( ) ;
505+ let mut storage_liveness = storage_live. get ( ) . clone ( ) ;
506+
507+ // Later passes handle the generator's `self` argument separately.
508+ storage_liveness. remove ( SELF_ARG ) ;
519509
520510 // Store the storage liveness for later use so we can restore the state
521511 // after a suspension point
522- storage_liveness_map. insert ( block, storage_liveness. clone ( ) ) ;
512+ storage_liveness_map. insert ( block, storage_liveness) ;
523513
524514 requires_storage_cursor. seek_before ( loc) ;
525515 let storage_required = requires_storage_cursor. get ( ) . clone ( ) ;
@@ -551,8 +541,12 @@ fn locals_live_across_suspend_points(
551541 . map ( |live_here| renumber_bitset ( & live_here, & live_locals) )
552542 . collect ( ) ;
553543
554- let storage_conflicts =
555- compute_storage_conflicts ( body_ref, & live_locals, & ignored, requires_storage_results) ;
544+ let storage_conflicts = compute_storage_conflicts (
545+ body_ref,
546+ & live_locals,
547+ always_live_locals. clone ( ) ,
548+ requires_storage_results,
549+ ) ;
556550
557551 LivenessInfo {
558552 live_locals,
@@ -590,18 +584,18 @@ fn renumber_bitset(
590584fn compute_storage_conflicts (
591585 body : & ' mir Body < ' tcx > ,
592586 stored_locals : & liveness:: LiveVarSet ,
593- ignored : & StorageIgnored ,
587+ always_live_locals : storage :: AlwaysLiveLocals ,
594588 requires_storage : dataflow:: Results < ' tcx , MaybeRequiresStorage < ' mir , ' tcx > > ,
595589) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
596- assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
597590 assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
591+
598592 debug ! ( "compute_storage_conflicts({:?})" , body. span) ;
599- debug ! ( "ignored = {:?}" , ignored . 0 ) ;
593+ debug ! ( "always_live = {:?}" , always_live_locals ) ;
600594
601- // Storage ignored locals are not eligible for overlap, since their storage
602- // is always live .
603- let mut ineligible_locals = ignored . 0 . clone ( ) ;
604- ineligible_locals. intersect ( & stored_locals) ;
595+ // Locals that are always live or ones that need to be stored across
596+ // suspension points are not eligible for overlap .
597+ let mut ineligible_locals = always_live_locals . into_inner ( ) ;
598+ ineligible_locals. intersect ( stored_locals) ;
605599
606600 // Compute the storage conflicts for all eligible locals.
607601 let mut visitor = StorageConflictVisitor {
@@ -697,6 +691,7 @@ fn compute_layout<'tcx>(
697691 source : MirSource < ' tcx > ,
698692 upvars : & Vec < Ty < ' tcx > > ,
699693 interior : Ty < ' tcx > ,
694+ always_live_locals : & storage:: AlwaysLiveLocals ,
700695 movable : bool ,
701696 body : & mut BodyAndCache < ' tcx > ,
702697) -> (
@@ -710,7 +705,13 @@ fn compute_layout<'tcx>(
710705 live_locals_at_suspension_points,
711706 storage_conflicts,
712707 storage_liveness,
713- } = locals_live_across_suspend_points ( tcx, read_only ! ( body) , source, movable) ;
708+ } = locals_live_across_suspend_points (
709+ tcx,
710+ read_only ! ( body) ,
711+ source,
712+ always_live_locals,
713+ movable,
714+ ) ;
714715
715716 // Erase regions from the types passed in from typeck so we can compare them with
716717 // MIR types
@@ -1180,7 +1181,10 @@ fn create_cases<'tcx>(
11801181 }
11811182
11821183 let l = Local :: new ( i) ;
1183- if point. storage_liveness . contains ( l) && !transform. remap . contains_key ( & l) {
1184+ let needs_storage_live = point. storage_liveness . contains ( l)
1185+ && !transform. remap . contains_key ( & l)
1186+ && !transform. always_live_locals . contains ( l) ;
1187+ if needs_storage_live {
11841188 statements
11851189 . push ( Statement { source_info, kind : StatementKind :: StorageLive ( l) } ) ;
11861190 }
@@ -1276,11 +1280,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12761280 } ,
12771281 ) ;
12781282
1283+ let always_live_locals = storage:: AlwaysLiveLocals :: new ( & body) ;
1284+
12791285 // Extract locals which are live across suspension point into `layout`
12801286 // `remap` gives a mapping from local indices onto generator struct indices
12811287 // `storage_liveness` tells us which locals have live storage at suspension points
12821288 let ( remap, layout, storage_liveness) =
1283- compute_layout ( tcx, source, & upvars, interior, movable, body) ;
1289+ compute_layout ( tcx, source, & upvars, interior, & always_live_locals , movable, body) ;
12841290
12851291 let can_return = can_return ( tcx, body) ;
12861292
@@ -1294,6 +1300,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12941300 state_substs,
12951301 remap,
12961302 storage_liveness,
1303+ always_live_locals,
12971304 suspension_points : Vec :: new ( ) ,
12981305 new_ret_local,
12991306 discr_ty,
0 commit comments