@@ -1077,31 +1077,42 @@ fn compute_layout<'tcx>(
10771077/// Replaces the entry point of `body` with a block that switches on the coroutine discriminant and
10781078/// dispatches to blocks according to `cases`.
10791079///
1080- /// After this function, the former entry point of the function will be bb1 .
1080+ /// After this function, the former entry point of the function will be the last block .
10811081fn insert_switch < ' tcx > (
10821082 body : & mut Body < ' tcx > ,
10831083 cases : Vec < ( usize , BasicBlock ) > ,
10841084 transform : & TransformVisitor < ' tcx > ,
10851085 default_block : BasicBlock ,
10861086) {
10871087 let ( assign, discr) = transform. get_discr ( body) ;
1088- let switch_targets =
1089- SwitchTargets :: new ( cases. iter ( ) . map ( |( i, bb) | ( ( * i) as u128 , * bb) ) , default_block) ;
1090- let switch = TerminatorKind :: SwitchInt { discr : Operand :: Move ( discr) , targets : switch_targets } ;
10911088
1092- let source_info = SourceInfo :: outermost ( body. span ) ;
1093- body. basic_blocks_mut ( ) . raw . insert (
1094- 0 ,
1095- BasicBlockData :: new_stmts (
1096- vec ! [ assign] ,
1097- Some ( Terminator { source_info, kind : switch } ) ,
1098- false ,
1099- ) ,
1089+ // MIR validation ensures that no block targets `ENTRY_BLOCK`.
1090+ #[ cfg( debug_assertions) ]
1091+ for bb in body. basic_blocks . iter ( ) {
1092+ for target in bb. terminator ( ) . successors ( ) {
1093+ assert_ne ! ( target, START_BLOCK ) ;
1094+ }
1095+ }
1096+
1097+ // Add the switch as entry block, and put the former entry block at the end.
1098+ let former_entry = std:: mem:: replace (
1099+ & mut body. basic_blocks_mut ( ) [ START_BLOCK ] ,
1100+ BasicBlockData :: new_stmts ( vec ! [ assign] , None , false ) ,
11001101 ) ;
1102+ let former_entry = body. basic_blocks_mut ( ) . push ( former_entry) ;
11011103
1102- for b in body. basic_blocks_mut ( ) . iter_mut ( ) {
1103- b. terminator_mut ( ) . successors_mut ( |target| * target += 1 ) ;
1104+ // We may point to `START_BLOCK` in our `cases`, replace it with `former_entry`.
1105+ let mut switch_targets =
1106+ SwitchTargets :: new ( cases. iter ( ) . map ( |( i, bb) | ( ( * i) as u128 , * bb) ) , default_block) ;
1107+ for bb in switch_targets. all_targets_mut ( ) {
1108+ if * bb == START_BLOCK {
1109+ * bb = former_entry;
1110+ }
11041111 }
1112+
1113+ let switch = TerminatorKind :: SwitchInt { discr : Operand :: Move ( discr) , targets : switch_targets } ;
1114+ body. basic_blocks_mut ( ) [ START_BLOCK ] . terminator =
1115+ Some ( Terminator { source_info : SourceInfo :: outermost ( body. span ) , kind : switch } ) ;
11051116}
11061117
11071118fn insert_term_block < ' tcx > ( body : & mut Body < ' tcx > , kind : TerminatorKind < ' tcx > ) -> BasicBlock {
0 commit comments