@@ -56,12 +56,13 @@ use crate::transform::simplify;
56
56
use crate :: transform:: { MirPass , MirSource } ;
57
57
use crate :: util:: dump_mir;
58
58
use crate :: util:: liveness;
59
+ use crate :: util:: storage;
59
60
use rustc_data_structures:: fx:: FxHashMap ;
60
61
use rustc_hir as hir;
61
62
use rustc_hir:: def_id:: DefId ;
62
63
use rustc_index:: bit_set:: { BitMatrix , BitSet } ;
63
64
use rustc_index:: vec:: { Idx , IndexVec } ;
64
- use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext , Visitor } ;
65
+ use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext } ;
65
66
use rustc_middle:: mir:: * ;
66
67
use rustc_middle:: ty:: subst:: SubstsRef ;
67
68
use rustc_middle:: ty:: GeneratorSubsts ;
@@ -222,6 +223,9 @@ struct TransformVisitor<'tcx> {
222
223
// A list of suspension points, generated during the transform
223
224
suspension_points : Vec < SuspensionPoint < ' tcx > > ,
224
225
226
+ // The set of locals that have no `StorageLive`/`StorageDead` annotations.
227
+ always_live_locals : storage:: AlwaysLiveLocals ,
228
+
225
229
// The original RETURN_PLACE local
226
230
new_ret_local : Local ,
227
231
}
@@ -416,19 +420,6 @@ fn replace_local<'tcx>(
416
420
new_local
417
421
}
418
422
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
-
432
423
struct LivenessInfo {
433
424
/// Which locals are live across any suspension point.
434
425
///
@@ -454,23 +445,19 @@ fn locals_live_across_suspend_points(
454
445
tcx : TyCtxt < ' tcx > ,
455
446
body : ReadOnlyBodyAndCache < ' _ , ' tcx > ,
456
447
source : MirSource < ' tcx > ,
448
+ always_live_locals : & storage:: AlwaysLiveLocals ,
457
449
movable : bool ,
458
450
) -> LivenessInfo {
459
451
let def_id = source. def_id ( ) ;
460
452
let body_ref: & Body < ' _ > = & body;
461
453
462
454
// Calculate when MIR locals have live storage. This gives us an upper bound of their
463
455
// lifetimes.
464
- let mut storage_live = MaybeStorageLive
456
+ let mut storage_live = MaybeStorageLive :: new ( always_live_locals . clone ( ) )
465
457
. into_engine ( tcx, body_ref, def_id)
466
458
. iterate_to_fixpoint ( )
467
459
. into_results_cursor ( body_ref) ;
468
460
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
-
474
461
// Calculate the MIR locals which have been previously
475
462
// borrowed (even if they are still active).
476
463
let borrowed_locals_results =
@@ -515,11 +502,14 @@ fn locals_live_across_suspend_points(
515
502
}
516
503
517
504
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 ) ;
519
509
520
510
// Store the storage liveness for later use so we can restore the state
521
511
// after a suspension point
522
- storage_liveness_map. insert ( block, storage_liveness. clone ( ) ) ;
512
+ storage_liveness_map. insert ( block, storage_liveness) ;
523
513
524
514
requires_storage_cursor. seek_before ( loc) ;
525
515
let storage_required = requires_storage_cursor. get ( ) . clone ( ) ;
@@ -551,8 +541,12 @@ fn locals_live_across_suspend_points(
551
541
. map ( |live_here| renumber_bitset ( & live_here, & live_locals) )
552
542
. collect ( ) ;
553
543
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
+ ) ;
556
550
557
551
LivenessInfo {
558
552
live_locals,
@@ -590,18 +584,18 @@ fn renumber_bitset(
590
584
fn compute_storage_conflicts (
591
585
body : & ' mir Body < ' tcx > ,
592
586
stored_locals : & liveness:: LiveVarSet ,
593
- ignored : & StorageIgnored ,
587
+ always_live_locals : storage :: AlwaysLiveLocals ,
594
588
requires_storage : dataflow:: Results < ' tcx , MaybeRequiresStorage < ' mir , ' tcx > > ,
595
589
) -> BitMatrix < GeneratorSavedLocal , GeneratorSavedLocal > {
596
- assert_eq ! ( body. local_decls. len( ) , ignored. 0 . domain_size( ) ) ;
597
590
assert_eq ! ( body. local_decls. len( ) , stored_locals. domain_size( ) ) ;
591
+
598
592
debug ! ( "compute_storage_conflicts({:?})" , body. span) ;
599
- debug ! ( "ignored = {:?}" , ignored . 0 ) ;
593
+ debug ! ( "always_live = {:?}" , always_live_locals ) ;
600
594
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) ;
605
599
606
600
// Compute the storage conflicts for all eligible locals.
607
601
let mut visitor = StorageConflictVisitor {
@@ -697,6 +691,7 @@ fn compute_layout<'tcx>(
697
691
source : MirSource < ' tcx > ,
698
692
upvars : & Vec < Ty < ' tcx > > ,
699
693
interior : Ty < ' tcx > ,
694
+ always_live_locals : & storage:: AlwaysLiveLocals ,
700
695
movable : bool ,
701
696
body : & mut BodyAndCache < ' tcx > ,
702
697
) -> (
@@ -710,7 +705,13 @@ fn compute_layout<'tcx>(
710
705
live_locals_at_suspension_points,
711
706
storage_conflicts,
712
707
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
+ ) ;
714
715
715
716
// Erase regions from the types passed in from typeck so we can compare them with
716
717
// MIR types
@@ -1180,7 +1181,10 @@ fn create_cases<'tcx>(
1180
1181
}
1181
1182
1182
1183
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 {
1184
1188
statements
1185
1189
. push ( Statement { source_info, kind : StatementKind :: StorageLive ( l) } ) ;
1186
1190
}
@@ -1276,11 +1280,13 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1276
1280
} ,
1277
1281
) ;
1278
1282
1283
+ let always_live_locals = storage:: AlwaysLiveLocals :: new ( & body) ;
1284
+
1279
1285
// Extract locals which are live across suspension point into `layout`
1280
1286
// `remap` gives a mapping from local indices onto generator struct indices
1281
1287
// `storage_liveness` tells us which locals have live storage at suspension points
1282
1288
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) ;
1284
1290
1285
1291
let can_return = can_return ( tcx, body) ;
1286
1292
@@ -1294,6 +1300,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1294
1300
state_substs,
1295
1301
remap,
1296
1302
storage_liveness,
1303
+ always_live_locals,
1297
1304
suspension_points : Vec :: new ( ) ,
1298
1305
new_ret_local,
1299
1306
discr_ty,
0 commit comments