@@ -297,18 +297,22 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
297297 let mut builder = CloneShimBuilder :: new ( tcx, def_id, self_ty) ;
298298 let is_copy = !self_ty. moves_by_default ( tcx, tcx. param_env ( def_id) , builder. span ) ;
299299
300+ let dest = Place :: Local ( RETURN_PLACE ) ;
301+ let src = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
302+
300303 match self_ty. sty {
301304 _ if is_copy => builder. copy_shim ( ) ,
302305 ty:: TyArray ( ty, len) => {
303306 let len = len. val . to_const_int ( ) . unwrap ( ) . to_u64 ( ) . unwrap ( ) ;
304- builder. array_shim ( ty, len)
307+ builder. array_shim ( dest , src , ty, len)
305308 }
306309 ty:: TyClosure ( def_id, substs) => {
307310 builder. tuple_like_shim (
308- & substs. upvar_tys ( def_id, tcx) . collect :: < Vec < _ > > ( )
311+ dest, src,
312+ substs. upvar_tys ( def_id, tcx)
309313 )
310314 }
311- ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( & * * tys) ,
315+ ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( dest , src , tys. iter ( ) . cloned ( ) ) ,
312316 _ => {
313317 bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty)
314318 }
@@ -382,6 +386,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
382386 } )
383387 }
384388
389+ /// Gives the index of an upcoming BasicBlock, with an offset.
390+ /// offset=0 will give you the index of the next BasicBlock,
391+ /// offset=1 will give the index of the next-to-next block,
392+ /// offset=-1 will give you the index of the last-created block
393+ fn block_index_offset ( & mut self , offset : usize ) -> BasicBlock {
394+ BasicBlock :: new ( self . blocks . len ( ) + offset)
395+ }
396+
385397 fn make_statement ( & self , kind : StatementKind < ' tcx > ) -> Statement < ' tcx > {
386398 Statement {
387399 source_info : self . source_info ( ) ,
@@ -502,11 +514,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
502514 }
503515 }
504516
505- fn array_shim ( & mut self , ty : Ty < ' tcx > , len : u64 ) {
517+ fn array_shim ( & mut self , dest : Place < ' tcx > , src : Place < ' tcx > , ty : Ty < ' tcx > , len : u64 ) {
506518 let tcx = self . tcx ;
507519 let span = self . span ;
508- let src = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
509- let dest = Place :: Local ( RETURN_PLACE ) ;
510520
511521 let beg = self . local_decls . push ( temp_decl ( Mutability :: Mut , tcx. types . usize , span) ) ;
512522 let end = self . make_place ( Mutability :: Not , tcx. types . usize ) ;
@@ -616,42 +626,47 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
616626 self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
617627 }
618628
619- fn tuple_like_shim ( & mut self , tys : & [ ty:: Ty < ' tcx > ] ) {
620- let rcvr = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
621-
622- let mut previous_place = None ;
623- let return_place = Place :: Local ( RETURN_PLACE ) ;
624- for ( i, ity) in tys. iter ( ) . enumerate ( ) {
629+ fn tuple_like_shim < I > ( & mut self , dest : Place < ' tcx > ,
630+ src : Place < ' tcx > , tys : I )
631+ where I : Iterator < Item = ty:: Ty < ' tcx > > {
632+ let mut previous_field = None ;
633+ for ( i, ity) in tys. enumerate ( ) {
625634 let field = Field :: new ( i) ;
626- let rcvr_field = rcvr. clone ( ) . field ( field, * ity) ;
635+ let src_field = src. clone ( ) . field ( field, ity) ;
636+
637+ let dest_field = dest. clone ( ) . field ( field, ity) ;
627638
628- let place = return_place. clone ( ) . field ( field, * ity) ;
639+ // #(2i + 1) is the cleanup block for the previous clone operation
640+ let cleanup_block = self . block_index_offset ( 1 ) ;
641+ // #(2i + 2) is the next cloning block
642+ // (or the Return terminator if this is the last block)
643+ let next_block = self . block_index_offset ( 2 ) ;
629644
630645 // BB #(2i)
631- // `returns[i] = Clone::clone(&rcvr .i);`
646+ // `dest.i = Clone::clone(&src .i);`
632647 // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
633648 self . make_clone_call (
634- place . clone ( ) ,
635- rcvr_field ,
636- * ity,
637- BasicBlock :: new ( 2 * i + 2 ) ,
638- BasicBlock :: new ( 2 * i + 1 ) ,
649+ dest_field . clone ( ) ,
650+ src_field ,
651+ ity,
652+ next_block ,
653+ cleanup_block ,
639654 ) ;
640655
641656 // BB #(2i + 1) (cleanup)
642- if let Some ( previous_place ) = previous_place . take ( ) {
657+ if let Some ( ( previous_field , previous_cleanup ) ) = previous_field . take ( ) {
643658 // Drop previous field and goto previous cleanup block.
644659 self . block ( vec ! [ ] , TerminatorKind :: Drop {
645- location : previous_place ,
646- target : BasicBlock :: new ( 2 * i - 1 ) ,
660+ location : previous_field ,
661+ target : previous_cleanup ,
647662 unwind : None ,
648663 } , true ) ;
649664 } else {
650665 // Nothing to drop, just resume.
651666 self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
652667 }
653668
654- previous_place = Some ( place ) ;
669+ previous_field = Some ( ( dest_field , cleanup_block ) ) ;
655670 }
656671
657672 self . block ( vec ! [ ] , TerminatorKind :: Return , false ) ;
0 commit comments