|
52 | 52 |
|
53 | 53 | mod by_move_body; |
54 | 54 | mod drop; |
55 | | -use std::{iter, ops}; |
| 55 | +use std::ops; |
56 | 56 |
|
57 | 57 | pub(super) use by_move_body::coroutine_by_move_body_def_id; |
58 | 58 | use drop::{ |
59 | 59 | cleanup_async_drops, create_coroutine_drop_shim, create_coroutine_drop_shim_async, |
60 | 60 | create_coroutine_drop_shim_proxy_async, elaborate_coroutine_drops, expand_async_drops, |
61 | 61 | has_expandable_async_drops, insert_clean_drop, |
62 | 62 | }; |
| 63 | +use itertools::izip; |
63 | 64 | use rustc_abi::{FieldIdx, VariantIdx}; |
64 | 65 | use rustc_data_structures::fx::FxHashSet; |
65 | 66 | use rustc_errors::pluralize; |
@@ -730,53 +731,53 @@ fn locals_live_across_suspend_points<'tcx>( |
730 | 731 | let mut live_locals_at_any_suspension_point = DenseBitSet::new_empty(body.local_decls.len()); |
731 | 732 |
|
732 | 733 | for (block, data) in body.basic_blocks.iter_enumerated() { |
733 | | - if let TerminatorKind::Yield { .. } = data.terminator().kind { |
734 | | - let loc = Location { block, statement_index: data.statements.len() }; |
735 | | - |
736 | | - liveness.seek_to_block_end(block); |
737 | | - let mut live_locals = liveness.get().clone(); |
738 | | - |
739 | | - if !movable { |
740 | | - // The `liveness` variable contains the liveness of MIR locals ignoring borrows. |
741 | | - // This is correct for movable coroutines since borrows cannot live across |
742 | | - // suspension points. However for immovable coroutines we need to account for |
743 | | - // borrows, so we conservatively assume that all borrowed locals are live until |
744 | | - // we find a StorageDead statement referencing the locals. |
745 | | - // To do this we just union our `liveness` result with `borrowed_locals`, which |
746 | | - // contains all the locals which has been borrowed before this suspension point. |
747 | | - // If a borrow is converted to a raw reference, we must also assume that it lives |
748 | | - // forever. Note that the final liveness is still bounded by the storage liveness |
749 | | - // of the local, which happens using the `intersect` operation below. |
750 | | - borrowed_locals_cursor2.seek_before_primary_effect(loc); |
751 | | - live_locals.union(borrowed_locals_cursor2.get()); |
752 | | - } |
| 734 | + let TerminatorKind::Yield { .. } = data.terminator().kind else { continue }; |
| 735 | + |
| 736 | + let loc = Location { block, statement_index: data.statements.len() }; |
| 737 | + |
| 738 | + liveness.seek_to_block_end(block); |
| 739 | + let mut live_locals = liveness.get().clone(); |
| 740 | + |
| 741 | + if !movable { |
| 742 | + // The `liveness` variable contains the liveness of MIR locals ignoring borrows. |
| 743 | + // This is correct for movable coroutines since borrows cannot live across |
| 744 | + // suspension points. However for immovable coroutines we need to account for |
| 745 | + // borrows, so we conservatively assume that all borrowed locals are live until |
| 746 | + // we find a StorageDead statement referencing the locals. |
| 747 | + // To do this we just union our `liveness` result with `borrowed_locals`, which |
| 748 | + // contains all the locals which has been borrowed before this suspension point. |
| 749 | + // If a borrow is converted to a raw reference, we must also assume that it lives |
| 750 | + // forever. Note that the final liveness is still bounded by the storage liveness |
| 751 | + // of the local, which happens using the `intersect` operation below. |
| 752 | + borrowed_locals_cursor2.seek_before_primary_effect(loc); |
| 753 | + live_locals.union(borrowed_locals_cursor2.get()); |
| 754 | + } |
753 | 755 |
|
754 | | - // Store the storage liveness for later use so we can restore the state |
755 | | - // after a suspension point |
756 | | - storage_live.seek_before_primary_effect(loc); |
757 | | - storage_liveness_map[block] = Some(storage_live.get().clone()); |
| 756 | + // Store the storage liveness for later use so we can restore the state |
| 757 | + // after a suspension point |
| 758 | + storage_live.seek_before_primary_effect(loc); |
| 759 | + storage_liveness_map[block] = Some(storage_live.get().clone()); |
758 | 760 |
|
759 | | - // Locals live are live at this point only if they are used across |
760 | | - // suspension points (the `liveness` variable) |
761 | | - // and their storage is required (the `storage_required` variable) |
762 | | - requires_storage_cursor.seek_before_primary_effect(loc); |
763 | | - live_locals.intersect(requires_storage_cursor.get()); |
| 761 | + // Locals live are live at this point only if they are used across |
| 762 | + // suspension points (the `liveness` variable) |
| 763 | + // and their storage is required (the `storage_required` variable) |
| 764 | + requires_storage_cursor.seek_before_primary_effect(loc); |
| 765 | + live_locals.intersect(requires_storage_cursor.get()); |
764 | 766 |
|
765 | | - // The coroutine argument is ignored. |
766 | | - live_locals.remove(SELF_ARG); |
| 767 | + // The coroutine argument is ignored. |
| 768 | + live_locals.remove(SELF_ARG); |
767 | 769 |
|
768 | | - debug!("loc = {:?}, live_locals = {:?}", loc, live_locals); |
| 770 | + debug!(?loc, ?live_locals); |
769 | 771 |
|
770 | | - // Add the locals live at this suspension point to the set of locals which live across |
771 | | - // any suspension points |
772 | | - live_locals_at_any_suspension_point.union(&live_locals); |
| 772 | + // Add the locals live at this suspension point to the set of locals which live across |
| 773 | + // any suspension points |
| 774 | + live_locals_at_any_suspension_point.union(&live_locals); |
773 | 775 |
|
774 | | - live_locals_at_suspension_points.push(live_locals); |
775 | | - source_info_at_suspension_points.push(data.terminator().source_info); |
776 | | - } |
| 776 | + live_locals_at_suspension_points.push(live_locals); |
| 777 | + source_info_at_suspension_points.push(data.terminator().source_info); |
777 | 778 | } |
778 | 779 |
|
779 | | - debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point); |
| 780 | + debug!(?live_locals_at_any_suspension_point); |
780 | 781 | let saved_locals = CoroutineSavedLocals(live_locals_at_any_suspension_point); |
781 | 782 |
|
782 | 783 | // Renumber our liveness_map bitsets to include only the locals we are |
@@ -977,8 +978,8 @@ fn compute_layout<'tcx>( |
977 | 978 | } = liveness; |
978 | 979 |
|
979 | 980 | // Gather live local types and their indices. |
980 | | - let mut locals = IndexVec::<CoroutineSavedLocal, _>::new(); |
981 | | - let mut tys = IndexVec::<CoroutineSavedLocal, _>::new(); |
| 981 | + let mut locals = IndexVec::<CoroutineSavedLocal, _>::with_capacity(saved_locals.domain_size()); |
| 982 | + let mut tys = IndexVec::<CoroutineSavedLocal, _>::with_capacity(saved_locals.domain_size()); |
982 | 983 | for (saved_local, local) in saved_locals.iter_enumerated() { |
983 | 984 | debug!("coroutine saved local {:?} => {:?}", saved_local, local); |
984 | 985 |
|
@@ -1012,38 +1013,39 @@ fn compute_layout<'tcx>( |
1012 | 1013 | // In debuginfo, these will correspond to the beginning (UNRESUMED) or end |
1013 | 1014 | // (RETURNED, POISONED) of the function. |
1014 | 1015 | let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span; |
1015 | | - let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [ |
| 1016 | + let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = IndexVec::with_capacity( |
| 1017 | + CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), |
| 1018 | + ); |
| 1019 | + variant_source_info.extend([ |
1016 | 1020 | SourceInfo::outermost(body_span.shrink_to_lo()), |
1017 | 1021 | SourceInfo::outermost(body_span.shrink_to_hi()), |
1018 | 1022 | SourceInfo::outermost(body_span.shrink_to_hi()), |
1019 | | - ] |
1020 | | - .iter() |
1021 | | - .copied() |
1022 | | - .collect(); |
| 1023 | + ]); |
1023 | 1024 |
|
1024 | 1025 | // Build the coroutine variant field list. |
1025 | 1026 | // Create a map from local indices to coroutine struct indices. |
1026 | | - let mut variant_fields: IndexVec<VariantIdx, IndexVec<FieldIdx, CoroutineSavedLocal>> = |
1027 | | - iter::repeat(IndexVec::new()).take(CoroutineArgs::RESERVED_VARIANTS).collect(); |
| 1027 | + let mut variant_fields: IndexVec<VariantIdx, _> = IndexVec::from_elem_n( |
| 1028 | + IndexVec::new(), |
| 1029 | + CoroutineArgs::RESERVED_VARIANTS + live_locals_at_suspension_points.len(), |
| 1030 | + ); |
1028 | 1031 | let mut remap = IndexVec::from_elem_n(None, saved_locals.domain_size()); |
1029 | | - for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() { |
1030 | | - let variant_index = |
1031 | | - VariantIdx::from(CoroutineArgs::RESERVED_VARIANTS + suspension_point_idx); |
1032 | | - let mut fields = IndexVec::new(); |
1033 | | - for (idx, saved_local) in live_locals.iter().enumerate() { |
1034 | | - fields.push(saved_local); |
| 1032 | + for (live_locals, &source_info_at_suspension_point, (variant_index, fields)) in izip!( |
| 1033 | + &live_locals_at_suspension_points, |
| 1034 | + &source_info_at_suspension_points, |
| 1035 | + variant_fields.iter_enumerated_mut().skip(CoroutineArgs::RESERVED_VARIANTS) |
| 1036 | + ) { |
| 1037 | + *fields = live_locals.iter().collect(); |
| 1038 | + for (idx, &saved_local) in fields.iter_enumerated() { |
1035 | 1039 | // Note that if a field is included in multiple variants, we will |
1036 | 1040 | // just use the first one here. That's fine; fields do not move |
1037 | 1041 | // around inside coroutines, so it doesn't matter which variant |
1038 | 1042 | // index we access them by. |
1039 | | - let idx = FieldIdx::from_usize(idx); |
1040 | 1043 | remap[locals[saved_local]] = Some((tys[saved_local].ty, variant_index, idx)); |
1041 | 1044 | } |
1042 | | - variant_fields.push(fields); |
1043 | | - variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]); |
| 1045 | + variant_source_info.push(source_info_at_suspension_point); |
1044 | 1046 | } |
1045 | | - debug!("coroutine variant_fields = {:?}", variant_fields); |
1046 | | - debug!("coroutine storage_conflicts = {:#?}", storage_conflicts); |
| 1047 | + debug!(?variant_fields); |
| 1048 | + debug!(?storage_conflicts); |
1047 | 1049 |
|
1048 | 1050 | let mut field_names = IndexVec::from_elem(None, &tys); |
1049 | 1051 | for var in &body.var_debug_info { |
|
0 commit comments