@@ -6,6 +6,7 @@ use rustc_index::Idx;
66use rustc_middle:: mir:: patch:: MirPatch ;
77use rustc_middle:: mir:: * ;
88use rustc_middle:: span_bug;
9+ use rustc_middle:: ty:: adjustment:: PointerCoercion ;
910use rustc_middle:: ty:: util:: IntTypeExt ;
1011use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
1112use rustc_span:: DUMMY_SP ;
@@ -738,70 +739,52 @@ where
738739 loop_block
739740 }
740741
741- fn open_drop_for_array ( & mut self , ety : Ty < ' tcx > , opt_size : Option < u64 > ) -> BasicBlock {
742- debug ! ( "open_drop_for_array({:?}, {:?})" , ety, opt_size) ;
742+ fn open_drop_for_array (
743+ & mut self ,
744+ place_ty : Ty < ' tcx > ,
745+ element_ty : Ty < ' tcx > ,
746+ opt_size : Option < u64 > ,
747+ ) -> BasicBlock {
748+ debug ! ( "open_drop_for_array({:?}, {:?})" , element_ty, opt_size) ;
743749 let tcx = self . tcx ( ) ;
744750
745- if let Some ( size) = opt_size {
746- enum ProjectionKind < Path > {
747- Drop ( std:: ops:: Range < u64 > ) ,
748- Keep ( u64 , Path ) ,
749- }
750- // Previously, we'd make a projection for every element in the array and create a drop
751- // ladder if any `array_subpath` was `Some`, i.e. moving out with an array pattern.
752- // This caused huge memory usage when generating the drops for large arrays, so we instead
753- // record the *subslices* which are dropped and the *indexes* which are kept
754- let mut drop_ranges = vec ! [ ] ;
755- let mut dropping = true ;
756- let mut start = 0 ;
757- for i in 0 ..size {
758- let path = self . elaborator . array_subpath ( self . path , i, size) ;
759- if dropping && path. is_some ( ) {
760- drop_ranges. push ( ProjectionKind :: Drop ( start..i) ) ;
761- dropping = false ;
762- } else if !dropping && path. is_none ( ) {
763- dropping = true ;
764- start = i;
765- }
766- if let Some ( path) = path {
767- drop_ranges. push ( ProjectionKind :: Keep ( i, path) ) ;
768- }
769- }
770- if !drop_ranges. is_empty ( ) {
771- if dropping {
772- drop_ranges. push ( ProjectionKind :: Drop ( start..size) ) ;
773- }
774- let fields = drop_ranges
775- . iter ( )
776- . rev ( )
777- . map ( |p| {
778- let ( project, path) = match p {
779- ProjectionKind :: Drop ( r) => (
780- ProjectionElem :: Subslice {
781- from : r. start ,
782- to : r. end ,
783- from_end : false ,
784- } ,
785- None ,
786- ) ,
787- & ProjectionKind :: Keep ( offset, path) => (
788- ProjectionElem :: ConstantIndex {
789- offset,
790- min_length : size,
791- from_end : false ,
792- } ,
793- Some ( path) ,
794- ) ,
795- } ;
796- ( tcx. mk_place_elem ( self . place , project) , path)
797- } )
798- . collect :: < Vec < _ > > ( ) ;
799- let ( succ, unwind) = self . drop_ladder_bottom ( ) ;
800- return self . drop_ladder ( fields, succ, unwind) . 0 ;
801- }
751+ if let Some ( 0 ) = opt_size {
752+ span_bug ! ( self . source_info. span, "Opened drop for zero-length array of {element_ty:?}" )
802753 }
803754
804- self . drop_loop_pair ( ety)
755+ let array_ptr_ty = Ty :: new_mut_ptr ( tcx, place_ty) ;
756+ let array_ptr = self . new_temp ( array_ptr_ty) ;
757+ let slice_ty = Ty :: new_slice ( tcx, element_ty) ;
758+ let slice_ptr_ty = Ty :: new_mut_ptr ( tcx, slice_ty) ;
759+ let slice_ptr = self . new_temp ( slice_ptr_ty) ;
760+
761+ let unsize_and_drop_block = BasicBlockData {
762+ statements : vec ! [
763+ self . assign( Place :: from( array_ptr) , Rvalue :: RawPtr ( Mutability :: Mut , self . place) ) ,
764+ self . assign(
765+ Place :: from( slice_ptr) ,
766+ Rvalue :: Cast (
767+ CastKind :: PointerCoercion (
768+ PointerCoercion :: Unsize ,
769+ CoercionSource :: Implicit ,
770+ ) ,
771+ Operand :: Move ( Place :: from( array_ptr) ) ,
772+ slice_ptr_ty,
773+ ) ,
774+ ) ,
775+ ] ,
776+ is_cleanup : self . unwind . is_cleanup ( ) ,
777+ terminator : Some ( Terminator {
778+ source_info : self . source_info ,
779+ kind : TerminatorKind :: Drop {
780+ place : Place :: from ( slice_ptr) . project_deeper ( & [ PlaceElem :: Deref ] , tcx) ,
781+ target : self . succ ,
782+ unwind : self . unwind . into_action ( ) ,
783+ replace : false ,
784+ } ,
785+ } ) ,
786+ } ;
787+ self . elaborator . patch ( ) . new_block ( unsize_and_drop_block)
805788 }
806789
807790 /// Creates a pair of drop-loops of `place`, which drops its contents, even
@@ -817,10 +800,27 @@ where
817800
818801 let loop_block = self . drop_loop ( self . succ , cur, len, ety, unwind) ;
819802
803+ let place_ty = self . place_ty ( self . place ) ;
804+ assert ! ( place_ty. is_slice( ) , "Expected slice, got {place_ty:?}" ) ;
805+
806+ let [ PlaceElem :: Deref ] = self . place . projection . as_slice ( ) else {
807+ span_bug ! (
808+ self . source_info. span,
809+ "Expected place for slice drop shim to be *_n, but it's {:?}" ,
810+ self . place,
811+ ) ;
812+ } ;
813+
820814 let zero = self . constant_usize ( 0 ) ;
821815 let block = BasicBlockData {
822816 statements : vec ! [
823- self . assign( len. into( ) , Rvalue :: Len ( self . place) ) ,
817+ self . assign(
818+ len. into( ) ,
819+ Rvalue :: UnaryOp (
820+ UnOp :: PtrMetadata ,
821+ Operand :: Copy ( Place :: from( self . place. local) ) ,
822+ ) ,
823+ ) ,
824824 self . assign( cur. into( ) , Rvalue :: Use ( zero) ) ,
825825 ] ,
826826 is_cleanup : unwind. is_cleanup ( ) ,
@@ -863,7 +863,7 @@ where
863863 ty:: Dynamic ( ..) => self . complete_drop ( self . succ , self . unwind ) ,
864864 ty:: Array ( ety, size) => {
865865 let size = size. try_to_target_usize ( self . tcx ( ) ) ;
866- self . open_drop_for_array ( * ety, size)
866+ self . open_drop_for_array ( ty , * ety, size)
867867 }
868868 ty:: Slice ( ety) => self . drop_loop_pair ( * ety) ,
869869
0 commit comments