@@ -735,53 +735,53 @@ fn locals_live_across_suspend_points<'tcx>(
735735 let mut live_locals_at_any_suspension_point = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ;
736736
737737 for ( block, data) in body. basic_blocks . iter_enumerated ( ) {
738- if let TerminatorKind :: Yield { .. } = data. terminator ( ) . kind {
739- let loc = Location { block, statement_index : data. statements . len ( ) } ;
740-
741- liveness. seek_to_block_end ( block) ;
742- let mut live_locals = liveness. get ( ) . clone ( ) ;
743-
744- if !movable {
745- // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
746- // This is correct for movable coroutines since borrows cannot live across
747- // suspension points. However for immovable coroutines we need to account for
748- // borrows, so we conservatively assume that all borrowed locals are live until
749- // we find a StorageDead statement referencing the locals.
750- // To do this we just union our `liveness` result with `borrowed_locals`, which
751- // contains all the locals which has been borrowed before this suspension point.
752- // If a borrow is converted to a raw reference, we must also assume that it lives
753- // forever. Note that the final liveness is still bounded by the storage liveness
754- // of the local, which happens using the `intersect` operation below.
755- borrowed_locals_cursor2. seek_before_primary_effect ( loc) ;
756- live_locals. union ( borrowed_locals_cursor2. get ( ) ) ;
757- }
738+ let TerminatorKind :: Yield { .. } = data. terminator ( ) . kind else { continue } ;
739+
740+ let loc = Location { block, statement_index : data. statements . len ( ) } ;
741+
742+ liveness. seek_to_block_end ( block) ;
743+ let mut live_locals = liveness. get ( ) . clone ( ) ;
744+
745+ if !movable {
746+ // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
747+ // This is correct for movable coroutines since borrows cannot live across
748+ // suspension points. However for immovable coroutines we need to account for
749+ // borrows, so we conservatively assume that all borrowed locals are live until
750+ // we find a StorageDead statement referencing the locals.
751+ // To do this we just union our `liveness` result with `borrowed_locals`, which
752+ // contains all the locals which has been borrowed before this suspension point.
753+ // If a borrow is converted to a raw reference, we must also assume that it lives
754+ // forever. Note that the final liveness is still bounded by the storage liveness
755+ // of the local, which happens using the `intersect` operation below.
756+ borrowed_locals_cursor2. seek_before_primary_effect ( loc) ;
757+ live_locals. union ( borrowed_locals_cursor2. get ( ) ) ;
758+ }
758759
759- // Store the storage liveness for later use so we can restore the state
760- // after a suspension point
761- storage_live. seek_before_primary_effect ( loc) ;
762- storage_liveness_map[ block] = Some ( storage_live. get ( ) . clone ( ) ) ;
760+ // Store the storage liveness for later use so we can restore the state
761+ // after a suspension point
762+ storage_live. seek_before_primary_effect ( loc) ;
763+ storage_liveness_map[ block] = Some ( storage_live. get ( ) . clone ( ) ) ;
763764
764- // Locals live are live at this point only if they are used across
765- // suspension points (the `liveness` variable)
766- // and their storage is required (the `storage_required` variable)
767- requires_storage_cursor. seek_before_primary_effect ( loc) ;
768- live_locals. intersect ( requires_storage_cursor. get ( ) ) ;
765+ // Locals live are live at this point only if they are used across
766+ // suspension points (the `liveness` variable)
767+ // and their storage is required (the `storage_required` variable)
768+ requires_storage_cursor. seek_before_primary_effect ( loc) ;
769+ live_locals. intersect ( requires_storage_cursor. get ( ) ) ;
769770
770- // The coroutine argument is ignored.
771- live_locals. remove ( SELF_ARG ) ;
771+ // The coroutine argument is ignored.
772+ live_locals. remove ( SELF_ARG ) ;
772773
773- debug ! ( "loc = {:?}, live_locals = {:?}" , loc, live_locals) ;
774+ debug ! ( ? loc, ? live_locals) ;
774775
775- // Add the locals live at this suspension point to the set of locals which live across
776- // any suspension points
777- live_locals_at_any_suspension_point. union ( & live_locals) ;
776+ // Add the locals live at this suspension point to the set of locals which live across
777+ // any suspension points
778+ live_locals_at_any_suspension_point. union ( & live_locals) ;
778779
779- live_locals_at_suspension_points. push ( live_locals) ;
780- source_info_at_suspension_points. push ( data. terminator ( ) . source_info ) ;
781- }
780+ live_locals_at_suspension_points. push ( live_locals) ;
781+ source_info_at_suspension_points. push ( data. terminator ( ) . source_info ) ;
782782 }
783783
784- debug ! ( "live_locals_anywhere = {:?}" , live_locals_at_any_suspension_point) ;
784+ debug ! ( ? live_locals_at_any_suspension_point) ;
785785 let saved_locals = CoroutineSavedLocals ( live_locals_at_any_suspension_point) ;
786786
787787 // Renumber our liveness_map bitsets to include only the locals we are
@@ -982,71 +982,70 @@ fn compute_layout<'tcx>(
982982 } = liveness;
983983
984984 // Gather live local types and their indices.
985- let mut locals = IndexVec :: < CoroutineSavedLocal , _ > :: new ( ) ;
986- let mut tys = IndexVec :: < CoroutineSavedLocal , _ > :: new ( ) ;
987- for ( saved_local, local) in saved_locals. iter_enumerated ( ) {
988- debug ! ( "coroutine saved local {:?} => {:?}" , saved_local, local) ;
989-
990- locals. push ( local) ;
991- let decl = & body. local_decls [ local] ;
992- debug ! ( ?decl) ;
993-
994- // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared
995- // the information. This is alright, since `ignore_for_traits` is only relevant when
996- // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
997- // default.
998- let ignore_for_traits = match decl. local_info {
999- // Do not include raw pointers created from accessing `static` items, as those could
1000- // well be re-created by another access to the same static.
1001- ClearCrossCrate :: Set ( box LocalInfo :: StaticRef { is_thread_local, .. } ) => {
1002- !is_thread_local
1003- }
1004- // Fake borrows are only read by fake reads, so do not have any reality in
1005- // post-analysis MIR.
1006- ClearCrossCrate :: Set ( box LocalInfo :: FakeBorrow ) => true ,
1007- _ => false ,
1008- } ;
1009- let decl =
1010- CoroutineSavedTy { ty : decl. ty , source_info : decl. source_info , ignore_for_traits } ;
1011- debug ! ( ?decl) ;
985+ let ( locals, tys) : ( IndexVec < _ , _ > , IndexVec < _ , _ > ) = saved_locals
986+ . iter_enumerated ( )
987+ . map ( |( saved_local, local) | {
988+ debug ! ( "coroutine saved local {saved_local:?} => {local:?}" ) ;
1012989
1013- tys. push ( decl) ;
1014- }
990+ let decl = & body. local_decls [ local] ;
991+ debug ! ( ?decl) ;
992+
993+ // Do not `unwrap_crate_local` here, as post-borrowck cleanup may have already cleared
994+ // the information. This is alright, since `ignore_for_traits` is only relevant when
995+ // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
996+ // default.
997+ let ignore_for_traits = match decl. local_info {
998+ // Do not include raw pointers created from accessing `static` items, as those could
999+ // well be re-created by another access to the same static.
1000+ ClearCrossCrate :: Set ( box LocalInfo :: StaticRef { is_thread_local, .. } ) => {
1001+ !is_thread_local
1002+ }
1003+ // Fake borrows are only read by fake reads, so do not have any reality in
1004+ // post-analysis MIR.
1005+ ClearCrossCrate :: Set ( box LocalInfo :: FakeBorrow ) => true ,
1006+ _ => false ,
1007+ } ;
1008+ let decl =
1009+ CoroutineSavedTy { ty : decl. ty , source_info : decl. source_info , ignore_for_traits } ;
1010+ debug ! ( ?decl) ;
1011+
1012+ ( local, decl)
1013+ } )
1014+ . unzip ( ) ;
10151015
10161016 // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
10171017 // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
10181018 // (RETURNED, POISONED) of the function.
10191019 let body_span = body. source_scopes [ OUTERMOST_SOURCE_SCOPE ] . span ;
1020- let mut variant_source_info: IndexVec < VariantIdx , SourceInfo > = [
1020+ let variant_source_info: IndexVec < VariantIdx , SourceInfo > = [
10211021 SourceInfo :: outermost ( body_span. shrink_to_lo ( ) ) ,
10221022 SourceInfo :: outermost ( body_span. shrink_to_hi ( ) ) ,
10231023 SourceInfo :: outermost ( body_span. shrink_to_hi ( ) ) ,
10241024 ]
1025- . iter ( )
1026- . copied ( )
1025+ . into_iter ( )
1026+ . chain ( source_info_at_suspension_points )
10271027 . collect ( ) ;
10281028
10291029 // Build the coroutine variant field list.
10301030 // Create a map from local indices to coroutine struct indices.
1031- let mut variant_fields: IndexVec < VariantIdx , IndexVec < FieldIdx , CoroutineSavedLocal > > =
1032- iter:: repeat ( IndexVec :: new ( ) ) . take ( CoroutineArgs :: RESERVED_VARIANTS ) . collect ( ) ;
10331031 let mut remap = IndexVec :: from_elem_n ( None , saved_locals. domain_size ( ) ) ;
1034- for ( suspension_point_idx, live_locals) in live_locals_at_suspension_points. iter ( ) . enumerate ( ) {
1035- let variant_index =
1036- VariantIdx :: from ( CoroutineArgs :: RESERVED_VARIANTS + suspension_point_idx) ;
1037- let mut fields = IndexVec :: new ( ) ;
1038- for ( idx, saved_local) in live_locals. iter ( ) . enumerate ( ) {
1039- fields. push ( saved_local) ;
1040- // Note that if a field is included in multiple variants, we will
1041- // just use the first one here. That's fine; fields do not move
1042- // around inside coroutines, so it doesn't matter which variant
1043- // index we access them by.
1044- let idx = FieldIdx :: from_usize ( idx) ;
1045- remap[ locals[ saved_local] ] = Some ( ( tys[ saved_local] . ty , variant_index, idx) ) ;
1046- }
1047- variant_fields. push ( fields) ;
1048- variant_source_info. push ( source_info_at_suspension_points[ suspension_point_idx] ) ;
1049- }
1032+ let variant_fields = iter:: repeat_n ( IndexVec :: new ( ) , CoroutineArgs :: RESERVED_VARIANTS )
1033+ . chain ( live_locals_at_suspension_points. into_iter ( ) . enumerate ( ) . map (
1034+ |( suspension_point_idx, live_locals) | {
1035+ let variant_index =
1036+ VariantIdx :: from ( CoroutineArgs :: RESERVED_VARIANTS + suspension_point_idx) ;
1037+ let fields = live_locals. iter ( ) . collect :: < IndexVec < FieldIdx , _ > > ( ) ;
1038+ for ( idx, & saved_local) in fields. iter_enumerated ( ) {
1039+ // Note that if a field is included in multiple variants, we will
1040+ // just use the first one here. That's fine; fields do not move
1041+ // around inside coroutines, so it doesn't matter which variant
1042+ // index we access them by.
1043+ remap[ locals[ saved_local] ] = Some ( ( tys[ saved_local] . ty , variant_index, idx) ) ;
1044+ }
1045+ fields
1046+ } ,
1047+ ) )
1048+ . collect :: < IndexVec < VariantIdx , _ > > ( ) ;
10501049 debug ! ( "coroutine variant_fields = {:?}" , variant_fields) ;
10511050 debug ! ( "coroutine storage_conflicts = {:#?}" , storage_conflicts) ;
10521051
0 commit comments