@@ -4,9 +4,10 @@ use std::assert_matches::assert_matches;
44use std:: borrow:: Cow ;
55
66use either:: { Left , Right } ;
7- use rustc_abi:: { self as abi, ExternAbi , FieldIdx , Integer , VariantIdx } ;
7+ use rustc_abi:: { self as abi, ExternAbi , FieldIdx , HasDataLayout , Integer , Size , VariantIdx } ;
88use rustc_hir:: def_id:: DefId ;
9- use rustc_middle:: ty:: layout:: { IntegerExt , TyAndLayout } ;
9+ use rustc_middle:: mir:: interpret:: AllocId ;
10+ use rustc_middle:: ty:: layout:: { HasTyCtxt , IntegerExt , TyAndLayout } ;
1011use rustc_middle:: ty:: { self , AdtDef , Instance , Ty , VariantDef } ;
1112use rustc_middle:: { bug, mir, span_bug} ;
1213use rustc_span:: sym;
@@ -15,9 +16,9 @@ use tracing::field::Empty;
1516use tracing:: { info, instrument, trace} ;
1617
1718use super :: {
18- CtfeProvenance , FnVal , ImmTy , InterpCx , InterpResult , MPlaceTy , Machine , OpTy , PlaceTy ,
19- Projectable , Provenance , ReturnAction , ReturnContinuation , Scalar , StackPopInfo , interp_ok ,
20- throw_ub, throw_ub_custom,
19+ CtfeProvenance , FnVal , ImmTy , InterpCx , InterpResult , MPlaceTy , Machine , MemoryKind , OpTy ,
20+ PlaceTy , Pointer , Projectable , Provenance , ReturnAction , ReturnContinuation , Scalar ,
21+ StackPopInfo , interp_ok , throw_ub, throw_ub_custom,
2122} ;
2223use crate :: interpret:: EnteredTraceSpan ;
2324use crate :: { enter_trace_span, fluent_generated as fluent} ;
@@ -334,6 +335,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
334335 interp_ok ( ( ) )
335336 }
336337
338+ /// Store the (c-variadic) variable argument list in global memory.
339+ fn init_va_list (
340+ & mut self ,
341+ caller_fn_abi : & FnAbi < ' tcx , Ty < ' tcx > > ,
342+ args : & [ FnArg < ' tcx , M :: Provenance > ] ,
343+ fixed_count : usize ,
344+ ) -> InterpResult < ' tcx , AllocId > {
345+ let id = self . tcx ( ) . reserve_and_set_va_list_alloc ( ) ;
346+
347+ // Slice out the vararg part of the actual arguments.
348+ let vararg_args = & args[ fixed_count..] ;
349+ let vararg_abis = & caller_fn_abi. args [ fixed_count..] ;
350+ debug_assert_eq ! ( vararg_args. len( ) , vararg_abis. len( ) ) ;
351+
352+ let mut varargs = Vec :: with_capacity ( vararg_args. len ( ) ) ;
353+ for ( fn_arg, abi) in vararg_args. iter ( ) . zip ( vararg_abis) {
354+ let op = self . copy_fn_arg ( fn_arg) ;
355+ let mplace = self . allocate ( abi. layout , MemoryKind :: Stack ) ?;
356+ self . copy_op ( & op, & mplace) ?;
357+
358+ varargs. push ( mplace) ;
359+ }
360+
361+ // When the frame is dropped, this ID is used to deallocate the variable arguments list.
362+ self . frame_mut ( ) . va_list = Some ( id) ;
363+
364+ // A global map that is used to implement `va_arg`.
365+ self . memory . va_list_map . insert ( id, varargs) ;
366+
367+ interp_ok ( id)
368+ }
369+
337370 /// The main entry point for creating a new stack frame: performs ABI checks and initializes
338371 /// arguments.
339372 #[ instrument( skip( self ) , level = "trace" ) ]
@@ -470,7 +503,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
470503 let place = self . eval_place ( dest) ?;
471504 let mplace = self . force_allocation ( & place) ?;
472505
473- let _ = mplace;
506+ let alloc_id = self . init_va_list ( caller_fn_abi, args, fixed_count) ?;
507+
508+ // Functions are global allocations, so make sure we get the right root pointer.
509+ // We know this is not an `extern static` so this cannot fail.
510+ let ptr = self . global_root_pointer ( Pointer :: from ( alloc_id) ) . unwrap ( ) ;
511+ let addr = Scalar :: from_pointer ( ptr, self ) ;
512+
513+ // Store the pointer to the global variable arguments list allocation in the
514+ // first bytes of the `VaList` value.
515+ let mut alloc = self
516+ . get_ptr_alloc_mut ( mplace. ptr ( ) , self . data_layout ( ) . pointer_size ( ) ) ?
517+ . expect ( "not a ZST" ) ;
518+
519+ alloc. write_ptr_sized ( Size :: ZERO , addr) ?;
474520 } else if Some ( local) == body. spread_arg {
475521 // Make the local live once, then fill in the value field by field.
476522 self . storage_live ( local) ?;
0 commit comments