@@ -550,36 +550,75 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
550
550
Operand :: Consume ( cast_tmp)
551
551
}
552
552
553
- fn make_call_args ( & self , args : Vec < Operand < ' tcx > > ,
554
- callsite : & CallSite < ' tcx > , caller_mir : & mut Mir < ' tcx > ) -> Vec < Operand < ' tcx > > {
553
+ fn make_call_args (
554
+ & self ,
555
+ args : Vec < Operand < ' tcx > > ,
556
+ callsite : & CallSite < ' tcx > ,
557
+ caller_mir : & mut Mir < ' tcx > ,
558
+ ) -> Vec < Operand < ' tcx > > {
555
559
let tcx = self . tcx ;
560
+
561
+ // A closure is passed its self-type and a tuple like `(arg1, arg2, ...)`,
562
+ // hence mappings to tuple fields are needed.
563
+ if tcx. is_closure ( callsite. callee ) {
564
+ let mut args = args. into_iter ( ) ;
565
+ let self_ = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_mir) ;
566
+ let tuple = self . create_temp_if_necessary ( args. next ( ) . unwrap ( ) , callsite, caller_mir) ;
567
+ assert ! ( args. next( ) . is_none( ) ) ;
568
+
569
+ let tuple_tys = if let ty:: TyTuple ( s, _) = tuple. ty ( caller_mir, tcx) . to_ty ( tcx) . sty {
570
+ s
571
+ } else {
572
+ bug ! ( "Closure arguments are not passed as a tuple" ) ;
573
+ } ;
574
+
575
+ let mut res = Vec :: with_capacity ( 1 + tuple_tys. len ( ) ) ;
576
+ res. push ( Operand :: Consume ( self_) ) ;
577
+ res. extend ( tuple_tys. iter ( ) . enumerate ( ) . map ( |( i, ty) | {
578
+ Operand :: Consume ( tuple. clone ( ) . field ( Field :: new ( i) , ty) )
579
+ } ) ) ;
580
+ res
581
+ } else {
582
+ args. into_iter ( )
583
+ . map ( |a| Operand :: Consume ( self . create_temp_if_necessary ( a, callsite, caller_mir) ) )
584
+ . collect ( )
585
+ }
586
+ }
587
+
588
+ /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh
589
+ /// temporary `T` and an instruction `T = arg`, and returns `T`.
590
+ fn create_temp_if_necessary (
591
+ & self ,
592
+ arg : Operand < ' tcx > ,
593
+ callsite : & CallSite < ' tcx > ,
594
+ caller_mir : & mut Mir < ' tcx > ,
595
+ ) -> Lvalue < ' tcx > {
556
596
// FIXME: Analysis of the usage of the arguments to avoid
557
597
// unnecessary temporaries.
558
- args. into_iter ( ) . map ( |a| {
559
- if let Operand :: Consume ( Lvalue :: Local ( local) ) = a {
560
- if caller_mir. local_kind ( local) == LocalKind :: Temp {
561
- // Reuse the operand if it's a temporary already
562
- return a;
563
- }
598
+
599
+ if let Operand :: Consume ( Lvalue :: Local ( local) ) = arg {
600
+ if caller_mir. local_kind ( local) == LocalKind :: Temp {
601
+ // Reuse the operand if it's a temporary already
602
+ return Lvalue :: Local ( local) ;
564
603
}
604
+ }
565
605
566
- debug ! ( "Creating temp for argument" ) ;
567
- // Otherwise, create a temporary for the arg
568
- let arg = Rvalue :: Use ( a ) ;
606
+ debug ! ( "Creating temp for argument {:?}" , arg ) ;
607
+ // Otherwise, create a temporary for the arg
608
+ let arg = Rvalue :: Use ( arg ) ;
569
609
570
- let ty = arg. ty ( caller_mir, tcx) ;
610
+ let ty = arg. ty ( caller_mir, self . tcx ) ;
571
611
572
- let arg_tmp = LocalDecl :: new_temp ( ty, callsite. location . span ) ;
573
- let arg_tmp = caller_mir. local_decls . push ( arg_tmp) ;
574
- let arg_tmp = Lvalue :: Local ( arg_tmp) ;
612
+ let arg_tmp = LocalDecl :: new_temp ( ty, callsite. location . span ) ;
613
+ let arg_tmp = caller_mir. local_decls . push ( arg_tmp) ;
614
+ let arg_tmp = Lvalue :: Local ( arg_tmp) ;
575
615
576
- let stmt = Statement {
577
- source_info : callsite. location ,
578
- kind : StatementKind :: Assign ( arg_tmp. clone ( ) , arg)
579
- } ;
580
- caller_mir[ callsite. bb ] . statements . push ( stmt) ;
581
- Operand :: Consume ( arg_tmp)
582
- } ) . collect ( )
616
+ let stmt = Statement {
617
+ source_info : callsite. location ,
618
+ kind : StatementKind :: Assign ( arg_tmp. clone ( ) , arg) ,
619
+ } ;
620
+ caller_mir[ callsite. bb ] . statements . push ( stmt) ;
621
+ arg_tmp
583
622
}
584
623
}
585
624
0 commit comments