@@ -78,7 +78,8 @@ use std::mem;
78
78
use transform:: { MirPass , MirSource } ;
79
79
use transform:: simplify;
80
80
use transform:: no_landing_pads:: no_landing_pads;
81
- use dataflow:: { do_dataflow, DebugFormatted , MaybeStorageLive , state_for_location} ;
81
+ use dataflow:: { do_dataflow, DebugFormatted , state_for_location} ;
82
+ use dataflow:: { MaybeStorageLive , HaveBeenBorrowedLocals } ;
82
83
83
84
pub struct StateTransform ;
84
85
@@ -369,17 +370,33 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
369
370
HashMap < BasicBlock , liveness:: LocalSet > ) {
370
371
let dead_unwinds = IdxSetBuf :: new_empty ( mir. basic_blocks ( ) . len ( ) ) ;
371
372
let node_id = tcx. hir . as_local_node_id ( source. def_id ) . unwrap ( ) ;
372
- let analysis = MaybeStorageLive :: new ( mir) ;
373
+
374
+ // Calculate when MIR locals have live storage. This gives us an upper bound of their
375
+ // lifetimes.
376
+ let storage_live_analysis = MaybeStorageLive :: new ( mir) ;
373
377
let storage_live =
374
- do_dataflow ( tcx, mir, node_id, & [ ] , & dead_unwinds, analysis ,
378
+ do_dataflow ( tcx, mir, node_id, & [ ] , & dead_unwinds, storage_live_analysis ,
375
379
|bd, p| DebugFormatted :: new ( & bd. mir ( ) . local_decls [ p] ) ) ;
376
380
381
+ // Find the MIR locals which do not use StorageLive/StorageDead statements.
382
+ // The storage of these locals are always live.
377
383
let mut ignored = StorageIgnored ( IdxSetBuf :: new_filled ( mir. local_decls . len ( ) ) ) ;
378
384
ignored. visit_mir ( mir) ;
379
385
380
- let mut borrowed_locals = BorrowedLocals ( IdxSetBuf :: new_empty ( mir. local_decls . len ( ) ) ) ;
381
- borrowed_locals. visit_mir ( mir) ;
386
+ // Calculate the MIR locals which have been previously
387
+ // borrowed (even if they are still active).
388
+ // This is only used for immovable generators.
389
+ let borrowed_locals = if !movable {
390
+ let analysis = HaveBeenBorrowedLocals :: new ( mir) ;
391
+ let result =
392
+ do_dataflow ( tcx, mir, node_id, & [ ] , & dead_unwinds, analysis,
393
+ |bd, p| DebugFormatted :: new ( & bd. mir ( ) . local_decls [ p] ) ) ;
394
+ Some ( ( analysis, result) )
395
+ } else {
396
+ None
397
+ } ;
382
398
399
+ // Calculate the liveness of MIR locals ignoring borrows.
383
400
let mut set = liveness:: LocalSet :: new_empty ( mir. local_decls . len ( ) ) ;
384
401
let mut liveness = liveness:: liveness_of_locals ( mir, LivenessMode {
385
402
include_regular_use : true ,
@@ -396,24 +413,41 @@ fn locals_live_across_suspend_points<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
396
413
statement_index : data. statements . len ( ) ,
397
414
} ;
398
415
399
- let storage_liveness = state_for_location ( loc, & analysis, & storage_live, mir) ;
416
+ if let Some ( ( ref analysis, ref result) ) = borrowed_locals {
417
+ let borrowed_locals = state_for_location ( loc,
418
+ analysis,
419
+ result,
420
+ mir) ;
421
+ // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
422
+ // This is correct for movable generators since borrows cannot live across
423
+ // suspension points. However for immovable generators we need to account for
424
+ // borrows, so we conseratively assume that all borrowed locals live forever.
425
+ // To do this we just union our `liveness` result with `borrowed_locals`, which
426
+ // contains all the locals which has been borrowed before this suspension point.
427
+ // If a borrow is converted to a raw reference, we must also assume that it lives
428
+ // forever. Note that the final liveness is still bounded by the storage liveness
429
+ // of the local, which happens using the `intersect` operation below.
430
+ liveness. outs [ block] . union ( & borrowed_locals) ;
431
+ }
432
+
433
+ let mut storage_liveness = state_for_location ( loc,
434
+ & storage_live_analysis,
435
+ & storage_live,
436
+ mir) ;
400
437
438
+ // Store the storage liveness for later use so we can restore the state
439
+ // after a suspension point
401
440
storage_liveness_map. insert ( block, storage_liveness. clone ( ) ) ;
402
441
403
- let mut live_locals = storage_liveness;
404
-
405
442
// Mark locals without storage statements as always having live storage
406
- live_locals . union ( & ignored. 0 ) ;
443
+ storage_liveness . union ( & ignored. 0 ) ;
407
444
408
- if !movable {
409
- // For immovable generators we consider borrowed locals to always be live.
410
- // This effectively makes those locals use just the storage liveness.
411
- liveness. outs [ block] . union ( & borrowed_locals. 0 ) ;
412
- }
445
+ // Locals live are live at this point only if they are used across
446
+ // suspension points (the `liveness` variable)
447
+ // and their storage is live (the `storage_liveness` variable)
448
+ storage_liveness. intersect ( & liveness. outs [ block] ) ;
413
449
414
- // Locals live are live at this point only if they are used across suspension points
415
- // and their storage is live
416
- live_locals. intersect ( & liveness. outs [ block] ) ;
450
+ let live_locals = storage_liveness;
417
451
418
452
// Add the locals life at this suspension point to the set of locals which live across
419
453
// any suspension points
0 commit comments