@@ -294,22 +294,25 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
294294{
295295 debug ! ( "build_clone_shim(def_id={:?})" , def_id) ;
296296
297- let mut builder = CloneShimBuilder :: new ( tcx, def_id) ;
297+ 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 < _ > > ( ) ,
309- AggregateKind :: Closure ( def_id, substs )
311+ dest , src ,
312+ substs . upvar_tys ( def_id, tcx )
310313 )
311314 }
312- ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( & * * tys , AggregateKind :: Tuple ) ,
315+ ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( dest , src , tys . iter ( ) . cloned ( ) ) ,
313316 _ => {
314317 bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty)
315318 }
@@ -328,8 +331,14 @@ struct CloneShimBuilder<'a, 'tcx: 'a> {
328331}
329332
330333impl < ' a , ' tcx > CloneShimBuilder < ' a , ' tcx > {
331- fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , def_id : DefId ) -> Self {
332- let sig = tcx. fn_sig ( def_id) ;
334+ fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
335+ def_id : DefId ,
336+ self_ty : Ty < ' tcx > ) -> Self {
337+ // we must subst the self_ty because it's
338+ // otherwise going to be TySelf and we can't index
339+ // or access fields of a Place of type TySelf.
340+ let substs = tcx. mk_substs_trait ( self_ty, & [ ] ) ;
341+ let sig = tcx. fn_sig ( def_id) . subst ( tcx, substs) ;
333342 let sig = tcx. erase_late_bound_regions ( & sig) ;
334343 let span = tcx. def_span ( def_id) ;
335344
@@ -377,6 +386,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
377386 } )
378387 }
379388
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+
380397 fn make_statement ( & self , kind : StatementKind < ' tcx > ) -> Statement < ' tcx > {
381398 Statement {
382399 source_info : self . source_info ( ) ,
@@ -404,11 +421,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
404421
405422 fn make_clone_call (
406423 & mut self ,
424+ dest : Place < ' tcx > ,
425+ src : Place < ' tcx > ,
407426 ty : Ty < ' tcx > ,
408- rcvr_field : Place < ' tcx > ,
409427 next : BasicBlock ,
410428 cleanup : BasicBlock
411- ) -> Place < ' tcx > {
429+ ) {
412430 let tcx = self . tcx ;
413431
414432 let substs = Substs :: for_item (
@@ -439,25 +457,21 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
439457 } )
440458 ) ;
441459
442- let loc = self . make_place ( Mutability :: Not , ty) ;
443-
444- // `let ref_loc: &ty = &rcvr_field;`
460+ // `let ref_loc: &ty = &src;`
445461 let statement = self . make_statement (
446462 StatementKind :: Assign (
447463 ref_loc. clone ( ) ,
448- Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , rcvr_field )
464+ Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , src )
449465 )
450466 ) ;
451467
452468 // `let loc = Clone::clone(ref_loc);`
453469 self . block ( vec ! [ statement] , TerminatorKind :: Call {
454470 func,
455471 args : vec ! [ Operand :: Move ( ref_loc) ] ,
456- destination : Some ( ( loc . clone ( ) , next) ) ,
472+ destination : Some ( ( dest , next) ) ,
457473 cleanup : Some ( cleanup) ,
458474 } , false ) ;
459-
460- loc
461475 }
462476
463477 fn loop_header (
@@ -500,14 +514,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
500514 }
501515 }
502516
503- 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 ) {
504518 let tcx = self . tcx ;
505519 let span = self . span ;
506- let rcvr = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
507520
508521 let beg = self . local_decls . push ( temp_decl ( Mutability :: Mut , tcx. types . usize , span) ) ;
509522 let end = self . make_place ( Mutability :: Not , tcx. types . usize ) ;
510- let ret = self . make_place ( Mutability :: Mut , tcx. mk_array ( ty, len) ) ;
511523
512524 // BB #0
513525 // `let mut beg = 0;`
@@ -537,23 +549,17 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
537549 self . loop_header ( Place :: Local ( beg) , end, BasicBlock :: new ( 2 ) , BasicBlock :: new ( 4 ) , false ) ;
538550
539551 // BB #2
540- // `let cloned = Clone::clone(rcvr [beg])`;
552+ // `dest[i] = Clone::clone(src [beg])`;
541553 // Goto #3 if ok, #5 if unwinding happens.
542- let rcvr_field = rcvr. clone ( ) . index ( beg) ;
543- let cloned = self . make_clone_call ( ty, rcvr_field, BasicBlock :: new ( 3 ) , BasicBlock :: new ( 5 ) ) ;
554+ let dest_field = dest. clone ( ) . index ( beg) ;
555+ let src_field = src. clone ( ) . index ( beg) ;
556+ self . make_clone_call ( dest_field, src_field, ty, BasicBlock :: new ( 3 ) ,
557+ BasicBlock :: new ( 5 ) ) ;
544558
545559 // BB #3
546- // `ret[beg] = cloned;`
547560 // `beg = beg + 1;`
548561 // `goto #1`;
549- let ret_field = ret. clone ( ) . index ( beg) ;
550562 let statements = vec ! [
551- self . make_statement(
552- StatementKind :: Assign (
553- ret_field,
554- Rvalue :: Use ( Operand :: Move ( cloned) )
555- )
556- ) ,
557563 self . make_statement(
558564 StatementKind :: Assign (
559565 Place :: Local ( beg) ,
@@ -568,14 +574,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
568574 self . block ( statements, TerminatorKind :: Goto { target : BasicBlock :: new ( 1 ) } , false ) ;
569575
570576 // BB #4
571- // `return ret;`
572- let ret_statement = self . make_statement (
573- StatementKind :: Assign (
574- Place :: Local ( RETURN_PLACE ) ,
575- Rvalue :: Use ( Operand :: Move ( ret. clone ( ) ) ) ,
576- )
577- ) ;
578- self . block ( vec ! [ ret_statement] , TerminatorKind :: Return , false ) ;
577+ // `return dest;`
578+ self . block ( vec ! [ ] , TerminatorKind :: Return , false ) ;
579579
580580 // BB #5 (cleanup)
581581 // `let end = beg;`
@@ -600,9 +600,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
600600 BasicBlock :: new ( 7 ) , BasicBlock :: new ( 9 ) , true ) ;
601601
602602 // BB #7 (cleanup)
603- // `drop(ret [beg])`;
603+ // `drop(dest [beg])`;
604604 self . block ( vec ! [ ] , TerminatorKind :: Drop {
605- location : ret . index ( beg) ,
605+ location : dest . index ( beg) ,
606606 target : BasicBlock :: new ( 8 ) ,
607607 unwind : None ,
608608 } , true ) ;
@@ -626,55 +626,50 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
626626 self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
627627 }
628628
629- fn tuple_like_shim ( & mut self , tys : & [ ty:: Ty < ' tcx > ] , kind : AggregateKind < ' tcx > ) {
630- match kind {
631- AggregateKind :: Tuple | AggregateKind :: Closure ( ..) => ( ) ,
632- _ => bug ! ( "only tuples and closures are accepted" ) ,
633- } ;
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 ( ) {
634+ let field = Field :: new ( i) ;
635+ let src_field = src. clone ( ) . field ( field, ity) ;
634636
635- let rcvr = Place :: Local ( Local :: new ( 1 + 0 ) ) . deref ( ) ;
637+ let dest_field = dest . clone ( ) . field ( field , ity ) ;
636638
637- let mut returns = Vec :: new ( ) ;
638- for ( i, ity) in tys. iter ( ) . enumerate ( ) {
639- let rcvr_field = rcvr. clone ( ) . field ( Field :: new ( i) , * 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 ) ;
640644
641645 // BB #(2i)
642- // `returns[i] = Clone::clone(&rcvr .i);`
646+ // `dest.i = Clone::clone(&src .i);`
643647 // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
644- returns. push (
645- self . make_clone_call (
646- * ity,
647- rcvr_field,
648- BasicBlock :: new ( 2 * i + 2 ) ,
649- BasicBlock :: new ( 2 * i + 1 ) ,
650- )
648+ self . make_clone_call (
649+ dest_field. clone ( ) ,
650+ src_field,
651+ ity,
652+ next_block,
653+ cleanup_block,
651654 ) ;
652655
653656 // BB #(2i + 1) (cleanup)
654- if i == 0 {
655- // Nothing to drop, just resume.
656- self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
657- } else {
657+ if let Some ( ( previous_field, previous_cleanup) ) = previous_field. take ( ) {
658658 // Drop previous field and goto previous cleanup block.
659659 self . block ( vec ! [ ] , TerminatorKind :: Drop {
660- location : returns [ i - 1 ] . clone ( ) ,
661- target : BasicBlock :: new ( 2 * i - 1 ) ,
660+ location : previous_field ,
661+ target : previous_cleanup ,
662662 unwind : None ,
663663 } , true ) ;
664+ } else {
665+ // Nothing to drop, just resume.
666+ self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
664667 }
668+
669+ previous_field = Some ( ( dest_field, cleanup_block) ) ;
665670 }
666671
667- // `return kind(returns[0], returns[1], ..., returns[tys.len() - 1]);`
668- let ret_statement = self . make_statement (
669- StatementKind :: Assign (
670- Place :: Local ( RETURN_PLACE ) ,
671- Rvalue :: Aggregate (
672- box kind,
673- returns. into_iter ( ) . map ( Operand :: Move ) . collect ( )
674- )
675- )
676- ) ;
677- self . block ( vec ! [ ret_statement] , TerminatorKind :: Return , false ) ;
672+ self . block ( vec ! [ ] , TerminatorKind :: Return , false ) ;
678673 }
679674}
680675
0 commit comments