@@ -5,6 +5,7 @@ use std::borrow::Cow;
5
5
6
6
use either:: { Left , Right } ;
7
7
use rustc_abi:: { self as abi, ExternAbi , FieldIdx , Integer , VariantIdx } ;
8
+ use rustc_data_structures:: fx:: FxHashSet ;
8
9
use rustc_hir:: def_id:: DefId ;
9
10
use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
10
11
use rustc_middle:: ty:: { self , AdtDef , Instance , Ty , VariantDef } ;
@@ -19,7 +20,7 @@ use super::{
19
20
Projectable , Provenance , ReturnAction , ReturnContinuation , Scalar , StackPopInfo , interp_ok,
20
21
throw_ub, throw_ub_custom, throw_unsup_format,
21
22
} ;
22
- use crate :: interpret:: EnteredTraceSpan ;
23
+ use crate :: interpret:: { EnteredTraceSpan , MemoryKind } ;
23
24
use crate :: { enter_trace_span, fluent_generated as fluent} ;
24
25
25
26
/// An argument passed to a function.
@@ -752,11 +753,41 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
752
753
& mut self ,
753
754
fn_val : FnVal < ' tcx , M :: ExtraFnVal > ,
754
755
( caller_abi, caller_fn_abi) : ( ExternAbi , & FnAbi < ' tcx , Ty < ' tcx > > ) ,
755
- args : & [ FnArg < ' tcx , M :: Provenance > ] ,
756
+ mut args : Vec < FnArg < ' tcx , M :: Provenance > > ,
756
757
with_caller_location : bool ,
757
758
) -> InterpResult < ' tcx > {
758
759
trace ! ( "init_fn_tail_call: {:#?}" , fn_val) ;
759
760
761
+ let mut local_temps = vec ! [ ] ;
762
+ let frame_locals = & self . stack ( ) . last ( ) . unwrap ( ) . locals ;
763
+ if frame_locals. iter ( ) . any ( |frame_local| frame_local. is_allocation ( ) ) {
764
+ // Allocations corresponding to the locals in the last frame.
765
+ let local_allocs: FxHashSet < _ > = frame_locals
766
+ . iter ( )
767
+ . filter_map ( |local| local. as_mplace_or_imm ( ) ?. left ( ) ?. 0 . provenance ?. get_alloc_id ( ) )
768
+ . collect ( ) ;
769
+
770
+ for arg in & mut args {
771
+ let mplace = match arg {
772
+ FnArg :: Copy ( op) => match op. as_mplace_or_imm ( ) {
773
+ Left ( mplace) => mplace,
774
+ Right ( _) => continue ,
775
+ } ,
776
+ FnArg :: InPlace ( mplace) => mplace. clone ( ) ,
777
+ } ;
778
+
779
+ if let Some ( prov) = mplace. ptr ( ) . provenance
780
+ && let Some ( alloc_id) = prov. get_alloc_id ( )
781
+ && local_allocs. contains ( & alloc_id)
782
+ {
783
+ let temp_mplace = self . allocate ( * arg. layout ( ) , MemoryKind :: Stack ) ?;
784
+ self . copy_op ( & mplace, & temp_mplace) ?;
785
+ local_temps. push ( temp_mplace. clone ( ) ) ;
786
+ * arg = FnArg :: Copy ( temp_mplace. into ( ) ) ;
787
+ }
788
+ }
789
+ }
790
+
760
791
// This is the "canonical" implementation of tails calls,
761
792
// a pop of the current stack frame, followed by a normal call
762
793
// which pushes a new stack frame, with the return address from
@@ -785,12 +816,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
785
816
self . init_fn_call (
786
817
fn_val,
787
818
( caller_abi, caller_fn_abi) ,
788
- args,
819
+ & args,
789
820
with_caller_location,
790
821
& return_place,
791
822
ret,
792
823
unwind,
793
- )
824
+ ) ?;
825
+
826
+ for local_temp in local_temps {
827
+ self . deallocate_ptr ( local_temp. ptr ( ) , None , MemoryKind :: Stack ) ?;
828
+ }
829
+
830
+ interp_ok ( ( ) )
794
831
}
795
832
796
833
pub ( super ) fn init_drop_in_place_call (
0 commit comments