@@ -729,23 +729,59 @@ where
729
729
let tcx = self . tcx ( ) ;
730
730
731
731
if let Some ( size) = opt_size {
732
- let fields: Vec < ( Place < ' tcx > , Option < D :: Path > ) > = ( 0 ..size)
733
- . map ( |i| {
734
- (
735
- tcx. mk_place_elem (
736
- self . place ,
737
- ProjectionElem :: ConstantIndex {
738
- offset : i,
739
- min_length : size,
740
- from_end : false ,
741
- } ,
742
- ) ,
743
- self . elaborator . array_subpath ( self . path , i, size) ,
744
- )
745
- } )
746
- . collect ( ) ;
747
-
748
- if fields. iter ( ) . any ( |( _, path) | path. is_some ( ) ) {
732
+ enum ProjectionKind < Path > {
733
+ Drop ( std:: ops:: Range < u64 > ) ,
734
+ Keep ( u64 , Path ) ,
735
+ }
736
+ // Previously, we'd make a projection for every element in the array and create a drop
737
+ // ladder if any `array_subpath` was `Some`, i.e. moving out with an array pattern.
738
+ // This caused huge memory usage when generating the drops for large arrays, so we instead
739
+ // record the *subslices* which are dropped and the *indexes* which are kept
740
+ let mut drop_ranges = vec ! [ ] ;
741
+ let mut dropping = true ;
742
+ let mut start = 0 ;
743
+ for i in 0 ..size {
744
+ let path = self . elaborator . array_subpath ( self . path , i, size) ;
745
+ if dropping && path. is_some ( ) {
746
+ drop_ranges. push ( ProjectionKind :: Drop ( start..i) ) ;
747
+ dropping = false ;
748
+ } else if !dropping && path. is_none ( ) {
749
+ dropping = true ;
750
+ start = i;
751
+ }
752
+ if let Some ( path) = path {
753
+ drop_ranges. push ( ProjectionKind :: Keep ( i, path) ) ;
754
+ }
755
+ }
756
+ if !drop_ranges. is_empty ( ) {
757
+ if dropping {
758
+ drop_ranges. push ( ProjectionKind :: Drop ( start..size) ) ;
759
+ }
760
+ let fields = drop_ranges
761
+ . iter ( )
762
+ . rev ( )
763
+ . map ( |p| {
764
+ let ( project, path) = match p {
765
+ ProjectionKind :: Drop ( r) => (
766
+ ProjectionElem :: Subslice {
767
+ from : r. start ,
768
+ to : r. end ,
769
+ from_end : false ,
770
+ } ,
771
+ None ,
772
+ ) ,
773
+ & ProjectionKind :: Keep ( offset, path) => (
774
+ ProjectionElem :: ConstantIndex {
775
+ offset,
776
+ min_length : size,
777
+ from_end : false ,
778
+ } ,
779
+ Some ( path) ,
780
+ ) ,
781
+ } ;
782
+ ( tcx. mk_place_elem ( self . place , project) , path)
783
+ } )
784
+ . collect :: < Vec < _ > > ( ) ;
749
785
let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
750
786
return self . drop_ladder ( fields, succ, unwind) . 0 ;
751
787
}
@@ -824,7 +860,7 @@ where
824
860
let size = size. try_eval_target_usize ( self . tcx ( ) , self . elaborator . param_env ( ) ) ;
825
861
self . open_drop_for_array ( * ety, size)
826
862
}
827
- ty:: Slice ( ety) => self . open_drop_for_array ( * ety, None ) ,
863
+ ty:: Slice ( ety) => self . drop_loop_pair ( * ety) ,
828
864
829
865
_ => span_bug ! ( self . source_info. span, "open drop from non-ADT `{:?}`" , ty) ,
830
866
}
0 commit comments