@@ -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,13 @@ 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+ storage_liveness. remove ( SELF_ARG ) ;
519508
520509 // Store the storage liveness for later use so we can restore the state
521510 // after a suspension point
522- storage_liveness_map. insert ( block, storage_liveness. clone ( ) ) ;
511+ storage_liveness_map. insert ( block, storage_liveness) ;
523512
524513 requires_storage_cursor. seek_before ( loc) ;
525514 let storage_required = requires_storage_cursor. get ( ) . clone ( ) ;
@@ -551,8 +540,12 @@ fn locals_live_across_suspend_points(
551540 . map ( |live_here| renumber_bitset ( & live_here, & live_locals) )
552541 . collect ( ) ;
553542
554- let storage_conflicts =
555- compute_storage_conflicts ( body_ref, & live_locals, & ignored, requires_storage_results) ;
543+ let storage_conflicts = compute_storage_conflicts (
544+ body_ref,
545+ & live_locals,
546+ always_live_locals. clone ( ) ,
547+ requires_storage_results,
548+ ) ;
556549
557550 LivenessInfo {
558551 live_locals,
@@ -590,18 +583,18 @@ fn renumber_bitset(
590583fn compute_storage_conflicts (
591584 body : & ' mir Body < ' tcx > ,
592585 stored_locals : & liveness:: LiveVarSet ,
593- ignored : & StorageIgnored ,
586+ always_live_locals : storage :: AlwaysLiveLocals ,
594587 requires_storage : dataflow:: Results < ' tcx , MaybeRequiresStorage < ' mir , ' tcx > > ,
595588) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
596- assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
597589 assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
590+
598591 debug ! ( "compute_storage_conflicts({:?})" , body. span) ;
599- debug ! ( "ignored = {:?}" , ignored . 0 ) ;
592+ debug ! ( "always_live = {:?}" , always_live_locals ) ;
600593
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) ;
594+ // Locals that are always live or ones that need to be stored across
595+ // suspension points are not eligible for overlap .
596+ let mut ineligible_locals = always_live_locals . into_inner ( ) ;
597+ ineligible_locals. intersect ( stored_locals) ;
605598
606599 // Compute the storage conflicts for all eligible locals.
607600 let mut visitor = StorageConflictVisitor {
@@ -697,6 +690,7 @@ fn compute_layout<'tcx>(
697690 source : MirSource < ' tcx > ,
698691 upvars : & Vec < Ty < ' tcx > > ,
699692 interior : Ty < ' tcx > ,
693+ always_live_locals : & storage:: AlwaysLiveLocals ,
700694 movable : bool ,
701695 body : & mut BodyAndCache < ' tcx > ,
702696) -> (
@@ -710,7 +704,13 @@ fn compute_layout<'tcx>(
710704 live_locals_at_suspension_points,
711705 storage_conflicts,
712706 storage_liveness,
713- } = locals_live_across_suspend_points ( tcx, read_only ! ( body) , source, movable) ;
707+ } = locals_live_across_suspend_points (
708+ tcx,
709+ read_only ! ( body) ,
710+ source,
711+ always_live_locals,
712+ movable,
713+ ) ;
714714
715715 // Erase regions from the types passed in from typeck so we can compare them with
716716 // MIR types
@@ -1180,7 +1180,10 @@ fn create_cases<'tcx>(
11801180 }
11811181
11821182 let l = Local :: new ( i) ;
1183- if point. storage_liveness . contains ( l) && !transform. remap . contains_key ( & l) {
1183+ let needs_storage_live = point. storage_liveness . contains ( l)
1184+ && !transform. remap . contains_key ( & l)
1185+ && !transform. always_live_locals . contains ( l) ;
1186+ if needs_storage_live {
11841187 statements
11851188 . push ( Statement { source_info, kind : StatementKind :: StorageLive ( l) } ) ;
11861189 }
@@ -1276,11 +1279,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12761279 } ,
12771280 ) ;
12781281
1282+ let always_live_locals = storage:: AlwaysLiveLocals :: new ( & body) ;
1283+
12791284 // Extract locals which are live across suspension point into `layout`
12801285 // `remap` gives a mapping from local indices onto generator struct indices
12811286 // `storage_liveness` tells us which locals have live storage at suspension points
12821287 let ( remap, layout, storage_liveness) =
1283- compute_layout ( tcx, source, & upvars, interior, movable, body) ;
1288+ compute_layout ( tcx, source, & upvars, interior, & always_live_locals , movable, body) ;
12841289
12851290 let can_return = can_return ( tcx, body) ;
12861291
@@ -1294,6 +1299,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
12941299 state_substs,
12951300 remap,
12961301 storage_liveness,
1302+ always_live_locals,
12971303 suspension_points : Vec :: new ( ) ,
12981304 new_ret_local,
12991305 discr_ty,
0 commit comments