@@ -68,7 +68,7 @@ use rustc_hir::lang_items::LangItem;
6868use rustc_hir:: { CoroutineDesugaring , CoroutineKind } ;
6969use rustc_index:: bit_set:: { BitMatrix , DenseBitSet , GrowableBitSet } ;
7070use rustc_index:: { Idx , IndexVec } ;
71- use rustc_middle:: mir:: visit:: { MutVisitor , PlaceContext , Visitor } ;
71+ use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
7272use rustc_middle:: mir:: * ;
7373use rustc_middle:: ty:: util:: Discr ;
7474use rustc_middle:: ty:: {
@@ -110,6 +110,8 @@ impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
110110 fn visit_local ( & mut self , local : & mut Local , _: PlaceContext , _: Location ) {
111111 if * local == self . from {
112112 * local = self . to ;
113+ } else if * local == self . to {
114+ * local = self . from ;
113115 }
114116 }
115117
@@ -206,8 +208,8 @@ struct TransformVisitor<'tcx> {
206208 // The set of locals that have no `StorageLive`/`StorageDead` annotations.
207209 always_live_locals : DenseBitSet < Local > ,
208210
209- // The original RETURN_PLACE local
210- old_ret_local : Local ,
211+ // New local we just create to hold the `CoroutineState` value.
212+ new_ret_local : Local ,
211213
212214 old_yield_ty : Ty < ' tcx > ,
213215
@@ -344,9 +346,10 @@ impl<'tcx> TransformVisitor<'tcx> {
344346 }
345347 } ;
346348
349+ // Assign to `new_ret_local`, which will be replaced by `RETURN_PLACE` later.
347350 statements. push ( Statement :: new (
348351 source_info,
349- StatementKind :: Assign ( Box :: new ( ( Place :: return_place ( ) , rvalue) ) ) ,
352+ StatementKind :: Assign ( Box :: new ( ( self . new_ret_local . into ( ) , rvalue) ) ) ,
350353 ) ) ;
351354 }
352355
@@ -388,6 +391,20 @@ impl<'tcx> TransformVisitor<'tcx> {
388391 ) ;
389392 ( assign, temp)
390393 }
394+
395+ /// Swaps all references of `old_local` and `new_local`.
396+ #[ tracing:: instrument( level = "trace" , skip( self , body) ) ]
397+ fn replace_local ( & mut self , old_local : Local , new_local : Local , body : & mut Body < ' tcx > ) {
398+ body. local_decls . swap ( old_local, new_local) ;
399+
400+ let mut visitor = RenameLocalVisitor { from : old_local, to : new_local, tcx : self . tcx } ;
401+ visitor. visit_body ( body) ;
402+ for suspension in & mut self . suspension_points {
403+ let ctxt = PlaceContext :: MutatingUse ( MutatingUseContext :: Yield ) ;
404+ let location = Location { block : START_BLOCK , statement_index : 0 } ;
405+ visitor. visit_place ( & mut suspension. resume_arg , ctxt, location) ;
406+ }
407+ }
391408}
392409
393410impl < ' tcx > MutVisitor < ' tcx > for TransformVisitor < ' tcx > {
@@ -419,14 +436,24 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> {
419436 self . super_statement ( stmt, location) ;
420437 }
421438
439+ #[ tracing:: instrument( level = "trace" , skip( self , term) , ret) ]
440+ fn visit_terminator ( & mut self , term : & mut Terminator < ' tcx > , location : Location ) {
441+ if let TerminatorKind :: Return = term. kind {
442+ // `visit_basic_block_data` introduces `Return` terminators which read `RETURN_PLACE`.
443+ // But this `RETURN_PLACE` is already remapped, so we should not touch it again.
444+ return ;
445+ }
446+ self . super_terminator ( term, location) ;
447+ }
448+
422449 #[ tracing:: instrument( level = "trace" , skip( self , data) , ret) ]
423450 fn visit_basic_block_data ( & mut self , block : BasicBlock , data : & mut BasicBlockData < ' tcx > ) {
424451 match data. terminator ( ) . kind {
425452 TerminatorKind :: Return => {
426453 let source_info = data. terminator ( ) . source_info ;
427454 // We must assign the value first in case it gets declared dead below
428455 self . make_state (
429- Operand :: Move ( Place :: from ( self . old_ret_local ) ) ,
456+ Operand :: Move ( Place :: return_place ( ) ) ,
430457 source_info,
431458 true ,
432459 & mut data. statements ,
@@ -521,27 +548,6 @@ fn make_coroutine_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body
521548 . visit_body ( body) ;
522549}
523550
524- /// Allocates a new local and replaces all references of `local` with it. Returns the new local.
525- ///
526- /// `local` will be changed to a new local decl with type `ty`.
527- ///
528- /// Note that the new local will be uninitialized. It is the caller's responsibility to assign some
529- /// valid value to it before its first use.
530- fn replace_local < ' tcx > (
531- local : Local ,
532- ty : Ty < ' tcx > ,
533- body : & mut Body < ' tcx > ,
534- tcx : TyCtxt < ' tcx > ,
535- ) -> Local {
536- let new_decl = LocalDecl :: new ( ty, body. span ) ;
537- let new_local = body. local_decls . push ( new_decl) ;
538- body. local_decls . swap ( local, new_local) ;
539-
540- RenameLocalVisitor { from : local, to : new_local, tcx } . visit_body ( body) ;
541-
542- new_local
543- }
544-
545551/// Transforms the `body` of the coroutine applying the following transforms:
546552///
547553/// - Eliminates all the `get_context` calls that async lowering created.
@@ -1511,10 +1517,6 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15111517 }
15121518 } ;
15131519
1514- // We rename RETURN_PLACE which has type mir.return_ty to old_ret_local
1515- // RETURN_PLACE then is a fresh unused local with type ret_ty.
1516- let old_ret_local = replace_local ( RETURN_PLACE , new_ret_ty, body, tcx) ;
1517-
15181520 // We need to insert clean drop for unresumed state and perform drop elaboration
15191521 // (finally in open_drop_for_tuple) before async drop expansion.
15201522 // Async drops, produced by this drop elaboration, will be expanded,
@@ -1561,6 +1563,11 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15611563
15621564 let can_return = can_return ( tcx, body, body. typing_env ( tcx) ) ;
15631565
1566+ // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
1567+ // RETURN_PLACE then is a fresh unused local with type ret_ty.
1568+ let new_ret_local = body. local_decls . push ( LocalDecl :: new ( new_ret_ty, body. span ) ) ;
1569+ tracing:: trace!( ?new_ret_local) ;
1570+
15641571 // Run the transformation which converts Places from Local to coroutine struct
15651572 // accesses for locals in `remap`.
15661573 // It also rewrites `return x` and `yield y` as writing a new coroutine state and returning
@@ -1573,13 +1580,16 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
15731580 storage_liveness,
15741581 always_live_locals,
15751582 suspension_points : Vec :: new ( ) ,
1576- old_ret_local,
15771583 discr_ty,
1584+ new_ret_local,
15781585 old_ret_ty,
15791586 old_yield_ty,
15801587 } ;
15811588 transform. visit_body ( body) ;
15821589
1590+ // Swap the actual `RETURN_PLACE` and the provisional `new_ret_local`.
1591+ transform. replace_local ( RETURN_PLACE , new_ret_local, body) ;
1592+
15831593 // MIR parameters are not explicitly assigned-to when entering the MIR body.
15841594 // If we want to save their values inside the coroutine state, we need to do so explicitly.
15851595 let source_info = SourceInfo :: outermost ( body. span ) ;
0 commit comments