1
1
use std:: borrow:: Cow ;
2
2
3
+ use either:: Either ;
3
4
use rustc_ast:: ast:: InlineAsmOptions ;
4
5
use rustc_middle:: {
5
6
mir,
@@ -30,28 +31,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
30
31
Copy ( OpTy < ' tcx , Prov > ) ,
31
32
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
32
33
/// make the place inaccessible for the duration of the function call.
33
- InPlace ( PlaceTy < ' tcx , Prov > ) ,
34
+ InPlace ( MPlaceTy < ' tcx , Prov > ) ,
34
35
}
35
36
36
37
impl < ' tcx , Prov : Provenance > FnArg < ' tcx , Prov > {
37
38
pub fn layout ( & self ) -> & TyAndLayout < ' tcx > {
38
39
match self {
39
40
FnArg :: Copy ( op) => & op. layout ,
40
- FnArg :: InPlace ( place ) => & place . layout ,
41
+ FnArg :: InPlace ( mplace ) => & mplace . layout ,
41
42
}
42
43
}
43
44
}
44
45
45
46
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
46
47
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
47
48
/// 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 > {
52
50
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 ( ) ,
55
53
}
56
54
}
57
55
@@ -60,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
60
58
pub fn copy_fn_args (
61
59
& self ,
62
60
args : & [ FnArg < ' tcx , M :: Provenance > ] ,
63
- ) -> InterpResult < ' tcx , Vec < OpTy < ' tcx , M :: Provenance > > > {
61
+ ) -> Vec < OpTy < ' tcx , M :: Provenance > > {
64
62
args. iter ( ) . map ( |fn_arg| self . copy_fn_arg ( fn_arg) ) . collect ( )
65
63
}
66
64
@@ -71,7 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
71
69
) -> InterpResult < ' tcx , FnArg < ' tcx , M :: Provenance > > {
72
70
Ok ( match arg {
73
71
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) ?) ,
75
73
} )
76
74
}
77
75
@@ -246,10 +244,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
246
244
) -> InterpResult < ' tcx , Vec < FnArg < ' tcx , M :: Provenance > > > {
247
245
ops. iter ( )
248
246
. 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)
253
269
} )
254
270
. collect ( )
255
271
}
@@ -459,7 +475,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
459
475
// We work with a copy of the argument for now; if this is in-place argument passing, we
460
476
// will later protect the source it comes from. This means the callee cannot observe if we
461
477
// 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) ;
463
479
if !already_live {
464
480
let local = callee_arg. as_local ( ) . unwrap ( ) ;
465
481
let meta = caller_arg_copy. meta ( ) ;
@@ -477,8 +493,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
477
493
// specifically.)
478
494
self . copy_op_allow_transmute ( & caller_arg_copy, & callee_arg) ?;
479
495
// 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 ) ?;
482
498
}
483
499
Ok ( ( ) )
484
500
}
@@ -525,7 +541,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
525
541
M :: call_intrinsic (
526
542
self ,
527
543
instance,
528
- & self . copy_fn_args ( args) ? ,
544
+ & self . copy_fn_args ( args) ,
529
545
destination,
530
546
target,
531
547
unwind,
@@ -602,8 +618,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602
618
. map( |arg| (
603
619
arg. layout( ) . ty,
604
620
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 :?})" ) ,
607
623
}
608
624
) )
609
625
. collect:: <Vec <_>>( )
@@ -725,8 +741,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
725
741
callee_ty: callee_fn_abi. ret. layout. ty
726
742
} ) ;
727
743
}
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
+ }
730
749
731
750
// Don't forget to mark "initially live" locals as live.
732
751
self . storage_live_for_always_live_locals ( ) ?;
@@ -749,7 +768,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
749
768
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
750
769
// really pass the argument in-place anyway, and we are constructing a new
751
770
// `Immediate` receiver.
752
- let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ? ;
771
+ let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ;
753
772
let receiver_place = loop {
754
773
match receiver. layout . ty . kind ( ) {
755
774
ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
0 commit comments