@@ -20,6 +20,7 @@ use rustc::mir::transform::{MirPass, MirSource};
20
20
use rustc:: mir:: visit:: * ;
21
21
use rustc:: ty:: { self , Instance , Ty , TyCtxt , TypeFoldable } ;
22
22
use rustc:: ty:: subst:: { Subst , Substs } ;
23
+ use rustc:: hir:: map:: definitions:: DefPathData ;
23
24
24
25
use std:: collections:: VecDeque ;
25
26
use super :: simplify:: { remove_dead_blocks, CfgSimplifier } ;
@@ -550,22 +551,31 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
550
551
Operand :: Consume ( cast_tmp)
551
552
}
552
553
553
- fn make_call_args ( & self , args : Vec < Operand < ' tcx > > ,
554
- callsite : & CallSite < ' tcx > , caller_mir : & mut Mir < ' tcx > ) -> Vec < Operand < ' tcx > > {
555
- let tcx = self . tcx ;
554
+ fn make_call_args (
555
+ & self ,
556
+ args : Vec < Operand < ' tcx > > ,
557
+ callsite : & CallSite < ' tcx > ,
558
+ caller_mir : & mut Mir < ' tcx > ,
559
+ ) -> Vec < Operand < ' tcx > > {
556
560
// FIXME: Analysis of the usage of the arguments to avoid
557
561
// unnecessary temporaries.
558
- args. into_iter ( ) . map ( |a| {
559
- if let Operand :: Consume ( Lvalue :: Local ( local) ) = a {
562
+
563
+ fn create_temp_if_necessary < ' a , ' tcx : ' a > (
564
+ arg : Operand < ' tcx > ,
565
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
566
+ callsite : & CallSite < ' tcx > ,
567
+ caller_mir : & mut Mir < ' tcx > ,
568
+ ) -> Operand < ' tcx > {
569
+ if let Operand :: Consume ( Lvalue :: Local ( local) ) = arg {
560
570
if caller_mir. local_kind ( local) == LocalKind :: Temp {
561
571
// Reuse the operand if it's a temporary already
562
- return a ;
572
+ return arg ;
563
573
}
564
574
}
565
575
566
- debug ! ( "Creating temp for argument" ) ;
576
+ debug ! ( "Creating temp for argument {:?}" , arg ) ;
567
577
// Otherwise, create a temporary for the arg
568
- let arg = Rvalue :: Use ( a ) ;
578
+ let arg = Rvalue :: Use ( arg ) ;
569
579
570
580
let ty = arg. ty ( caller_mir, tcx) ;
571
581
@@ -575,11 +585,47 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
575
585
576
586
let stmt = Statement {
577
587
source_info : callsite. location ,
578
- kind : StatementKind :: Assign ( arg_tmp. clone ( ) , arg)
588
+ kind : StatementKind :: Assign ( arg_tmp. clone ( ) , arg) ,
579
589
} ;
580
590
caller_mir[ callsite. bb ] . statements . push ( stmt) ;
581
591
Operand :: Consume ( arg_tmp)
582
- } ) . collect ( )
592
+ }
593
+
594
+ let tcx = self . tcx ;
595
+
596
+ // A closure is passed its self-type and a tuple like `(arg1, arg2, ...)`,
597
+ // hence mappings to tuple fields are needed.
598
+ if tcx. def_key ( callsite. callee ) . disambiguated_data . data == DefPathData :: ClosureExpr {
599
+ let mut args = args. into_iter ( ) ;
600
+
601
+ let self_ = create_temp_if_necessary ( args. next ( ) . unwrap ( ) , tcx, callsite, caller_mir) ;
602
+
603
+ let tuple = if let Operand :: Consume ( lvalue) =
604
+ create_temp_if_necessary ( args. next ( ) . unwrap ( ) , tcx, callsite, caller_mir)
605
+ {
606
+ lvalue
607
+ } else {
608
+ unreachable ! ( )
609
+ } ;
610
+ assert ! ( args. next( ) . is_none( ) ) ;
611
+
612
+ let tuple_tys = if let ty:: TyTuple ( s, _) = tuple. ty ( caller_mir, tcx) . to_ty ( tcx) . sty {
613
+ s
614
+ } else {
615
+ bug ! ( "Closure arguments are not passed as a tuple" ) ;
616
+ } ;
617
+
618
+ let mut res = Vec :: with_capacity ( 1 + tuple_tys. len ( ) ) ;
619
+ res. push ( self_) ;
620
+ res. extend ( tuple_tys. iter ( ) . enumerate ( ) . map ( |( i, ty) | {
621
+ Operand :: Consume ( tuple. clone ( ) . field ( Field :: new ( i) , ty) )
622
+ } ) ) ;
623
+ res
624
+ } else {
625
+ args. into_iter ( )
626
+ . map ( |a| create_temp_if_necessary ( a, tcx, callsite, caller_mir) )
627
+ . collect ( )
628
+ }
583
629
}
584
630
}
585
631
0 commit comments