11use  std:: borrow:: Cow ; 
22
3+ use  either:: Either ; 
4+ 
35use  rustc_ast:: ast:: InlineAsmOptions ; 
46use  rustc_middle:: { 
57    mir, 
@@ -30,28 +32,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
3032     Copy ( OpTy < ' tcx ,  Prov > ) , 
3133    /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and 
3234     /// make the place inaccessible for the duration of the function call. 
33-      InPlace ( PlaceTy < ' tcx ,  Prov > ) , 
35+      InPlace ( MPlaceTy < ' tcx ,  Prov > ) , 
3436} 
3537
3638impl < ' tcx ,  Prov :  Provenance >  FnArg < ' tcx ,  Prov >  { 
3739    pub  fn  layout ( & self )  -> & TyAndLayout < ' tcx >  { 
3840        match  self  { 
3941            FnArg :: Copy ( op)  => & op. layout , 
40-             FnArg :: InPlace ( place )  => & place . layout , 
42+             FnArg :: InPlace ( mplace )  => & mplace . layout , 
4143        } 
4244    } 
4345} 
4446
4547impl < ' mir ,  ' tcx :  ' mir ,  M :  Machine < ' mir ,  ' tcx > >  InterpCx < ' mir ,  ' tcx ,  M >  { 
4648    /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the 
4749     /// original memory occurs. 
48-      pub  fn  copy_fn_arg ( 
49-         & self , 
50-         arg :  & FnArg < ' tcx ,  M :: Provenance > , 
51-     )  -> InterpResult < ' tcx ,  OpTy < ' tcx ,  M :: Provenance > >  { 
50+      pub  fn  copy_fn_arg ( & self ,  arg :  & FnArg < ' tcx ,  M :: Provenance > )  -> OpTy < ' tcx ,  M :: Provenance >  { 
5251        match  arg { 
53-             FnArg :: Copy ( op)  => Ok ( op. clone ( ) ) , 
54-             FnArg :: InPlace ( place )  => self . place_to_op ( place ) , 
52+             FnArg :: Copy ( op)  => op. clone ( ) , 
53+             FnArg :: InPlace ( mplace )  => mplace . clone ( ) . into ( ) , 
5554        } 
5655    } 
5756
@@ -60,7 +59,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6059     pub  fn  copy_fn_args ( 
6160        & self , 
6261        args :  & [ FnArg < ' tcx ,  M :: Provenance > ] , 
63-     )  -> InterpResult < ' tcx ,   Vec < OpTy < ' tcx ,  M :: Provenance > > >  { 
62+     )  -> Vec < OpTy < ' tcx ,  M :: Provenance > >  { 
6463        args. iter ( ) . map ( |fn_arg| self . copy_fn_arg ( fn_arg) ) . collect ( ) 
6564    } 
6665
@@ -71,7 +70,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7170    )  -> InterpResult < ' tcx ,  FnArg < ' tcx ,  M :: Provenance > >  { 
7271        Ok ( match  arg { 
7372            FnArg :: Copy ( op)  => FnArg :: Copy ( self . project_field ( op,  field) ?) , 
74-             FnArg :: InPlace ( place )  => FnArg :: InPlace ( self . project_field ( place ,  field) ?) , 
73+             FnArg :: InPlace ( mplace )  => FnArg :: InPlace ( self . project_field ( mplace ,  field) ?) , 
7574        } ) 
7675    } 
7776
@@ -246,10 +245,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
246245    )  -> InterpResult < ' tcx ,  Vec < FnArg < ' tcx ,  M :: Provenance > > >  { 
247246        ops. iter ( ) 
248247            . map ( |op| { 
249-                 Ok ( match  & op. node  { 
250-                     mir:: Operand :: Move ( place)  => FnArg :: InPlace ( self . eval_place ( * place) ?) , 
251-                     _ => FnArg :: Copy ( self . eval_operand ( & op. node ,  None ) ?) , 
252-                 } ) 
248+                 let  arg = match  & op. node  { 
249+                     mir:: Operand :: Copy ( _)  | mir:: Operand :: Constant ( _)  => { 
250+                         // Make a regular copy. 
251+                         let  op = self . eval_operand ( & op. node ,  None ) ?; 
252+                         FnArg :: Copy ( op) 
253+                     } 
254+                     mir:: Operand :: Move ( place)  => { 
255+                         // If this place lives in memory, preserve its location. 
256+                         // We call `place_to_op` which will be an `MPlaceTy` whenever there exists 
257+                         // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local` 
258+                         // which can return a local even if that has an mplace.) 
259+                         let  place = self . eval_place ( * place) ?; 
260+                         let  op = self . place_to_op ( & place) ?; 
261+ 
262+                         match  op. as_mplace_or_imm ( )  { 
263+                             Either :: Left ( mplace)  => FnArg :: InPlace ( mplace) , 
264+                             Either :: Right ( _imm)  => { 
265+                                 // This argument doesn't live in memory, so there's no place 
266+                                 // to make inaccessible during the call. 
267+                                 // We rely on there not being any stray `PlaceTy` that would let the 
268+                                 // caller directly access this local! 
269+                                 // This is also crucial for tail calls, where we want the `FnArg` to 
270+                                 // stay valid when the old stack frame gets popped. 
271+                                 FnArg :: Copy ( op) 
272+                             } 
273+                         } 
274+                     } 
275+                 } ; 
276+ 
277+                 Ok ( arg) 
253278            } ) 
254279            . collect ( ) 
255280    } 
@@ -459,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
459484        // We work with a copy of the argument for now; if this is in-place argument passing, we 
460485        // will later protect the source it comes from. This means the callee cannot observe if we 
461486        // did in-place of by-copy argument passing, except for pointer equality tests. 
462-         let  caller_arg_copy = self . copy_fn_arg ( caller_arg) ? ; 
487+         let  caller_arg_copy = self . copy_fn_arg ( caller_arg) ; 
463488        if  !already_live { 
464489            let  local = callee_arg. as_local ( ) . unwrap ( ) ; 
465490            let  meta = caller_arg_copy. meta ( ) ; 
@@ -477,8 +502,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
477502        // specifically.) 
478503        self . copy_op_allow_transmute ( & caller_arg_copy,  & callee_arg) ?; 
479504        // If this was an in-place pass, protect the place it comes from for the duration of the call. 
480-         if  let  FnArg :: InPlace ( place )  = caller_arg { 
481-             M :: protect_in_place_function_argument ( self ,  place ) ?; 
505+         if  let  FnArg :: InPlace ( mplace )  = caller_arg { 
506+             M :: protect_in_place_function_argument ( self ,  mplace ) ?; 
482507        } 
483508        Ok ( ( ) ) 
484509    } 
@@ -525,7 +550,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
525550                M :: call_intrinsic ( 
526551                    self , 
527552                    instance, 
528-                     & self . copy_fn_args ( args) ? , 
553+                     & self . copy_fn_args ( args) , 
529554                    destination, 
530555                    target, 
531556                    unwind, 
@@ -602,8 +627,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602627                            . map( |arg| ( 
603628                                arg. layout( ) . ty, 
604629                                match  arg { 
605-                                     FnArg :: Copy ( op)  => format!( "copy({:?})" ,   * op ) , 
606-                                     FnArg :: InPlace ( place )  => format!( "in-place({:?})" ,   * place ) , 
630+                                     FnArg :: Copy ( op)  => format!( "copy({op :?})" ) , 
631+                                     FnArg :: InPlace ( mplace )  => format!( "in-place({mplace :?})" ) , 
607632                                } 
608633                            ) ) 
609634                            . collect:: <Vec <_>>( ) 
@@ -725,8 +750,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
725750                            callee_ty:  callee_fn_abi. ret. layout. ty
726751                        } ) ; 
727752                    } 
753+ 
728754                    // Protect return place for in-place return value passing. 
729-                     M :: protect_in_place_function_argument ( self ,  & destination. clone ( ) . into ( ) ) ?; 
755+                     M :: protect_in_place_function_argument ( self ,  & destination) ?; 
730756
731757                    // Don't forget to mark "initially live" locals as live. 
732758                    self . storage_live_for_always_live_locals ( ) ?; 
@@ -749,7 +775,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
749775                // An `InPlace` does nothing here, we keep the original receiver intact. We can't 
750776                // really pass the argument in-place anyway, and we are constructing a new 
751777                // `Immediate` receiver. 
752-                 let  mut  receiver = self . copy_fn_arg ( & args[ 0 ] ) ? ; 
778+                 let  mut  receiver = self . copy_fn_arg ( & args[ 0 ] ) ; 
753779                let  receiver_place = loop  { 
754780                    match  receiver. layout . ty . kind ( )  { 
755781                        ty:: Ref ( ..)  | ty:: RawPtr ( ..)  => { 
0 commit comments