@@ -286,18 +286,26 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
286
286
let mut local_decls = local_decls_for_sig ( & sig, span) ;
287
287
let source_info = SourceInfo { span, scope : ARGUMENT_VISIBILITY_SCOPE } ;
288
288
289
+ let rcvr = Lvalue :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
290
+
289
291
let mut blocks = IndexVec :: new ( ) ;
290
- let block = |blocks : & mut IndexVec < _ , _ > , statement , kind| {
292
+ let block = |blocks : & mut IndexVec < _ , _ > , statements , kind, is_cleanup | {
291
293
blocks. push ( BasicBlockData {
292
- statements : vec ! [ statement ] ,
294
+ statements,
293
295
terminator : Some ( Terminator { source_info, kind } ) ,
294
- is_cleanup : false
296
+ is_cleanup,
295
297
} )
296
298
} ;
297
299
298
- let rcvr = Lvalue :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
300
+ let make_lvalue = |mutability, ty, local_decls : & mut IndexVec < _ , _ > | {
301
+ Lvalue :: Local (
302
+ local_decls. push ( temp_decl ( mutability, ty, span) )
303
+ )
304
+ } ;
299
305
300
- let call_clone = |i, ty, rcvr_field, blocks : & mut _ , local_decls : & mut IndexVec < _ , _ > | {
306
+ let call_clone = |ty, rcvr_field, next, cleanup,
307
+ blocks : & mut _ , local_decls : & mut IndexVec < _ , _ > |
308
+ {
301
309
// `func == Clone::clone(&ty) -> ty`
302
310
let substs = Substs :: for_item ( tcx, def_id, |_, _| tcx. types . re_erased , |_, _| ty) ;
303
311
let func = Operand :: Constant ( box Constant {
@@ -308,102 +316,281 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
308
316
} ,
309
317
} ) ;
310
318
311
- let ref_loc = Lvalue :: Local (
312
- local_decls. push ( temp_decl (
313
- Mutability :: Not ,
314
- tcx. mk_ref ( tcx. types . re_erased , ty:: TypeAndMut {
315
- ty,
316
- mutbl : hir:: Mutability :: MutImmutable ,
317
- } ) ,
318
- span
319
- ) )
320
- ) ;
321
-
322
- let loc = Lvalue :: Local (
323
- local_decls. push ( temp_decl (
324
- Mutability :: Not ,
319
+ let ref_loc = make_lvalue (
320
+ Mutability :: Not ,
321
+ tcx. mk_ref ( tcx. types . re_erased , ty:: TypeAndMut {
325
322
ty,
326
- span
327
- ) )
323
+ mutbl : hir:: Mutability :: MutImmutable ,
324
+ } ) ,
325
+ local_decls
328
326
) ;
329
327
328
+ let loc = make_lvalue ( Mutability :: Not , ty, local_decls) ;
329
+
330
330
// `let ref_loc: &ty = &rcvr_field;`
331
331
let statement = Statement {
332
- source_info : source_info ,
332
+ source_info,
333
333
kind : StatementKind :: Assign (
334
334
ref_loc. clone ( ) ,
335
335
Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , rcvr_field)
336
336
)
337
337
} ;
338
338
339
339
// `let loc = Clone::clone(ref_loc);`
340
- block ( blocks, statement, TerminatorKind :: Call {
340
+ block ( blocks, vec ! [ statement] , TerminatorKind :: Call {
341
341
func,
342
342
args : vec ! [ Operand :: Consume ( ref_loc) ] ,
343
- destination : Some ( ( loc. clone ( ) , BasicBlock :: new ( i + 1 ) ) ) ,
344
- cleanup : None ,
345
- } ) ;
343
+ destination : Some ( ( loc. clone ( ) , next ) ) ,
344
+ cleanup : Some ( cleanup ) ,
345
+ } , false ) ;
346
346
347
347
loc
348
348
} ;
349
349
350
350
let is_copy = !self_ty. moves_by_default ( tcx, tcx. param_env ( def_id) , span) ;
351
-
352
351
match self_ty. sty {
353
352
_ if is_copy => {
354
353
// `return *self;`
355
- let statement = Statement {
356
- source_info : source_info ,
354
+ let ret_statement = Statement {
355
+ source_info,
357
356
kind : StatementKind :: Assign (
358
357
Lvalue :: Local ( RETURN_POINTER ) ,
359
358
Rvalue :: Use ( Operand :: Consume ( rcvr) )
360
359
)
361
360
} ;
362
- block ( & mut blocks, statement , TerminatorKind :: Return ) ;
361
+ block ( & mut blocks, vec ! [ ret_statement ] , TerminatorKind :: Return , false ) ;
363
362
}
364
363
ty:: TyArray ( ty, len) => {
365
- let mut returns = Vec :: new ( ) ;
366
- for i in 0 ..len {
367
- let index = ConstUsize :: new ( i as u64 , tcx. sess . target . uint_type ) . unwrap ( ) ;
368
- let rcvr_field = rcvr. clone ( ) . index (
369
- Operand :: Constant ( box Constant {
370
- span,
371
- ty : tcx. types . usize ,
372
- literal : Literal :: Value {
373
- value : ConstVal :: Integral ( ConstInt :: Usize ( index) )
374
- }
375
- } )
364
+ let make_loop = |beg, end, loop_body, loop_end,
365
+ blocks : & mut _ , local_decls : & mut _ , is_cleanup|
366
+ {
367
+ let cond = make_lvalue ( Mutability :: Mut , tcx. types . bool , local_decls) ;
368
+ let compute_cond = Statement {
369
+ source_info,
370
+ kind : StatementKind :: Assign (
371
+ cond. clone ( ) ,
372
+ Rvalue :: BinaryOp ( BinOp :: Ne , Operand :: Consume ( end) , Operand :: Consume ( beg) )
373
+ )
374
+ } ;
375
+
376
+ // `if end != beg { goto loop_body; } else { goto loop_end; }`
377
+ block (
378
+ blocks,
379
+ vec ! [ compute_cond] ,
380
+ TerminatorKind :: if_ ( tcx, Operand :: Consume ( cond) , loop_body, loop_end) ,
381
+ is_cleanup
376
382
) ;
383
+ } ;
377
384
378
- // `returns[i] = Clone::clone(&rcvr[i]);`
379
- returns. push ( call_clone ( i, ty, rcvr_field, & mut blocks, & mut local_decls) ) ;
380
- }
385
+ let make_usize = |value| {
386
+ let value = ConstUsize :: new ( value as u64 , tcx. sess . target . uint_type ) . unwrap ( ) ;
387
+ box Constant {
388
+ span,
389
+ ty : tcx. types . usize ,
390
+ literal : Literal :: Value {
391
+ value : ConstVal :: Integral ( ConstInt :: Usize ( value) )
392
+ }
393
+ }
394
+ } ;
381
395
382
- // `return [returns[0], returns[1], ..., returns[len - 1]];`
383
- let statement = Statement {
396
+ let beg = make_lvalue ( Mutability :: Mut , tcx. types . usize , & mut local_decls) ;
397
+ let end = make_lvalue ( Mutability :: Not , tcx. types . usize , & mut local_decls) ;
398
+ let ret = make_lvalue ( Mutability :: Mut , tcx. mk_array ( ty, len) , & mut local_decls) ;
399
+
400
+ // BB #0
401
+ // `let mut beg = 0;`
402
+ // `let end = len;`
403
+ // `goto #1;`
404
+ let inits = vec ! [
405
+ Statement {
406
+ source_info,
407
+ kind: StatementKind :: Assign (
408
+ beg. clone( ) ,
409
+ Rvalue :: Use ( Operand :: Constant ( make_usize( 0 ) ) )
410
+ )
411
+ } ,
412
+ Statement {
413
+ source_info,
414
+ kind: StatementKind :: Assign (
415
+ end. clone( ) ,
416
+ Rvalue :: Use ( Operand :: Constant ( make_usize( len) ) )
417
+ )
418
+ }
419
+ ] ;
420
+ block ( & mut blocks, inits, TerminatorKind :: Goto { target : BasicBlock :: new ( 1 ) } , false ) ;
421
+
422
+ // BB #1: loop {
423
+ // BB #2;
424
+ // BB #3;
425
+ // }
426
+ // BB #4;
427
+ make_loop (
428
+ beg. clone ( ) ,
429
+ end,
430
+ BasicBlock :: new ( 2 ) ,
431
+ BasicBlock :: new ( 4 ) ,
432
+ & mut blocks,
433
+ & mut local_decls,
434
+ false
435
+ ) ;
436
+
437
+ // BB #2
438
+ // `let cloned = Clone::clone(rcvr[beg])`;
439
+ // Goto #3 if ok, #5 if unwinding happens.
440
+ let rcvr_field = rcvr. clone ( ) . index ( Operand :: Consume ( beg. clone ( ) ) ) ;
441
+ let cloned = call_clone (
442
+ ty,
443
+ rcvr_field,
444
+ BasicBlock :: new ( 3 ) ,
445
+ BasicBlock :: new ( 5 ) ,
446
+ & mut blocks,
447
+ & mut local_decls
448
+ ) ;
449
+
450
+ // BB #3
451
+ // `ret[beg] = cloned;`
452
+ // `beg = beg + 1;`
453
+ // `goto #1`;
454
+ let ret_field = ret. clone ( ) . index ( Operand :: Consume ( beg. clone ( ) ) ) ;
455
+ let statements = vec ! [
456
+ Statement {
457
+ source_info,
458
+ kind: StatementKind :: Assign (
459
+ ret_field,
460
+ Rvalue :: Use ( Operand :: Consume ( cloned) )
461
+ )
462
+ } ,
463
+ Statement {
464
+ source_info,
465
+ kind: StatementKind :: Assign (
466
+ beg. clone( ) ,
467
+ Rvalue :: BinaryOp (
468
+ BinOp :: Add ,
469
+ Operand :: Consume ( beg. clone( ) ) ,
470
+ Operand :: Constant ( make_usize( 1 ) )
471
+ )
472
+ )
473
+ }
474
+ ] ;
475
+ block (
476
+ & mut blocks,
477
+ statements,
478
+ TerminatorKind :: Goto { target : BasicBlock :: new ( 1 ) } ,
479
+ false
480
+ ) ;
481
+
482
+ // BB #4
483
+ // `return ret;`
484
+ let ret_statement = Statement {
384
485
source_info : source_info,
385
486
kind : StatementKind :: Assign (
386
487
Lvalue :: Local ( RETURN_POINTER ) ,
387
- Rvalue :: Aggregate (
388
- box AggregateKind :: Array ( ty) ,
389
- returns. into_iter ( ) . map ( Operand :: Consume ) . collect ( )
488
+ Rvalue :: Use ( Operand :: Consume ( ret. clone ( ) ) ) ,
489
+ )
490
+ } ;
491
+ block ( & mut blocks, vec ! [ ret_statement] , TerminatorKind :: Return , false ) ;
492
+
493
+ // BB #5 (cleanup)
494
+ // `let end = beg;`
495
+ // `let mut beg = 0;`
496
+ // goto #6;
497
+ let end = beg;
498
+ let beg = make_lvalue ( Mutability :: Mut , tcx. types . usize , & mut local_decls) ;
499
+ let init = Statement {
500
+ source_info,
501
+ kind : StatementKind :: Assign (
502
+ beg. clone ( ) ,
503
+ Rvalue :: Use ( Operand :: Constant ( make_usize ( 0 ) ) )
504
+ )
505
+ } ;
506
+ block (
507
+ & mut blocks,
508
+ vec ! [ init] ,
509
+ TerminatorKind :: Goto { target : BasicBlock :: new ( 6 ) } ,
510
+ true
511
+ ) ;
512
+
513
+ // BB #6 (cleanup): loop {
514
+ // BB #7;
515
+ // BB #8;
516
+ // }
517
+ // BB #9;
518
+ make_loop (
519
+ beg. clone ( ) ,
520
+ end,
521
+ BasicBlock :: new ( 7 ) ,
522
+ BasicBlock :: new ( 9 ) ,
523
+ & mut blocks,
524
+ & mut local_decls,
525
+ true
526
+ ) ;
527
+
528
+ // BB #7 (cleanup)
529
+ // `drop(ret[beg])`;
530
+ block ( & mut blocks, vec ! [ ] , TerminatorKind :: Drop {
531
+ location : ret. index ( Operand :: Consume ( beg. clone ( ) ) ) ,
532
+ target : BasicBlock :: new ( 8 ) ,
533
+ unwind : None ,
534
+ } , true ) ;
535
+
536
+ // BB #8 (cleanup)
537
+ // `beg = beg + 1;`
538
+ // `goto #6;`
539
+ let statement = Statement {
540
+ source_info,
541
+ kind : StatementKind :: Assign (
542
+ beg. clone ( ) ,
543
+ Rvalue :: BinaryOp (
544
+ BinOp :: Add ,
545
+ Operand :: Consume ( beg. clone ( ) ) ,
546
+ Operand :: Constant ( make_usize ( 1 ) )
390
547
)
391
548
)
392
549
} ;
393
- block ( & mut blocks, statement, TerminatorKind :: Return ) ;
550
+ block (
551
+ & mut blocks,
552
+ vec ! [ statement] ,
553
+ TerminatorKind :: Goto { target : BasicBlock :: new ( 6 ) } ,
554
+ true
555
+ ) ;
556
+
557
+ // BB #9 (resume)
558
+ block ( & mut blocks, vec ! [ ] , TerminatorKind :: Resume , true ) ;
394
559
}
395
560
ty:: TyTuple ( tys, _) => {
396
561
let mut returns = Vec :: new ( ) ;
397
562
for ( i, ity) in tys. iter ( ) . enumerate ( ) {
398
563
let rcvr_field = rcvr. clone ( ) . field ( Field :: new ( i) , * ity) ;
399
564
565
+ // BB #(2i)
400
566
// `returns[i] = Clone::clone(&rcvr.i);`
401
- returns. push ( call_clone ( i, * ity, rcvr_field, & mut blocks, & mut local_decls) ) ;
567
+ // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
568
+ returns. push ( call_clone (
569
+ * ity,
570
+ rcvr_field,
571
+ BasicBlock :: new ( 2 * i + 2 ) ,
572
+ BasicBlock :: new ( 2 * i + 1 ) ,
573
+ & mut blocks,
574
+ & mut local_decls
575
+ ) ) ;
576
+
577
+ // BB #(2i + 1) (cleanup)
578
+ if i == 0 {
579
+ // Nothing to drop, just resume.
580
+ block ( & mut blocks, vec ! [ ] , TerminatorKind :: Resume , true ) ;
581
+ } else {
582
+ // Drop previous field and goto previous cleanup block.
583
+ block ( & mut blocks, vec ! [ ] , TerminatorKind :: Drop {
584
+ location : returns[ i - 1 ] . clone ( ) ,
585
+ target : BasicBlock :: new ( 2 * i - 1 ) ,
586
+ unwind : None ,
587
+ } , true ) ;
588
+ }
402
589
}
403
590
404
591
// `return (returns[0], returns[1], ..., returns[tys.len() - 1]);`
405
- let statement = Statement {
406
- source_info : source_info ,
592
+ let ret_statement = Statement {
593
+ source_info,
407
594
kind : StatementKind :: Assign (
408
595
Lvalue :: Local ( RETURN_POINTER ) ,
409
596
Rvalue :: Aggregate (
@@ -412,10 +599,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
412
599
)
413
600
)
414
601
} ;
415
- block ( & mut blocks, statement , TerminatorKind :: Return ) ;
602
+ block ( & mut blocks, vec ! [ ret_statement ] , TerminatorKind :: Return , false ) ;
416
603
}
417
604
_ => {
418
- bug ! ( "builtin shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty) ;
605
+ bug ! ( "clone shim for `{:?}` which is not `Copy` and is not an aggregate" , self_ty) ;
419
606
}
420
607
} ;
421
608
0 commit comments