1
1
use std:: borrow:: Cow ;
2
2
3
+ use either:: Either ;
4
+
3
5
use rustc_ast:: ast:: InlineAsmOptions ;
4
6
use rustc_middle:: {
5
7
mir,
@@ -30,28 +32,25 @@ pub enum FnArg<'tcx, Prov: Provenance = CtfeProvenance> {
30
32
Copy ( OpTy < ' tcx , Prov > ) ,
31
33
/// Allow for the argument to be passed in-place: destroy the value originally stored at that place and
32
34
/// make the place inaccessible for the duration of the function call.
33
- InPlace ( PlaceTy < ' tcx , Prov > ) ,
35
+ InPlace ( MPlaceTy < ' tcx , Prov > ) ,
34
36
}
35
37
36
38
impl < ' tcx , Prov : Provenance > FnArg < ' tcx , Prov > {
37
39
pub fn layout ( & self ) -> & TyAndLayout < ' tcx > {
38
40
match self {
39
41
FnArg :: Copy ( op) => & op. layout ,
40
- FnArg :: InPlace ( place ) => & place . layout ,
42
+ FnArg :: InPlace ( mplace ) => & mplace . layout ,
41
43
}
42
44
}
43
45
}
44
46
45
47
impl < ' mir , ' tcx : ' mir , M : Machine < ' mir , ' tcx > > InterpCx < ' mir , ' tcx , M > {
46
48
/// Make a copy of the given fn_arg. Any `InPlace` are degenerated to copies, no protection of the
47
49
/// 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 > {
52
51
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 ( ) ,
55
54
}
56
55
}
57
56
@@ -60,7 +59,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
60
59
pub fn copy_fn_args (
61
60
& self ,
62
61
args : & [ FnArg < ' tcx , M :: Provenance > ] ,
63
- ) -> InterpResult < ' tcx , Vec < OpTy < ' tcx , M :: Provenance > > > {
62
+ ) -> Vec < OpTy < ' tcx , M :: Provenance > > {
64
63
args. iter ( ) . map ( |fn_arg| self . copy_fn_arg ( fn_arg) ) . collect ( )
65
64
}
66
65
@@ -71,7 +70,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
71
70
) -> InterpResult < ' tcx , FnArg < ' tcx , M :: Provenance > > {
72
71
Ok ( match arg {
73
72
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) ?) ,
75
74
} )
76
75
}
77
76
@@ -246,10 +245,36 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
246
245
) -> InterpResult < ' tcx , Vec < FnArg < ' tcx , M :: Provenance > > > {
247
246
ops. iter ( )
248
247
. 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)
253
278
} )
254
279
. collect ( )
255
280
}
@@ -459,7 +484,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
459
484
// We work with a copy of the argument for now; if this is in-place argument passing, we
460
485
// will later protect the source it comes from. This means the callee cannot observe if we
461
486
// 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) ;
463
488
if !already_live {
464
489
let local = callee_arg. as_local ( ) . unwrap ( ) ;
465
490
let meta = caller_arg_copy. meta ( ) ;
@@ -477,8 +502,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
477
502
// specifically.)
478
503
self . copy_op_allow_transmute ( & caller_arg_copy, & callee_arg) ?;
479
504
// 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 ) ?;
482
507
}
483
508
Ok ( ( ) )
484
509
}
@@ -525,7 +550,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
525
550
M :: call_intrinsic (
526
551
self ,
527
552
instance,
528
- & self . copy_fn_args ( args) ? ,
553
+ & self . copy_fn_args ( args) ,
529
554
destination,
530
555
target,
531
556
unwind,
@@ -602,8 +627,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
602
627
. map( |arg| (
603
628
arg. layout( ) . ty,
604
629
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 :?})" ) ,
607
632
}
608
633
) )
609
634
. collect:: <Vec <_>>( )
@@ -725,8 +750,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
725
750
callee_ty: callee_fn_abi. ret. layout. ty
726
751
} ) ;
727
752
}
728
- // Protect return place for in-place return value passing.
729
- M :: protect_in_place_function_argument ( self , destination) ?;
753
+
754
+ if let Either :: Left ( destination) =
755
+ self . place_to_op ( & destination) ?. as_mplace_or_imm ( )
756
+ {
757
+ // Protect return place for in-place return value passing.
758
+ M :: protect_in_place_function_argument ( self , & destination) ?;
759
+ }
730
760
731
761
// Don't forget to mark "initially live" locals as live.
732
762
self . storage_live_for_always_live_locals ( ) ?;
@@ -749,7 +779,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
749
779
// An `InPlace` does nothing here, we keep the original receiver intact. We can't
750
780
// really pass the argument in-place anyway, and we are constructing a new
751
781
// `Immediate` receiver.
752
- let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ? ;
782
+ let mut receiver = self . copy_fn_arg ( & args[ 0 ] ) ;
753
783
let receiver_place = loop {
754
784
match receiver. layout . ty . kind ( ) {
755
785
ty:: Ref ( ..) | ty:: RawPtr ( ..) => {
0 commit comments