@@ -380,28 +380,35 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
380380 PinArgVisitor { ref_gen_ty, tcx } . visit_body ( body) ;
381381}
382382
383- fn replace_result_variable < ' tcx > (
384- ret_ty : Ty < ' tcx > ,
383+ /// Allocates a new local and replaces all references of `local` with it. Returns the new local.
384+ ///
385+ /// `local` will be changed to a new local decl with type `ty`.
386+ ///
387+ /// Note that the new local will be uninitialized. It is the caller's responsibility to assign some
388+ /// valid value to it before its first use.
389+ fn replace_local < ' tcx > (
390+ local : Local ,
391+ ty : Ty < ' tcx > ,
385392 body : & mut BodyAndCache < ' tcx > ,
386393 tcx : TyCtxt < ' tcx > ,
387394) -> Local {
388395 let source_info = source_info ( body) ;
389- let new_ret = LocalDecl {
396+ let new_decl = LocalDecl {
390397 mutability : Mutability :: Mut ,
391- ty : ret_ty ,
398+ ty,
392399 user_ty : UserTypeProjections :: none ( ) ,
393400 source_info,
394401 internal : false ,
395402 is_block_tail : None ,
396403 local_info : LocalInfo :: Other ,
397404 } ;
398- let new_ret_local = Local :: new ( body. local_decls . len ( ) ) ;
399- body. local_decls . push ( new_ret ) ;
400- body. local_decls . swap ( RETURN_PLACE , new_ret_local ) ;
405+ let new_local = Local :: new ( body. local_decls . len ( ) ) ;
406+ body. local_decls . push ( new_decl ) ;
407+ body. local_decls . swap ( local , new_local ) ;
401408
402- RenameLocalVisitor { from : RETURN_PLACE , to : new_ret_local , tcx } . visit_body ( body) ;
409+ RenameLocalVisitor { from : local , to : new_local , tcx } . visit_body ( body) ;
403410
404- new_ret_local
411+ new_local
405412}
406413
407414struct StorageIgnored ( liveness:: LiveVarSet ) ;
@@ -794,6 +801,10 @@ fn compute_layout<'tcx>(
794801 ( remap, layout, storage_liveness)
795802}
796803
804+ /// Replaces the entry point of `body` with a block that switches on the generator discriminant and
805+ /// dispatches to blocks according to `cases`.
806+ ///
807+ /// After this function, the former entry point of the function will be bb1.
797808fn insert_switch < ' tcx > (
798809 body : & mut BodyAndCache < ' tcx > ,
799810 cases : Vec < ( usize , BasicBlock ) > ,
@@ -1093,6 +1104,13 @@ fn create_cases<'tcx>(
10931104
10941105 // Create StorageLive instructions for locals with live storage
10951106 for i in 0 ..( body. local_decls . len ( ) ) {
1107+ if i == 2 {
1108+ // The resume argument is live on function entry. Don't insert a
1109+ // `StorageLive`, or the following `Assign` will read from uninitialized
1110+ // memory.
1111+ continue ;
1112+ }
1113+
10961114 let l = Local :: new ( i) ;
10971115 if point. storage_liveness . contains ( l) && !transform. remap . contains_key ( & l) {
10981116 statements
@@ -1110,6 +1128,10 @@ fn create_cases<'tcx>(
11101128 Rvalue :: Use ( Operand :: Move ( resume_arg. into ( ) ) ) ,
11111129 ) ) ,
11121130 } ) ;
1131+ statements. push ( Statement {
1132+ source_info,
1133+ kind : StatementKind :: StorageDead ( resume_arg) ,
1134+ } ) ;
11131135 }
11141136
11151137 // Then jump to the real target
@@ -1166,7 +1188,28 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
11661188
11671189 // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
11681190 // RETURN_PLACE then is a fresh unused local with type ret_ty.
1169- let new_ret_local = replace_result_variable ( ret_ty, body, tcx) ;
1191+ let new_ret_local = replace_local ( RETURN_PLACE , ret_ty, body, tcx) ;
1192+
1193+ // We also replace the resume argument and insert an `Assign`.
1194+ // This is needed because the resume argument might be live across a `yield`, and the
1195+ // transform assumes that any local live across a `yield` is assigned to before that.
1196+ let resume_local = Local :: new ( 2 ) ;
1197+ let new_resume_local =
1198+ replace_local ( resume_local, body. local_decls [ resume_local] . ty , body, tcx) ;
1199+
1200+ // When first entering the generator, move the resume argument into its new local.
1201+ let source_info = source_info ( body) ;
1202+ let stmts = & mut body. basic_blocks_mut ( ) [ BasicBlock :: new ( 0 ) ] . statements ;
1203+ stmts. insert (
1204+ 0 ,
1205+ Statement {
1206+ source_info,
1207+ kind : StatementKind :: Assign ( box (
1208+ new_resume_local. into ( ) ,
1209+ Rvalue :: Use ( Operand :: Move ( resume_local. into ( ) ) ) ,
1210+ ) ) ,
1211+ } ,
1212+ ) ;
11701213
11711214 // Extract locals which are live across suspension point into `layout`
11721215 // `remap` gives a mapping from local indices onto generator struct indices
0 commit comments