@@ -5,6 +5,7 @@ use std::borrow::Cow;
55
66use either:: { Left , Right } ;
77use rustc_abi:: { self as abi, ExternAbi , FieldIdx , Integer , VariantIdx } ;
8+ use rustc_data_structures:: fx:: FxHashSet ;
89use rustc_hir:: def_id:: DefId ;
910use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
1011use rustc_middle:: ty:: { self , AdtDef , Instance , Ty , VariantDef } ;
@@ -19,7 +20,7 @@ use super::{
1920 Projectable , Provenance , ReturnAction , ReturnContinuation , Scalar , StackPopInfo , interp_ok,
2021 throw_ub, throw_ub_custom, throw_unsup_format,
2122} ;
22- use crate :: interpret:: EnteredTraceSpan ;
23+ use crate :: interpret:: { EnteredTraceSpan , MemoryKind } ;
2324use crate :: { enter_trace_span, fluent_generated as fluent} ;
2425
2526/// An argument passed to a function.
@@ -752,11 +753,41 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
752753 & mut self ,
753754 fn_val : FnVal < ' tcx , M :: ExtraFnVal > ,
754755 ( caller_abi, caller_fn_abi) : ( ExternAbi , & FnAbi < ' tcx , Ty < ' tcx > > ) ,
755- args : & [ FnArg < ' tcx , M :: Provenance > ] ,
756+ mut args : Vec < FnArg < ' tcx , M :: Provenance > > ,
756757 with_caller_location : bool ,
757758 ) -> InterpResult < ' tcx > {
758759 trace ! ( "init_fn_tail_call: {:#?}" , fn_val) ;
759760
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+
760791 // This is the "canonical" implementation of tails calls,
761792 // a pop of the current stack frame, followed by a normal call
762793 // which pushes a new stack frame, with the return address from
@@ -785,12 +816,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
785816 self . init_fn_call (
786817 fn_val,
787818 ( caller_abi, caller_fn_abi) ,
788- args,
819+ & args,
789820 with_caller_location,
790821 & return_place,
791822 ret,
792823 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 ( ( ) )
794831 }
795832
796833 pub ( super ) fn init_drop_in_place_call (
0 commit comments