@@ -297,18 +297,22 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
297
297
let mut builder = CloneShimBuilder :: new ( tcx, def_id, self_ty) ;
298
298
let is_copy = !self_ty. moves_by_default ( tcx, tcx. param_env ( def_id) , builder. span ) ;
299
299
300
+ let dest = Place :: Local ( RETURN_PLACE ) ;
301
+ let src = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
302
+
300
303
match self_ty. sty {
301
304
_ if is_copy => builder. copy_shim ( ) ,
302
305
ty:: TyArray ( ty, len) => {
303
306
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)
305
308
}
306
309
ty:: TyClosure ( def_id, substs) => {
307
310
builder. tuple_like_shim (
308
- & substs. upvar_tys ( def_id, tcx) . collect :: < Vec < _ > > ( )
311
+ dest, src,
312
+ substs. upvar_tys ( def_id, tcx)
309
313
)
310
314
}
311
- ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( & * * tys) ,
315
+ ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( dest , src , tys. iter ( ) . cloned ( ) ) ,
312
316
_ => {
313
317
bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty)
314
318
}
@@ -382,6 +386,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
382
386
} )
383
387
}
384
388
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
+
385
397
fn make_statement ( & self , kind : StatementKind < ' tcx > ) -> Statement < ' tcx > {
386
398
Statement {
387
399
source_info : self . source_info ( ) ,
@@ -502,11 +514,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
502
514
}
503
515
}
504
516
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 ) {
506
518
let tcx = self . tcx ;
507
519
let span = self . span ;
508
- let src = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
509
- let dest = Place :: Local ( RETURN_PLACE ) ;
510
520
511
521
let beg = self . local_decls . push ( temp_decl ( Mutability :: Mut , tcx. types . usize , span) ) ;
512
522
let end = self . make_place ( Mutability :: Not , tcx. types . usize ) ;
@@ -616,42 +626,47 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
616
626
self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
617
627
}
618
628
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 ( ) {
625
634
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) ;
627
638
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 ) ;
629
644
630
645
// BB #(2i)
631
- // `returns[i] = Clone::clone(&rcvr .i);`
646
+ // `dest.i = Clone::clone(&src .i);`
632
647
// Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
633
648
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 ,
639
654
) ;
640
655
641
656
// BB #(2i + 1) (cleanup)
642
- if let Some ( previous_place ) = previous_place . take ( ) {
657
+ if let Some ( ( previous_field , previous_cleanup ) ) = previous_field . take ( ) {
643
658
// Drop previous field and goto previous cleanup block.
644
659
self . block ( vec ! [ ] , TerminatorKind :: Drop {
645
- location : previous_place ,
646
- target : BasicBlock :: new ( 2 * i - 1 ) ,
660
+ location : previous_field ,
661
+ target : previous_cleanup ,
647
662
unwind : None ,
648
663
} , true ) ;
649
664
} else {
650
665
// Nothing to drop, just resume.
651
666
self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
652
667
}
653
668
654
- previous_place = Some ( place ) ;
669
+ previous_field = Some ( ( dest_field , cleanup_block ) ) ;
655
670
}
656
671
657
672
self . block ( vec ! [ ] , TerminatorKind :: Return , false ) ;
0 commit comments