26
26
//! }
27
27
//!
28
28
//! This pass computes the meaning of the state field and the MIR locals which are live
29
- //! across a suspension point. There are however two hardcoded generator states:
29
+ //! across a suspension point. There are however three hardcoded generator states:
30
30
//! 0 - Generator have not been resumed yet
31
31
//! 1 - Generator has returned / is completed
32
32
//! 2 - Generator has been poisoned
@@ -144,6 +144,13 @@ fn self_arg() -> Local {
144
144
Local :: new ( 1 )
145
145
}
146
146
147
+ /// Generator have not been resumed yet
148
+ const UNRESUMED : u32 = 0 ;
149
+ /// Generator has returned / is completed
150
+ const RETURNED : u32 = 1 ;
151
+ /// Generator has been poisoned
152
+ const POISONED : u32 = 2 ;
153
+
147
154
struct SuspensionPoint {
148
155
state : u32 ,
149
156
resume : BasicBlock ,
@@ -278,7 +285,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
278
285
279
286
state
280
287
} else { // Return
281
- 1 // state for returned
288
+ RETURNED // state for returned
282
289
} ;
283
290
data. statements . push ( self . set_state ( state, source_info) ) ;
284
291
data. terminator . as_mut ( ) . unwrap ( ) . kind = TerminatorKind :: Return ;
@@ -590,8 +597,15 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
590
597
let param_env = tcx. param_env ( def_id) ;
591
598
let gen = self_arg ( ) ;
592
599
593
- for block in mir. basic_blocks ( ) . indices ( ) {
594
- let ( target, unwind, source_info) = match mir. basic_blocks ( ) [ block] . terminator ( ) {
600
+ let mut elaborator = DropShimElaborator {
601
+ mir : mir,
602
+ patch : MirPatch :: new ( mir) ,
603
+ tcx,
604
+ param_env
605
+ } ;
606
+
607
+ for ( block, block_data) in mir. basic_blocks ( ) . iter_enumerated ( ) {
608
+ let ( target, unwind, source_info) = match block_data. terminator ( ) {
595
609
& Terminator {
596
610
source_info,
597
611
kind : TerminatorKind :: Drop {
@@ -602,31 +616,22 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
602
616
} if local == gen => ( target, unwind, source_info) ,
603
617
_ => continue ,
604
618
} ;
605
- let unwind = if let Some ( unwind) = unwind {
606
- Unwind :: To ( unwind)
607
- } else {
619
+ let unwind = if block_data. is_cleanup {
608
620
Unwind :: InCleanup
621
+ } else {
622
+ Unwind :: To ( unwind. unwrap_or_else ( || elaborator. patch . resume_block ( ) ) )
609
623
} ;
610
- let patch = {
611
- let mut elaborator = DropShimElaborator {
612
- mir : & mir,
613
- patch : MirPatch :: new ( mir) ,
614
- tcx,
615
- param_env
616
- } ;
617
- elaborate_drop (
618
- & mut elaborator,
619
- source_info,
620
- & Place :: Base ( PlaceBase :: Local ( gen) ) ,
621
- ( ) ,
622
- target,
623
- unwind,
624
- block
625
- ) ;
626
- elaborator. patch
627
- } ;
628
- patch. apply ( mir) ;
624
+ elaborate_drop (
625
+ & mut elaborator,
626
+ source_info,
627
+ & Place :: Base ( PlaceBase :: Local ( gen) ) ,
628
+ ( ) ,
629
+ target,
630
+ unwind,
631
+ block,
632
+ ) ;
629
633
}
634
+ elaborator. patch . apply ( mir) ;
630
635
}
631
636
632
637
fn create_generator_drop_shim < ' a , ' tcx > (
@@ -643,10 +648,10 @@ fn create_generator_drop_shim<'a, 'tcx>(
643
648
644
649
let mut cases = create_cases ( & mut mir, transform, |point| point. drop ) ;
645
650
646
- cases. insert ( 0 , ( 0 , drop_clean) ) ;
651
+ cases. insert ( 0 , ( UNRESUMED , drop_clean) ) ;
647
652
648
- // The returned state (1) and the poisoned state (2) falls through to
649
- // the default case which is just to return
653
+ // The returned state and the poisoned state fall through to the default
654
+ // case which is just to return
650
655
651
656
insert_switch ( tcx, & mut mir, cases, & transform, TerminatorKind :: Return ) ;
652
657
@@ -762,7 +767,7 @@ fn create_generator_resume_function<'a, 'tcx>(
762
767
for block in mir. basic_blocks_mut ( ) {
763
768
let source_info = block. terminator ( ) . source_info ;
764
769
if let & TerminatorKind :: Resume = & block. terminator ( ) . kind {
765
- block. statements . push ( transform. set_state ( 1 , source_info) ) ;
770
+ block. statements . push ( transform. set_state ( POISONED , source_info) ) ;
766
771
}
767
772
}
768
773
@@ -773,12 +778,12 @@ fn create_generator_resume_function<'a, 'tcx>(
773
778
GeneratorResumedAfterReturn ,
774
779
} ;
775
780
776
- // Jump to the entry point on the 0 state
777
- cases. insert ( 0 , ( 0 , BasicBlock :: new ( 0 ) ) ) ;
778
- // Panic when resumed on the returned (1) state
779
- cases. insert ( 1 , ( 1 , insert_panic_block ( tcx, mir, GeneratorResumedAfterReturn ) ) ) ;
780
- // Panic when resumed on the poisoned (2) state
781
- cases. insert ( 2 , ( 2 , insert_panic_block ( tcx, mir, GeneratorResumedAfterPanic ) ) ) ;
781
+ // Jump to the entry point on the unresumed
782
+ cases. insert ( 0 , ( UNRESUMED , BasicBlock :: new ( 0 ) ) ) ;
783
+ // Panic when resumed on the returned state
784
+ cases. insert ( 1 , ( RETURNED , insert_panic_block ( tcx, mir, GeneratorResumedAfterReturn ) ) ) ;
785
+ // Panic when resumed on the poisoned state
786
+ cases. insert ( 2 , ( POISONED , insert_panic_block ( tcx, mir, GeneratorResumedAfterPanic ) ) ) ;
782
787
783
788
insert_switch ( tcx, mir, cases, & transform, TerminatorKind :: Unreachable ) ;
784
789
@@ -942,7 +947,7 @@ impl MirPass for StateTransform {
942
947
mir. generator_layout = Some ( layout) ;
943
948
944
949
// Insert `drop(generator_struct)` which is used to drop upvars for generators in
945
- // the unresumed (0) state.
950
+ // the unresumed state.
946
951
// This is expanded to a drop ladder in `elaborate_generator_drops`.
947
952
let drop_clean = insert_clean_drop ( mir) ;
948
953
0 commit comments