@@ -493,13 +493,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
493493 let discr_ty = adt. repr . discr_type ( ) . to_ty ( self . tcx ( ) ) ;
494494 let discr = Lvalue :: Local ( self . new_temp ( discr_ty) ) ;
495495 let discr_rv = Rvalue :: Discriminant ( self . lvalue . clone ( ) ) ;
496- let switch_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
497- statements : vec ! [
498- Statement {
499- source_info: self . source_info,
500- kind: StatementKind :: Assign ( discr. clone( ) , discr_rv) ,
501- }
502- ] ,
496+ let switch_block = BasicBlockData {
497+ statements : vec ! [ self . assign( & discr, discr_rv) ] ,
503498 terminator : Some ( Terminator {
504499 source_info : self . source_info ,
505500 kind : TerminatorKind :: SwitchInt {
@@ -510,7 +505,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
510505 }
511506 } ) ,
512507 is_cleanup : unwind. is_cleanup ( ) ,
513- } ) ;
508+ } ;
509+ let switch_block = self . elaborator . patch ( ) . new_block ( switch_block) ;
514510 self . drop_flag_test_block ( switch_block, succ, unwind)
515511 }
516512
@@ -531,14 +527,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
531527 let ref_lvalue = self . new_temp ( ref_ty) ;
532528 let unit_temp = Lvalue :: Local ( self . new_temp ( tcx. mk_nil ( ) ) ) ;
533529
534- self . elaborator . patch ( ) . new_block ( BasicBlockData {
535- statements : vec ! [ Statement {
536- source_info: self . source_info,
537- kind: StatementKind :: Assign (
538- Lvalue :: Local ( ref_lvalue) ,
539- Rvalue :: Ref ( tcx. types. re_erased, BorrowKind :: Mut , self . lvalue. clone( ) )
540- )
541- } ] ,
530+ let result = BasicBlockData {
531+ statements : vec ! [ self . assign(
532+ & Lvalue :: Local ( ref_lvalue) ,
533+ Rvalue :: Ref ( tcx. types. re_erased, BorrowKind :: Mut , self . lvalue. clone( ) )
534+ ) ] ,
542535 terminator : Some ( Terminator {
543536 kind : TerminatorKind :: Call {
544537 func : Operand :: function_handle ( tcx, drop_fn. def_id , substs,
@@ -550,24 +543,33 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
550543 source_info : self . source_info
551544 } ) ,
552545 is_cleanup : unwind. is_cleanup ( ) ,
553- } )
546+ } ;
547+ self . elaborator . patch ( ) . new_block ( result)
554548 }
555549
556550 /// create a loop that drops an array:
551+ ///
552+
557553 ///
558554 /// loop-block:
559- /// can_go = index == len
555+ /// can_go = cur == length_or_end
560556 /// if can_go then succ else drop-block
561557 /// drop-block:
562- /// ptr = &mut LV[index]
563- /// index = index + 1
558+ /// if ptr_based {
559+ /// ptr = cur
560+ /// cur = cur.offset(1)
561+ /// } else {
562+ /// ptr = &mut LV[cur]
563+ /// cur = cur + 1
564+ /// }
564565 /// drop(ptr)
565566 fn drop_loop ( & mut self ,
566567 succ : BasicBlock ,
567- index : & Lvalue < ' tcx > ,
568- length : & Lvalue < ' tcx > ,
568+ cur : & Lvalue < ' tcx > ,
569+ length_or_end : & Lvalue < ' tcx > ,
569570 ety : Ty < ' tcx > ,
570- unwind : Unwind )
571+ unwind : Unwind ,
572+ ptr_based : bool )
571573 -> BasicBlock
572574 {
573575 let use_ = |lv : & Lvalue < ' tcx > | Operand :: Consume ( lv. clone ( ) ) ;
@@ -581,38 +583,44 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
581583 let can_go = & Lvalue :: Local ( self . new_temp ( tcx. types . bool ) ) ;
582584
583585 let one = self . constant_usize ( 1 ) ;
584- let drop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
586+ let ( ptr_next, cur_next) = if ptr_based {
587+ ( Rvalue :: Use ( use_ ( cur) ) ,
588+ Rvalue :: BinaryOp ( BinOp :: Offset , use_ ( cur) , one) )
589+ } else {
590+ ( Rvalue :: Ref (
591+ tcx. types . re_erased ,
592+ BorrowKind :: Mut ,
593+ self . lvalue . clone ( ) . index ( use_ ( cur) ) ) ,
594+ Rvalue :: BinaryOp ( BinOp :: Add , use_ ( cur) , one) )
595+ } ;
596+
597+ let drop_block = BasicBlockData {
585598 statements : vec ! [
586- Statement { source_info: self . source_info, kind: StatementKind :: Assign (
587- ptr. clone( ) , Rvalue :: Ref (
588- tcx. types. re_erased, BorrowKind :: Mut ,
589- self . lvalue. clone( ) . index( use_( index) )
590- ) ,
591- ) } ,
592- Statement { source_info: self . source_info, kind: StatementKind :: Assign (
593- index. clone( ) , Rvalue :: BinaryOp ( BinOp :: Add , use_( index) , one)
594- ) } ,
599+ self . assign( ptr, ptr_next) ,
600+ self . assign( cur, cur_next)
595601 ] ,
596602 is_cleanup : unwind. is_cleanup ( ) ,
597603 terminator : Some ( Terminator {
598604 source_info : self . source_info ,
599605 // this gets overwritten by drop elaboration.
600606 kind : TerminatorKind :: Unreachable ,
601607 } )
602- } ) ;
608+ } ;
609+ let drop_block = self . elaborator . patch ( ) . new_block ( drop_block) ;
603610
604- let loop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
611+ let loop_block = BasicBlockData {
605612 statements : vec ! [
606- Statement { source_info : self . source_info , kind : StatementKind :: Assign (
607- can_go . clone ( ) , Rvalue :: BinaryOp ( BinOp :: Eq , use_ ( index ) , use_( length ) )
608- ) } ,
613+ self . assign ( can_go , Rvalue :: BinaryOp ( BinOp :: Eq ,
614+ use_( cur ) ,
615+ use_ ( length_or_end ) ) )
609616 ] ,
610617 is_cleanup : unwind. is_cleanup ( ) ,
611618 terminator : Some ( Terminator {
612619 source_info : self . source_info ,
613620 kind : TerminatorKind :: if_ ( tcx, use_ ( can_go) , succ, drop_block)
614621 } )
615- } ) ;
622+ } ;
623+ let loop_block = self . elaborator . patch ( ) . new_block ( loop_block) ;
616624
617625 self . elaborator . patch ( ) . patch_terminator ( drop_block, TerminatorKind :: Drop {
618626 location : ptr. clone ( ) . deref ( ) ,
@@ -625,29 +633,97 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
625633
626634 fn open_drop_for_array ( & mut self , ety : Ty < ' tcx > ) -> BasicBlock {
627635 debug ! ( "open_drop_for_array({:?})" , ety) ;
628- // FIXME: using an index instead of a pointer to avoid
629- // special-casing ZSTs.
636+
637+ // if size_of::<ety>() == 0 {
638+ // index_based_loop
639+ // } else {
640+ // ptr_based_loop
641+ // }
642+
643+ let tcx = self . tcx ( ) ;
644+
645+ let use_ = |lv : & Lvalue < ' tcx > | Operand :: Consume ( lv. clone ( ) ) ;
646+ let size = & Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
647+ let size_is_zero = & Lvalue :: Local ( self . new_temp ( tcx. types . bool ) ) ;
648+ let base_block = BasicBlockData {
649+ statements : vec ! [
650+ self . assign( size, Rvalue :: NullaryOp ( NullOp :: SizeOf , ety) ) ,
651+ self . assign( size_is_zero, Rvalue :: BinaryOp ( BinOp :: Eq ,
652+ use_( size) ,
653+ self . constant_usize( 0 ) ) )
654+ ] ,
655+ is_cleanup : self . unwind . is_cleanup ( ) ,
656+ terminator : Some ( Terminator {
657+ source_info : self . source_info ,
658+ kind : TerminatorKind :: if_ (
659+ tcx,
660+ use_ ( size_is_zero) ,
661+ self . drop_loop_pair ( ety, false ) ,
662+ self . drop_loop_pair ( ety, true )
663+ )
664+ } )
665+ } ;
666+ self . elaborator . patch ( ) . new_block ( base_block)
667+ }
668+
669+ // create a pair of drop-loops of `lvalue`, which drops its contents
670+ // even in the case of 1 panic. If `ptr_based`, create a pointer loop,
671+ // otherwise create an index loop.
672+ fn drop_loop_pair ( & mut self , ety : Ty < ' tcx > , ptr_based : bool ) -> BasicBlock {
673+ debug ! ( "drop_loop_pair({:?}, {:?})" , ety, ptr_based) ;
630674 let tcx = self . tcx ( ) ;
631- let index = & Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
632- let length = & Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
675+ let iter_ty = if ptr_based {
676+ tcx. mk_ptr ( ty:: TypeAndMut { ty : ety, mutbl : hir:: Mutability :: MutMutable } )
677+ } else {
678+ tcx. types . usize
679+ } ;
680+
681+ let cur = Lvalue :: Local ( self . new_temp ( iter_ty) ) ;
682+ let length = Lvalue :: Local ( self . new_temp ( tcx. types . usize ) ) ;
683+ let length_or_end = if ptr_based {
684+ Lvalue :: Local ( self . new_temp ( iter_ty) )
685+ } else {
686+ length. clone ( )
687+ } ;
633688
634689 let unwind = self . unwind . map ( |unwind| {
635- self . drop_loop ( unwind, index, length, ety, Unwind :: InCleanup )
690+ self . drop_loop ( unwind,
691+ & cur,
692+ & length_or_end,
693+ ety,
694+ Unwind :: InCleanup ,
695+ ptr_based)
636696 } ) ;
637697
638698 let succ = self . succ ; // FIXME(#6393)
639- let loop_block = self . drop_loop ( succ, index, length, ety, unwind) ;
699+ let loop_block = self . drop_loop (
700+ succ,
701+ & cur,
702+ & length_or_end,
703+ ety,
704+ unwind,
705+ ptr_based) ;
640706
641707 let zero = self . constant_usize ( 0 ) ;
708+ let mut drop_block_stmts = vec ! [ ] ;
709+ drop_block_stmts. push ( self . assign ( & length, Rvalue :: Len ( self . lvalue . clone ( ) ) ) ) ;
710+ if ptr_based {
711+ // cur = &LV[0];
712+ // end = &LV[len];
713+ drop_block_stmts. push ( self . assign ( & cur, Rvalue :: Ref (
714+ tcx. types . re_erased , BorrowKind :: Mut ,
715+ self . lvalue . clone ( ) . index ( zero. clone ( ) )
716+ ) ) ) ;
717+ drop_block_stmts. push ( self . assign ( & length_or_end, Rvalue :: Ref (
718+ tcx. types . re_erased , BorrowKind :: Mut ,
719+ self . lvalue . clone ( ) . index ( Operand :: Consume ( length. clone ( ) ) )
720+ ) ) ) ;
721+ } else {
722+ // index = 0 (length already pushed)
723+ drop_block_stmts. push ( self . assign ( & cur, Rvalue :: Use ( zero) ) ) ;
724+ }
642725 let drop_block = self . elaborator . patch ( ) . new_block ( BasicBlockData {
643- statements : vec ! [
644- Statement { source_info: self . source_info, kind: StatementKind :: Assign (
645- length. clone( ) , Rvalue :: Len ( self . lvalue. clone( ) )
646- ) } ,
647- Statement { source_info: self . source_info, kind: StatementKind :: Assign (
648- index. clone( ) , Rvalue :: Use ( zero) ,
649- ) } ,
650- ] ,
726+ statements : drop_block_stmts,
651727 is_cleanup : unwind. is_cleanup ( ) ,
652728 terminator : Some ( Terminator {
653729 source_info : self . source_info ,
@@ -836,4 +912,11 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
836912 literal : Literal :: Value { value : ConstVal :: Integral ( self . tcx ( ) . const_usize ( val) ) }
837913 } )
838914 }
915+
916+ fn assign ( & self , lhs : & Lvalue < ' tcx > , rhs : Rvalue < ' tcx > ) -> Statement < ' tcx > {
917+ Statement {
918+ source_info : self . source_info ,
919+ kind : StatementKind :: Assign ( lhs. clone ( ) , rhs)
920+ }
921+ }
839922}
0 commit comments