11use std:: borrow:: Cow ;
22
3+ use either:: Either ;
34use rustc_ast:: ast:: InlineAsmOptions ;
45use rustc_middle:: {
56 mir,
@@ -30,28 +31,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
3031 Copy ( OpTy < ' tcx , Prov > ) ,
3132 /// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
3233 /// make the place inaccessible for the duration of the function call.
33- InPlace ( PlaceTy < ' tcx , Prov > ) ,
34+ InPlace ( MPlaceTy < ' tcx , Prov > ) ,
3435}
3536
3637impl < ' tcx , Prov : Provenance > FnArg < ' tcx , Prov > {
3738 pub fn layout ( & self ) -> & TyAndLayout < ' tcx > {
3839 match self {
3940 FnArg :: Copy ( op) => & op. layout ,
40- FnArg :: InPlace ( place ) => & place . layout ,
41+ FnArg :: InPlace ( mplace ) => & mplace . layout ,
4142 }
4243 }
4344}
4445
4546impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
4647 /// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
4748 /// original memory occurs.
48- pub fn copy_fn_arg (
49- & self ,
50- arg : & FnArg < ' tcx , M :: Provenance > ,
51- ) -> InterpResult < ' tcx , OpTy < ' tcx , M :: Provenance > > {
49+ pub fn copy_fn_arg ( & self , arg : & FnArg < ' tcx , M :: Provenance > ) -> OpTy < ' tcx , M :: Provenance > {
5250 match arg {
53- FnArg :: Copy ( op) => Ok ( op. clone ( ) ) ,
54- FnArg :: InPlace ( place ) => self . place_to_op ( place ) ,
51+ FnArg :: Copy ( op) => op. clone ( ) ,
52+ FnArg :: InPlace ( mplace ) => mplace . clone ( ) . into ( ) ,
5553 }
5654 }
5755
@@ -60,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
6058 pub fn copy_fn_args (
6159 & self ,
6260 args : & [ FnArg < ' tcx , M :: Provenance > ] ,
63- ) -> InterpResult < ' tcx , Vec < OpTy < ' tcx , M :: Provenance > > > {
61+ ) -> Vec < OpTy < ' tcx , M :: Provenance > > {
6462 args. iter ( ) . map ( |fn_arg| self . copy_fn_arg ( fn_arg) ) . collect ( )
6563 }
6664
@@ -71,7 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
7169 ) -> InterpResult < ' tcx , FnArg < ' tcx , M :: Provenance > > {
7270 Ok ( match arg {
7371 FnArg :: Copy ( op) => FnArg :: Copy ( self . project_field ( op, field) ?) ,
74- FnArg :: InPlace ( place ) => FnArg :: InPlace ( self . project_field ( place , field) ?) ,
72+ FnArg :: InPlace ( mplace ) => FnArg :: InPlace ( self . project_field ( mplace , field) ?) ,
7573 } )
7674 }
7775
@@ -246,10 +244,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
246244 ) -> InterpResult < ' tcx , Vec < FnArg < ' tcx , M :: Provenance > > > {
247245 ops. iter ( )
248246 . 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- } )
247+ let arg = match & op. node {
248+ mir:: Operand :: Copy ( _) | mir:: Operand :: Constant ( _) => {
249+ let op = self . eval_operand ( & op. node , None ) ?;
250+ FnArg :: Copy ( op)
251+ }
252+ mir:: Operand :: Move ( place) => {
253+ let place = self . eval_place ( * place) ?;
254+
255+ match place. as_mplace_or_local ( ) {
256+ Either :: Left ( mplace) => FnArg :: InPlace ( mplace) ,
257+ Either :: Right ( _local) => {
258+ // This argument doesn't live in memory, so there's no place
259+ // to make inaccessible during the call.
260+ // This is also crucial for tail calls, where we want the `FnArg` to
261+ // stay valid when the old stack frame gets popped.
262+ FnArg :: Copy ( self . place_to_op ( & place) ?)
263+ }
264+ }
265+ }
266+ } ;
267+
268+ Ok ( arg)
253269 } )
254270 . collect ( )
255271 }
@@ -459,7 +475,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
459475 // We work with a copy of the argument for now; if this is in-place argument passing, we
460476 // will later protect the source it comes from. This means the callee cannot observe if we
461477 // did in-place of by-copy argument passing, except for pointer equality tests.
462- let caller_arg_copy = self . copy_fn_arg ( caller_arg) ? ;
478+ let caller_arg_copy = self . copy_fn_arg ( caller_arg) ;
463479 if !already_live {
464480 let local = callee_arg. as_local ( ) . unwrap ( ) ;
465481 let meta = caller_arg_copy. meta ( ) ;
@@ -477,8 +493,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
477493 // specifically.)
478494 self . copy_op_allow_transmute ( & caller_arg_copy, & callee_arg) ?;
479495 // 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 ) ?;
496+ if let FnArg :: InPlace ( mplace ) = caller_arg {
497+ M :: protect_in_place_function_argument ( self , mplace ) ?;
482498 }
483499 Ok ( ( ) )
484500 }
@@ -525,7 +541,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
525541 M :: call_intrinsic (
526542 self ,
527543 instance,
528- & self . copy_fn_args ( args) ? ,
544+ & self . copy_fn_args ( args) ,
529545 destination,
530546 target,
531547 unwind,
@@ -602,8 +618,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602618 . map( |arg| (
603619 arg. layout( ) . ty,
604620 match arg {
605- FnArg :: Copy ( op) => format!( "copy({:?})" , * op ) ,
606- FnArg :: InPlace ( place ) => format!( "in-place({:?})" , * place ) ,
621+ FnArg :: Copy ( op) => format!( "copy({op :?})" ) ,
622+ FnArg :: InPlace ( mplace ) => format!( "in-place({mplace :?})" ) ,
607623 }
608624 ) )
609625 . collect:: <Vec <_>>( )
@@ -725,8 +741,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
725741 callee_ty: callee_fn_abi. ret. layout. ty
726742 } ) ;
727743 }
728- // Protect return place for in-place return value passing.
729- M :: protect_in_place_function_argument ( self , destination) ?;
744+
745+ if let Either :: Left ( destination) = destination. as_mplace_or_local ( ) {
746+ // Protect return place for in-place return value passing.
747+ M :: protect_in_place_function_argument ( self , & destination) ?;
748+ }
730749
731750 // Don't forget to mark "initially live" locals as live.
732751 self . storage_live_for_always_live_locals ( ) ?;
@@ -749,7 +768,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
749768 // An `InPlace` does nothing here, we keep the original receiver intact. We can't
750769 // really pass the argument in-place anyway, and we are constructing a new
751770 // `Immediate` receiver.
752- let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ? ;
771+ let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ;
753772 let receiver_place = loop {
754773 match receiver. layout . ty . kind ( ) {
755774 ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
0 commit comments