@@ -729,23 +729,59 @@ where
729729 let tcx = self . tcx ( ) ;
730730
731731 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 < _ > > ( ) ;
749785 let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
750786 return self . drop_ladder ( fields, succ, unwind) . 0 ;
751787 }
@@ -824,7 +860,7 @@ where
824860 let size = size. try_eval_target_usize ( self . tcx ( ) , self . elaborator . param_env ( ) ) ;
825861 self . open_drop_for_array ( * ety, size)
826862 }
827- ty:: Slice ( ety) => self . open_drop_for_array ( * ety, None ) ,
863+ ty:: Slice ( ety) => self . drop_loop_pair ( * ety) ,
828864
829865 _ => span_bug ! ( self . source_info. span, "open drop from non-ADT `{:?}`" , ty) ,
830866 }
0 commit comments