1111use std:: fmt;
1212use rustc:: hir;
1313use rustc:: mir:: * ;
14- use rustc:: middle:: const_val:: ConstInt ;
14+ use rustc:: middle:: const_val:: { ConstInt , ConstVal } ;
1515use rustc:: middle:: lang_items;
1616use rustc:: ty:: { self , Ty } ;
1717use rustc:: ty:: subst:: { Kind , Substs } ;
@@ -535,6 +535,114 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
535535 } )
536536 }
537537
538+ /// create a loop that drops an array:
539+ ///
540+ /// loop-block:
541+ /// can_go = index < len
542+ /// if can_go then drop-block else succ
543+ /// drop-block:
544+ /// ptr = &mut LV[len]
545+ /// index = index + 1
546+ /// drop(ptr)
547+ fn drop_loop ( & mut self ,
548+ unwind : Option < BasicBlock > ,
549+ succ : BasicBlock ,
550+ index : & Lvalue < ' tcx > ,
551+ length : & Lvalue < ' tcx > ,
552+ ety : Ty < ' tcx > ,
553+ is_cleanup : bool )
554+ -> BasicBlock
555+ {
556+ let use_ = |lv : & Lvalue < ' tcx > | Operand :: Consume ( lv. clone ( ) ) ;
557+ let tcx = self . tcx ( ) ;
558+
559+ let ref_ty = tcx. mk_ref ( tcx. types . re_erased , ty:: TypeAndMut {
560+ ty : ety,
561+ mutbl : hir:: Mutability :: MutMutable
562+ } ) ;
563+ let ptr = & Lvalue :: Local ( self . new_temp ( ref_ty) ) ;
564+ let can_go = & Lvalue :: Local ( self . new_temp ( tcx. types . bool ) ) ;
565+
566+ let one = self . constant_usize ( 1 ) ;
567+ let drop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
568+ statements : vec ! [
569+ Statement { source_info: self . source_info, kind: StatementKind :: Assign (
570+ ptr. clone( ) , Rvalue :: Ref (
571+ tcx. types. re_erased, BorrowKind :: Mut ,
572+ self . lvalue. clone( ) . index( use_( index) )
573+ ) ,
574+ ) } ,
575+ Statement { source_info: self . source_info, kind: StatementKind :: Assign (
576+ index. clone( ) , Rvalue :: BinaryOp ( BinOp :: Add , use_( index) , one)
577+ ) } ,
578+ ] ,
579+ is_cleanup,
580+ terminator : Some ( Terminator {
581+ source_info : self . source_info ,
582+ kind : TerminatorKind :: Resume ,
583+ } )
584+ } ) ;
585+
586+ let loop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
587+ statements : vec ! [
588+ Statement { source_info: self . source_info, kind: StatementKind :: Assign (
589+ can_go. clone( ) , Rvalue :: BinaryOp ( BinOp :: Lt , use_( index) , use_( length) )
590+ ) } ,
591+ ] ,
592+ is_cleanup,
593+ terminator : Some ( Terminator {
594+ source_info : self . source_info ,
595+ kind : TerminatorKind :: if_ ( tcx, use_ ( can_go) , drop_block, succ)
596+ } )
597+ } ) ;
598+
599+ self . elaborator . patch ( ) . patch_terminator ( drop_block, TerminatorKind :: Drop {
600+ location : ptr. clone ( ) . deref ( ) ,
601+ target : loop_block,
602+ unwind : unwind
603+ } ) ;
604+
605+ loop_block
606+ }
607+
608+ fn open_drop_for_array ( & mut self , ety : Ty < ' tcx > ) -> BasicBlock {
609+ debug ! ( "open_drop_for_array({:?})" , ety) ;
610+ // FIXME: using an index instead of a pointer to avoid
611+ // special-casing ZSTs.
612+ let tcx = self . tcx ( ) ;
613+ let index = & Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
614+ let length = & Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
615+
616+ let unwind = self . unwind . map ( |unwind| {
617+ self . drop_loop ( None , unwind, index, length, ety, true )
618+ } ) ;
619+
620+ let is_cleanup = self . is_cleanup ;
621+ let succ = self . succ ; // FIXME(#6393)
622+ let loop_block = self . drop_loop ( unwind, succ, index, length, ety, is_cleanup) ;
623+
624+ let zero = self . constant_usize ( 0 ) ;
625+ let drop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
626+ statements : vec ! [
627+ Statement { source_info: self . source_info, kind: StatementKind :: Assign (
628+ length. clone( ) , Rvalue :: Len ( self . lvalue. clone( ) )
629+ ) } ,
630+ Statement { source_info: self . source_info, kind: StatementKind :: Assign (
631+ index. clone( ) , Rvalue :: Use ( zero) ,
632+ ) } ,
633+ ] ,
634+ is_cleanup,
635+ terminator : Some ( Terminator {
636+ source_info : self . source_info ,
637+ kind : TerminatorKind :: Goto { target : loop_block }
638+ } )
639+ } ) ;
640+
641+ // FIXME(#34708): handle partially-dropped array/slice elements.
642+ self . drop_flag_test_and_reset_block (
643+ is_cleanup, Some ( DropFlagMode :: Deep ) , drop_block, succ)
644+ }
645+
538646 /// The slow-path - create an "open", elaborated drop for a type
539647 /// which is moved-out-of only partially, and patch `bb` to a jump
540648 /// to it. This must not be called on ADTs with a destructor,
@@ -564,10 +672,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
564672 ty:: TyDynamic ( ..) => {
565673 self . complete_drop ( is_cleanup, Some ( DropFlagMode :: Deep ) , succ)
566674 }
567- ty:: TyArray ( ..) | ty:: TySlice ( ..) => {
568- // FIXME(#34708): handle partially-dropped
569- // array/slice elements.
570- self . complete_drop ( is_cleanup, Some ( DropFlagMode :: Deep ) , succ)
675+ ty:: TyArray ( ety, _) | ty:: TySlice ( ety) => {
676+ self . open_drop_for_array ( ety)
571677 }
572678 _ => bug ! ( "open drop from non-ADT `{:?}`" , ty)
573679 }
@@ -588,6 +694,17 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
588694 debug ! ( "complete_drop({:?},{:?})" , self , drop_mode) ;
589695
590696 let drop_block = self . drop_block ( is_cleanup, succ) ;
697+ self . drop_flag_test_and_reset_block ( is_cleanup, drop_mode, drop_block, succ)
698+ }
699+
700+ fn drop_flag_test_and_reset_block ( & mut self ,
701+ is_cleanup : bool ,
702+ drop_mode : Option < DropFlagMode > ,
703+ drop_block : BasicBlock ,
704+ succ : BasicBlock ) -> BasicBlock
705+ {
706+ debug ! ( "drop_flag_test_and_reset_block({:?},{:?})" , self , drop_mode) ;
707+
591708 if let Some ( mode) = drop_mode {
592709 let block_start = Location { block : drop_block, statement_index : 0 } ;
593710 self . elaborator . clear_drop_flag ( block_start, self . path , mode) ;
@@ -691,4 +808,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
691808 let mir = self . elaborator . mir ( ) ;
692809 self . elaborator . patch ( ) . terminator_loc ( mir, bb)
693810 }
811+
812+ fn constant_usize ( & self , val : usize ) -> Operand < ' tcx > {
813+ Operand :: Constant ( box Constant {
814+ span : self . source_info . span ,
815+ ty : self . tcx ( ) . types . usize ,
816+ literal : Literal :: Value { value : ConstVal :: Integral ( self . tcx ( ) . const_usize ( val) ) }
817+ } )
818+ }
694819}
0 commit comments