@@ -294,22 +294,25 @@ fn build_clone_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
294
294
{
295
295
debug ! ( "build_clone_shim(def_id={:?})" , def_id) ;
296
296
297
- let mut builder = CloneShimBuilder :: new ( tcx, def_id) ;
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 < _ > > ( ) ,
309
- AggregateKind :: Closure ( def_id, substs )
311
+ dest , src ,
312
+ substs . upvar_tys ( def_id, tcx )
310
313
)
311
314
}
312
- ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( & * * tys , AggregateKind :: Tuple ) ,
315
+ ty:: TyTuple ( tys, _) => builder. tuple_like_shim ( dest , src , tys . iter ( ) . cloned ( ) ) ,
313
316
_ => {
314
317
bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty)
315
318
}
@@ -328,8 +331,14 @@ struct CloneShimBuilder<'a, 'tcx: 'a> {
328
331
}
329
332
330
333
impl < ' 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) ;
333
342
let sig = tcx. erase_late_bound_regions ( & sig) ;
334
343
let span = tcx. def_span ( def_id) ;
335
344
@@ -377,6 +386,14 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
377
386
} )
378
387
}
379
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
+
380
397
fn make_statement ( & self , kind : StatementKind < ' tcx > ) -> Statement < ' tcx > {
381
398
Statement {
382
399
source_info : self . source_info ( ) ,
@@ -404,11 +421,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
404
421
405
422
fn make_clone_call (
406
423
& mut self ,
424
+ dest : Place < ' tcx > ,
425
+ src : Place < ' tcx > ,
407
426
ty : Ty < ' tcx > ,
408
- rcvr_field : Place < ' tcx > ,
409
427
next : BasicBlock ,
410
428
cleanup : BasicBlock
411
- ) -> Place < ' tcx > {
429
+ ) {
412
430
let tcx = self . tcx ;
413
431
414
432
let substs = Substs :: for_item (
@@ -439,25 +457,21 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
439
457
} )
440
458
) ;
441
459
442
- let loc = self . make_place ( Mutability :: Not , ty) ;
443
-
444
- // `let ref_loc: &ty = &rcvr_field;`
460
+ // `let ref_loc: &ty = &src;`
445
461
let statement = self . make_statement (
446
462
StatementKind :: Assign (
447
463
ref_loc. clone ( ) ,
448
- Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , rcvr_field )
464
+ Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , src )
449
465
)
450
466
) ;
451
467
452
468
// `let loc = Clone::clone(ref_loc);`
453
469
self . block ( vec ! [ statement] , TerminatorKind :: Call {
454
470
func,
455
471
args : vec ! [ Operand :: Move ( ref_loc) ] ,
456
- destination : Some ( ( loc . clone ( ) , next) ) ,
472
+ destination : Some ( ( dest , next) ) ,
457
473
cleanup : Some ( cleanup) ,
458
474
} , false ) ;
459
-
460
- loc
461
475
}
462
476
463
477
fn loop_header (
@@ -500,14 +514,12 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
500
514
}
501
515
}
502
516
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 ) {
504
518
let tcx = self . tcx ;
505
519
let span = self . span ;
506
- let rcvr = Place :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
507
520
508
521
let beg = self . local_decls . push ( temp_decl ( Mutability :: Mut , tcx. types . usize , span) ) ;
509
522
let end = self . make_place ( Mutability :: Not , tcx. types . usize ) ;
510
- let ret = self . make_place ( Mutability :: Mut , tcx. mk_array ( ty, len) ) ;
511
523
512
524
// BB #0
513
525
// `let mut beg = 0;`
@@ -537,23 +549,17 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
537
549
self . loop_header ( Place :: Local ( beg) , end, BasicBlock :: new ( 2 ) , BasicBlock :: new ( 4 ) , false ) ;
538
550
539
551
// BB #2
540
- // `let cloned = Clone::clone(rcvr [beg])`;
552
+ // `dest[i] = Clone::clone(src [beg])`;
541
553
// 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 ) ) ;
544
558
545
559
// BB #3
546
- // `ret[beg] = cloned;`
547
560
// `beg = beg + 1;`
548
561
// `goto #1`;
549
- let ret_field = ret. clone ( ) . index ( beg) ;
550
562
let statements = vec ! [
551
- self . make_statement(
552
- StatementKind :: Assign (
553
- ret_field,
554
- Rvalue :: Use ( Operand :: Move ( cloned) )
555
- )
556
- ) ,
557
563
self . make_statement(
558
564
StatementKind :: Assign (
559
565
Place :: Local ( beg) ,
@@ -568,14 +574,8 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
568
574
self . block ( statements, TerminatorKind :: Goto { target : BasicBlock :: new ( 1 ) } , false ) ;
569
575
570
576
// 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 ) ;
579
579
580
580
// BB #5 (cleanup)
581
581
// `let end = beg;`
@@ -600,9 +600,9 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
600
600
BasicBlock :: new ( 7 ) , BasicBlock :: new ( 9 ) , true ) ;
601
601
602
602
// BB #7 (cleanup)
603
- // `drop(ret [beg])`;
603
+ // `drop(dest [beg])`;
604
604
self . block ( vec ! [ ] , TerminatorKind :: Drop {
605
- location : ret . index ( beg) ,
605
+ location : dest . index ( beg) ,
606
606
target : BasicBlock :: new ( 8 ) ,
607
607
unwind : None ,
608
608
} , true ) ;
@@ -626,55 +626,50 @@ impl<'a, 'tcx> CloneShimBuilder<'a, 'tcx> {
626
626
self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
627
627
}
628
628
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) ;
634
636
635
- let rcvr = Place :: Local ( Local :: new ( 1 + 0 ) ) . deref ( ) ;
637
+ let dest_field = dest . clone ( ) . field ( field , ity ) ;
636
638
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 ) ;
640
644
641
645
// BB #(2i)
642
- // `returns[i] = Clone::clone(&rcvr .i);`
646
+ // `dest.i = Clone::clone(&src .i);`
643
647
// 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,
651
654
) ;
652
655
653
656
// 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 ( ) {
658
658
// Drop previous field and goto previous cleanup block.
659
659
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 ,
662
662
unwind : None ,
663
663
} , true ) ;
664
+ } else {
665
+ // Nothing to drop, just resume.
666
+ self . block ( vec ! [ ] , TerminatorKind :: Resume , true ) ;
664
667
}
668
+
669
+ previous_field = Some ( ( dest_field, cleanup_block) ) ;
665
670
}
666
671
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 ) ;
678
673
}
679
674
}
680
675
0 commit comments