@@ -380,28 +380,35 @@ fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
380
380
PinArgVisitor { ref_gen_ty, tcx } . visit_body ( body) ;
381
381
}
382
382
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 > ,
385
392
body : & mut BodyAndCache < ' tcx > ,
386
393
tcx : TyCtxt < ' tcx > ,
387
394
) -> Local {
388
395
let source_info = source_info ( body) ;
389
- let new_ret = LocalDecl {
396
+ let new_decl = LocalDecl {
390
397
mutability : Mutability :: Mut ,
391
- ty : ret_ty ,
398
+ ty,
392
399
user_ty : UserTypeProjections :: none ( ) ,
393
400
source_info,
394
401
internal : false ,
395
402
is_block_tail : None ,
396
403
local_info : LocalInfo :: Other ,
397
404
} ;
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 ) ;
401
408
402
- RenameLocalVisitor { from : RETURN_PLACE , to : new_ret_local , tcx } . visit_body ( body) ;
409
+ RenameLocalVisitor { from : local , to : new_local , tcx } . visit_body ( body) ;
403
410
404
- new_ret_local
411
+ new_local
405
412
}
406
413
407
414
struct StorageIgnored ( liveness:: LiveVarSet ) ;
@@ -794,6 +801,10 @@ fn compute_layout<'tcx>(
794
801
( remap, layout, storage_liveness)
795
802
}
796
803
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.
797
808
fn insert_switch < ' tcx > (
798
809
body : & mut BodyAndCache < ' tcx > ,
799
810
cases : Vec < ( usize , BasicBlock ) > ,
@@ -1093,6 +1104,13 @@ fn create_cases<'tcx>(
1093
1104
1094
1105
// Create StorageLive instructions for locals with live storage
1095
1106
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
+
1096
1114
let l = Local :: new ( i) ;
1097
1115
if point. storage_liveness . contains ( l) && !transform. remap . contains_key ( & l) {
1098
1116
statements
@@ -1110,6 +1128,10 @@ fn create_cases<'tcx>(
1110
1128
Rvalue :: Use ( Operand :: Move ( resume_arg. into ( ) ) ) ,
1111
1129
) ) ,
1112
1130
} ) ;
1131
+ statements. push ( Statement {
1132
+ source_info,
1133
+ kind : StatementKind :: StorageDead ( resume_arg) ,
1134
+ } ) ;
1113
1135
}
1114
1136
1115
1137
// Then jump to the real target
@@ -1166,7 +1188,28 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
1166
1188
1167
1189
// We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
1168
1190
// 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
+ ) ;
1170
1213
1171
1214
// Extract locals which are live across suspension point into `layout`
1172
1215
// `remap` gives a mapping from local indices onto generator struct indices
0 commit comments