@@ -286,18 +286,26 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
286286 let mut local_decls = local_decls_for_sig ( & sig, span) ;
287287 let source_info = SourceInfo { span, scope : ARGUMENT_VISIBILITY_SCOPE } ;
288288
289+ let rcvr = Lvalue :: Local ( Local :: new ( 1 +0 ) ) . deref ( ) ;
290+
289291 let mut blocks = IndexVec :: new ( ) ;
290- let block = |blocks : & mut IndexVec < _ , _ > , statement , kind| {
292+ let block = |blocks : & mut IndexVec < _ , _ > , statements , kind, is_cleanup | {
291293 blocks. push ( BasicBlockData {
292- statements : vec ! [ statement ] ,
294+ statements,
293295 terminator : Some ( Terminator { source_info, kind } ) ,
294- is_cleanup : false
296+ is_cleanup,
295297 } )
296298 } ;
297299
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+ } ;
299305
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+ {
301309 // `func == Clone::clone(&ty) -> ty`
302310 let substs = Substs :: for_item ( tcx, def_id, |_, _| tcx. types . re_erased , |_, _| ty) ;
303311 let func = Operand :: Constant ( box Constant {
@@ -308,102 +316,281 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
308316 } ,
309317 } ) ;
310318
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 {
325322 ty,
326- span
327- ) )
323+ mutbl : hir:: Mutability :: MutImmutable ,
324+ } ) ,
325+ local_decls
328326 ) ;
329327
328+ let loc = make_lvalue ( Mutability :: Not , ty, local_decls) ;
329+
330330 // `let ref_loc: &ty = &rcvr_field;`
331331 let statement = Statement {
332- source_info : source_info ,
332+ source_info,
333333 kind : StatementKind :: Assign (
334334 ref_loc. clone ( ) ,
335335 Rvalue :: Ref ( tcx. types . re_erased , BorrowKind :: Shared , rcvr_field)
336336 )
337337 } ;
338338
339339 // `let loc = Clone::clone(ref_loc);`
340- block ( blocks, statement, TerminatorKind :: Call {
340+ block ( blocks, vec ! [ statement] , TerminatorKind :: Call {
341341 func,
342342 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 ) ;
346346
347347 loc
348348 } ;
349349
350350 let is_copy = !self_ty. moves_by_default ( tcx, tcx. param_env ( def_id) , span) ;
351-
352351 match self_ty. sty {
353352 _ if is_copy => {
354353 // `return *self;`
355- let statement = Statement {
356- source_info : source_info ,
354+ let ret_statement = Statement {
355+ source_info,
357356 kind : StatementKind :: Assign (
358357 Lvalue :: Local ( RETURN_POINTER ) ,
359358 Rvalue :: Use ( Operand :: Consume ( rcvr) )
360359 )
361360 } ;
362- block ( & mut blocks, statement , TerminatorKind :: Return ) ;
361+ block ( & mut blocks, vec ! [ ret_statement ] , TerminatorKind :: Return , false ) ;
363362 }
364363 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
376382 ) ;
383+ } ;
377384
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+ } ;
381395
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 {
384485 source_info : source_info,
385486 kind : StatementKind :: Assign (
386487 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 ) )
390547 )
391548 )
392549 } ;
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 ) ;
394559 }
395560 ty:: TyTuple ( tys, _) => {
396561 let mut returns = Vec :: new ( ) ;
397562 for ( i, ity) in tys. iter ( ) . enumerate ( ) {
398563 let rcvr_field = rcvr. clone ( ) . field ( Field :: new ( i) , * ity) ;
399564
565+ // BB #(2i)
400566 // `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+ }
402589 }
403590
404591 // `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,
407594 kind : StatementKind :: Assign (
408595 Lvalue :: Local ( RETURN_POINTER ) ,
409596 Rvalue :: Aggregate (
@@ -412,10 +599,10 @@ fn build_clone_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
412599 )
413600 )
414601 } ;
415- block ( & mut blocks, statement , TerminatorKind :: Return ) ;
602+ block ( & mut blocks, vec ! [ ret_statement ] , TerminatorKind :: Return , false ) ;
416603 }
417604 _ => {
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) ;
419606 }
420607 } ;
421608
0 commit comments