1
1
use std:: borrow:: Cow ;
2
2
3
+ use either:: Either ;
4
+
3
5
use rustc_middle:: {
4
6
mir,
5
7
ty:: {
@@ -29,28 +31,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
29
31
Copy ( OpTy < ' tcx , Prov > ) ,
30
32
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
31
33
/// make the place inaccessible for the duration of the function call.
32
- InPlace ( PlaceTy < ' tcx , Prov > ) ,
34
+ InPlace ( MPlaceTy < ' tcx , Prov > ) ,
33
35
}
34
36
35
37
impl < ' tcx , Prov : Provenance > FnArg < ' tcx , Prov > {
36
38
pub fn layout ( & self ) -> & TyAndLayout < ' tcx > {
37
39
match self {
38
40
FnArg :: Copy ( op) => & op. layout ,
39
- FnArg :: InPlace ( place ) => & place . layout ,
41
+ FnArg :: InPlace ( mplace ) => & mplace . layout ,
40
42
}
41
43
}
42
44
}
43
45
44
46
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
45
47
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
46
48
/// original memory occurs.
47
- pub fn copy_fn_arg (
48
- & self ,
49
- arg : & FnArg < ' tcx , M :: Provenance > ,
50
- ) -> InterpResult < ' tcx , OpTy < ' tcx , M :: Provenance > > {
49
+ pub fn copy_fn_arg ( & self , arg : & FnArg < ' tcx , M :: Provenance > ) -> OpTy < ' tcx , M :: Provenance > {
51
50
match arg {
52
- FnArg :: Copy ( op) => Ok ( op. clone ( ) ) ,
53
- FnArg :: InPlace ( place ) => self . place_to_op ( place ) ,
51
+ FnArg :: Copy ( op) => op. clone ( ) ,
52
+ FnArg :: InPlace ( mplace ) => mplace . clone ( ) . into ( ) ,
54
53
}
55
54
}
56
55
@@ -59,7 +58,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
59
58
pub fn copy_fn_args (
60
59
& self ,
61
60
args : & [ FnArg < ' tcx , M :: Provenance > ] ,
62
- ) -> InterpResult < ' tcx , Vec < OpTy < ' tcx , M :: Provenance > > > {
61
+ ) -> Vec < OpTy < ' tcx , M :: Provenance > > {
63
62
args. iter ( ) . map ( |fn_arg| self . copy_fn_arg ( fn_arg) ) . collect ( )
64
63
}
65
64
@@ -70,7 +69,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
70
69
) -> InterpResult < ' tcx , FnArg < ' tcx , M :: Provenance > > {
71
70
Ok ( match arg {
72
71
FnArg :: Copy ( op) => FnArg :: Copy ( self . project_field ( op, field) ?) ,
73
- FnArg :: InPlace ( place ) => FnArg :: InPlace ( self . project_field ( place , field) ?) ,
72
+ FnArg :: InPlace ( mplace ) => FnArg :: InPlace ( self . project_field ( mplace , field) ?) ,
74
73
} )
75
74
}
76
75
@@ -238,10 +237,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
238
237
) -> InterpResult < ' tcx , Vec < FnArg < ' tcx , M :: Provenance > > > {
239
238
ops. iter ( )
240
239
. map ( |op| {
241
- Ok ( match & op. node {
242
- mir:: Operand :: Move ( place) => FnArg :: InPlace ( self . eval_place ( * place) ?) ,
243
- _ => FnArg :: Copy ( self . eval_operand ( & op. node , None ) ?) ,
244
- } )
240
+ let arg = match & op. node {
241
+ mir:: Operand :: Copy ( _) | mir:: Operand :: Constant ( _) => {
242
+ // Make a regular copy.
243
+ let op = self . eval_operand ( & op. node , None ) ?;
244
+ FnArg :: Copy ( op)
245
+ }
246
+ mir:: Operand :: Move ( place) => {
247
+ // If this place lives in memory, preserve its location.
248
+ // We call `place_to_op` which will be an `MPlaceTy` whenever there exists
249
+ // an mplace for this place. (This is in contrast to `PlaceTy::as_mplace_or_local`
250
+ // which can return a local even if that has an mplace.)
251
+ let place = self . eval_place ( * place) ?;
252
+ let op = self . place_to_op ( & place) ?;
253
+
254
+ match op. as_mplace_or_imm ( ) {
255
+ Either :: Left ( mplace) => FnArg :: InPlace ( mplace) ,
256
+ Either :: Right ( _imm) => {
257
+ // This argument doesn't live in memory, so there's no place
258
+ // to make inaccessible during the call.
259
+ // We rely on there not being any stray `PlaceTy` that would let the
260
+ // caller directly access this local!
261
+ // This is also crucial for tail calls, where we want the `FnArg` to
262
+ // stay valid when the old stack frame gets popped.
263
+ FnArg :: Copy ( op)
264
+ }
265
+ }
266
+ }
267
+ } ;
268
+
269
+ Ok ( arg)
245
270
} )
246
271
. collect ( )
247
272
}
@@ -451,7 +476,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
451
476
// We work with a copy of the argument for now; if this is in-place argument passing, we
452
477
// will later protect the source it comes from. This means the callee cannot observe if we
453
478
// did in-place of by-copy argument passing, except for pointer equality tests.
454
- let caller_arg_copy = self . copy_fn_arg ( caller_arg) ? ;
479
+ let caller_arg_copy = self . copy_fn_arg ( caller_arg) ;
455
480
if !already_live {
456
481
let local = callee_arg. as_local ( ) . unwrap ( ) ;
457
482
let meta = caller_arg_copy. meta ( ) ;
@@ -469,8 +494,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
469
494
// specifically.)
470
495
self . copy_op_allow_transmute ( & caller_arg_copy, & callee_arg) ?;
471
496
// If this was an in-place pass, protect the place it comes from for the duration of the call.
472
- if let FnArg :: InPlace ( place ) = caller_arg {
473
- M :: protect_in_place_function_argument ( self , place ) ?;
497
+ if let FnArg :: InPlace ( mplace ) = caller_arg {
498
+ M :: protect_in_place_function_argument ( self , mplace ) ?;
474
499
}
475
500
Ok ( ( ) )
476
501
}
@@ -517,7 +542,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
517
542
M :: call_intrinsic (
518
543
self ,
519
544
instance,
520
- & self . copy_fn_args ( args) ? ,
545
+ & self . copy_fn_args ( args) ,
521
546
destination,
522
547
target,
523
548
unwind,
@@ -594,8 +619,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
594
619
. map( |arg| (
595
620
arg. layout( ) . ty,
596
621
match arg {
597
- FnArg :: Copy ( op) => format!( "copy({:?})" , * op ) ,
598
- FnArg :: InPlace ( place ) => format!( "in-place({:?})" , * place ) ,
622
+ FnArg :: Copy ( op) => format!( "copy({op :?})" ) ,
623
+ FnArg :: InPlace ( mplace ) => format!( "in-place({mplace :?})" ) ,
599
624
}
600
625
) )
601
626
. collect:: <Vec <_>>( )
@@ -717,8 +742,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
717
742
callee_ty: callee_fn_abi. ret. layout. ty
718
743
} ) ;
719
744
}
745
+
720
746
// Protect return place for in-place return value passing.
721
- M :: protect_in_place_function_argument ( self , & destination. clone ( ) . into ( ) ) ?;
747
+ M :: protect_in_place_function_argument ( self , & destination) ?;
722
748
723
749
// Don't forget to mark "initially live" locals as live.
724
750
self . storage_live_for_always_live_locals ( ) ?;
@@ -741,7 +767,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
741
767
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
742
768
// really pass the argument in-place anyway, and we are constructing a new
743
769
// `Immediate` receiver.
744
- let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ? ;
770
+ let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ;
745
771
let receiver_place = loop {
746
772
match receiver. layout . ty . kind ( ) {
747
773
ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
0 commit comments