@@ -6,6 +6,7 @@ use rustc_index::Idx;
6
6
use rustc_middle:: mir:: patch:: MirPatch ;
7
7
use rustc_middle:: mir:: * ;
8
8
use rustc_middle:: span_bug;
9
+ use rustc_middle:: ty:: adjustment:: PointerCoercion ;
9
10
use rustc_middle:: ty:: util:: IntTypeExt ;
10
11
use rustc_middle:: ty:: { self , GenericArgsRef , Ty , TyCtxt } ;
11
12
use rustc_span:: DUMMY_SP ;
@@ -738,70 +739,52 @@ where
738
739
loop_block
739
740
}
740
741
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) ;
743
749
let tcx = self . tcx ( ) ;
744
750
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:?}" )
802
753
}
803
754
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)
805
788
}
806
789
807
790
/// Creates a pair of drop-loops of `place`, which drops its contents, even
@@ -817,10 +800,27 @@ where
817
800
818
801
let loop_block = self . drop_loop ( self . succ , cur, len, ety, unwind) ;
819
802
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
+
820
814
let zero = self . constant_usize ( 0 ) ;
821
815
let block = BasicBlockData {
822
816
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
+ ) ,
824
824
self . assign( cur. into( ) , Rvalue :: Use ( zero) ) ,
825
825
] ,
826
826
is_cleanup : unwind. is_cleanup ( ) ,
@@ -863,7 +863,7 @@ where
863
863
ty:: Dynamic ( ..) => self . complete_drop ( self . succ , self . unwind ) ,
864
864
ty:: Array ( ety, size) => {
865
865
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)
867
867
}
868
868
ty:: Slice ( ety) => self . drop_loop_pair ( * ety) ,
869
869
0 commit comments