@@ -57,6 +57,7 @@ use crate::transform::no_landing_pads::no_landing_pads;
57
57
use crate :: transform:: simplify;
58
58
use crate :: transform:: { MirPass , MirSource } ;
59
59
use crate :: util:: dump_mir;
60
+ use crate :: util:: patch:: MirPatch ;
60
61
use crate :: util:: storage;
61
62
use rustc_data_structures:: fx:: FxHashMap ;
62
63
use rustc_hir as hir;
@@ -494,15 +495,15 @@ fn locals_live_across_suspend_points(
494
495
let mut live_locals_at_any_suspension_point = BitSet :: new_empty ( body. local_decls . len ( ) ) ;
495
496
496
497
for ( block, data) in body. basic_blocks ( ) . iter_enumerated ( ) {
497
- if !matches ! ( data. terminator( ) . kind, TerminatorKind :: Yield { .. } ) {
498
- continue ;
499
- }
500
-
501
498
// Store the storage liveness for later use so we can restore the state
502
499
// after a suspension point
503
500
storage_live. seek_to_block_end ( block) ;
504
501
storage_liveness_map[ block] = Some ( storage_live. get ( ) . clone ( ) ) ;
505
502
503
+ if !matches ! ( data. terminator( ) . kind, TerminatorKind :: Yield { .. } ) {
504
+ continue ;
505
+ }
506
+
506
507
let mut live_locals = locals_live_across_yield_point ( block) ;
507
508
508
509
// The combination of `MaybeInitializedLocals` and `MaybeBorrowedLocals` should be strictly
@@ -797,7 +798,6 @@ fn insert_switch<'tcx>(
797
798
fn elaborate_generator_drops < ' tcx > ( tcx : TyCtxt < ' tcx > , def_id : DefId , body : & mut Body < ' tcx > ) {
798
799
use crate :: shim:: DropShimElaborator ;
799
800
use crate :: util:: elaborate_drops:: { elaborate_drop, Unwind } ;
800
- use crate :: util:: patch:: MirPatch ;
801
801
802
802
// Note that `elaborate_drops` only drops the upvars of a generator, and
803
803
// this is ok because `open_drop` can only be reached within that own
@@ -1007,32 +1007,56 @@ fn create_generator_resume_function<'tcx>(
1007
1007
// Poison the generator when it unwinds
1008
1008
if can_unwind {
1009
1009
let source_info = SourceInfo :: outermost ( body. span ) ;
1010
- let poison_block = body. basic_blocks_mut ( ) . push ( BasicBlockData {
1010
+ let mut patch = MirPatch :: new ( body) ;
1011
+ let poison_block = patch. new_block ( BasicBlockData {
1011
1012
statements : vec ! [ transform. set_discr( VariantIdx :: new( POISONED ) , source_info) ] ,
1012
1013
terminator : Some ( Terminator { source_info, kind : TerminatorKind :: Resume } ) ,
1013
1014
is_cleanup : true ,
1014
1015
} ) ;
1015
1016
1016
- for ( idx, block) in body. basic_blocks_mut ( ) . iter_enumerated_mut ( ) {
1017
+ for ( idx, block) in body. basic_blocks ( ) . iter_enumerated ( ) {
1017
1018
let source_info = block. terminator ( ) . source_info ;
1019
+ let empty_liveness = BitSet :: new_empty ( 0 ) ;
1020
+ let storage_deads = transform
1021
+ . storage_liveness . get ( idx) . map ( |info| info. as_ref ( ) . unwrap ( ) ) . unwrap_or ( & empty_liveness)
1022
+ . iter ( )
1023
+ . filter ( |local| * local != SELF_ARG )
1024
+ . filter ( |local| !transform. always_live_locals . contains ( * local) )
1025
+ . filter ( |local| !transform. remap . contains_key ( local) )
1026
+ . map ( |local| StatementKind :: StorageDead ( local) ) ;
1018
1027
1019
1028
if let TerminatorKind :: Resume = block. terminator ( ) . kind {
1020
1029
// An existing `Resume` terminator is redirected to jump to our dedicated
1021
1030
// "poisoning block" above.
1022
- if idx != poison_block {
1023
- * block . terminator_mut ( ) = Terminator {
1024
- source_info ,
1025
- kind : TerminatorKind :: Goto { target : poison_block } ,
1026
- } ;
1031
+ patch . patch_terminator ( idx, TerminatorKind :: Goto { target : poison_block } ) ;
1032
+ // Before redirecting, we declare StorageDead for any variables
1033
+ // that might be StorageLive.
1034
+ for stmt_kind in storage_deads {
1035
+ patch . add_statement ( patch . terminator_loc ( body , idx ) , stmt_kind ) ;
1027
1036
}
1028
1037
} else if !block. is_cleanup {
1029
1038
// Any terminators that *can* unwind but don't have an unwind target set are also
1030
1039
// pointed at our poisoning block (unless they're part of the cleanup path).
1031
- if let Some ( unwind @ None ) = block. terminator_mut ( ) . unwind_mut ( ) {
1032
- * unwind = Some ( poison_block) ;
1040
+ let mut terminator = block. terminator ( ) . clone ( ) ;
1041
+ if let Some ( unwind @ None ) = terminator. unwind_mut ( ) {
1042
+ let storage_deads: Vec < _ > = storage_deads. map ( |kind| Statement { source_info, kind } ) . collect ( ) ;
1043
+ let target = if storage_deads. is_empty ( ) {
1044
+ poison_block
1045
+ } else {
1046
+ let storage_dead_block = patch. new_block ( BasicBlockData {
1047
+ statements : storage_deads,
1048
+ terminator : Some ( Terminator { source_info, kind : TerminatorKind :: Goto { target : poison_block } } ) ,
1049
+ is_cleanup : true ,
1050
+ } ) ;
1051
+ storage_dead_block
1052
+ } ;
1053
+ * unwind = Some ( target) ;
1054
+ patch. patch_terminator ( idx, terminator. kind ) ;
1033
1055
}
1034
1056
}
1035
1057
}
1058
+
1059
+ patch. apply ( body) ;
1036
1060
}
1037
1061
1038
1062
let mut cases = create_cases ( body, & transform, Operation :: Resume ) ;
@@ -1219,7 +1243,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1219
1243
1220
1244
// When first entering the generator, move the resume argument into its new local.
1221
1245
let source_info = SourceInfo :: outermost ( body. span ) ;
1222
- let stmts = & mut body. basic_blocks_mut ( ) [ BasicBlock :: new ( 0 ) ] . statements ;
1246
+ let stmts = & mut body. basic_blocks_mut ( ) [ START_BLOCK ] . statements ;
1223
1247
stmts. insert (
1224
1248
0 ,
1225
1249
Statement {
0 commit comments