@@ -17,7 +17,7 @@ use tracing::{info, instrument, trace};
1717use super :: {
1818 CtfeProvenance , FnVal , ImmTy , InterpCx , InterpResult , MPlaceTy , Machine , OpTy , PlaceTy ,
1919 Projectable , Provenance , ReturnAction , ReturnContinuation , Scalar , StackPopInfo , interp_ok,
20- throw_ub, throw_ub_custom, throw_unsup_format ,
20+ throw_ub, throw_ub_custom,
2121} ;
2222use crate :: interpret:: EnteredTraceSpan ;
2323use crate :: { enter_trace_span, fluent_generated as fluent} ;
@@ -349,12 +349,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
349349 ) -> InterpResult < ' tcx > {
350350 let _trace = enter_trace_span ! ( M , step:: init_stack_frame, %instance, tracing_separate_thread = Empty ) ;
351351
352- // Compute callee information.
353- // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
354- let callee_fn_abi = self . fn_abi_of_instance ( instance, ty:: List :: empty ( ) ) ?;
352+ let ( fixed_count, c_variadic_args) = if caller_fn_abi. c_variadic {
353+ let sig = self . tcx . fn_sig ( instance. def_id ( ) ) . skip_binder ( ) ;
354+ let fixed_count = sig. inputs ( ) . skip_binder ( ) . len ( ) ;
355+ assert ! ( caller_fn_abi. args. len( ) >= fixed_count) ;
356+ let extra_tys: Vec < Ty < ' tcx > > =
357+ caller_fn_abi. args [ fixed_count..] . iter ( ) . map ( |arg_abi| arg_abi. layout . ty ) . collect ( ) ;
355358
356- if callee_fn_abi. c_variadic || caller_fn_abi. c_variadic {
357- throw_unsup_format ! ( "calling a c-variadic function is not supported" ) ;
359+ ( fixed_count, self . tcx . mk_type_list ( & extra_tys) )
360+ } else {
361+ ( caller_fn_abi. args . len ( ) , ty:: List :: empty ( ) )
362+ } ;
363+
364+ let callee_fn_abi = self . fn_abi_of_instance ( instance, c_variadic_args) ?;
365+
366+ if callee_fn_abi. c_variadic ^ caller_fn_abi. c_variadic {
367+ unreachable ! ( "caller and callee disagree on being c-variadic" ) ;
358368 }
359369
360370 if caller_fn_abi. conv != callee_fn_abi. conv {
@@ -436,16 +446,32 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
436446 // this is a single iterator (that handles `spread_arg`), then
437447 // `pass_argument` would be the loop body. It takes care to
438448 // not advance `caller_iter` for ignored arguments.
439- let mut callee_args_abis = callee_fn_abi. args . iter ( ) . enumerate ( ) ;
440- for local in body. args_iter ( ) {
449+ let mut callee_args_abis = if caller_fn_abi. c_variadic {
450+ callee_fn_abi. args [ ..fixed_count] . iter ( ) . enumerate ( )
451+ } else {
452+ callee_fn_abi. args . iter ( ) . enumerate ( )
453+ } ;
454+
455+ let mut it = body. args_iter ( ) . peekable ( ) ;
456+ while let Some ( local) = it. next ( ) {
441457 // Construct the destination place for this argument. At this point all
442458 // locals are still dead, so we cannot construct a `PlaceTy`.
443459 let dest = mir:: Place :: from ( local) ;
444460 // `layout_of_local` does more than just the instantiation we need to get the
445461 // type, but the result gets cached so this avoids calling the instantiation
446462 // query *again* the next time this local is accessed.
447463 let ty = self . layout_of_local ( self . frame ( ) , local, None ) ?. ty ;
448- if Some ( local) == body. spread_arg {
464+ if caller_fn_abi. c_variadic && it. peek ( ) . is_none ( ) {
465+ // The callee's signature has an additional VaList argument, that the caller
466+ // won't actually pass. Here we synthesize a `VaList` value, whose leading bytes
467+ // are a pointer that can be mapped to the corresponding variable argument list.
468+ self . storage_live ( local) ?;
469+
470+ let place = self . eval_place ( dest) ?;
471+ let mplace = self . force_allocation ( & place) ?;
472+
473+ let _ = mplace;
474+ } else if Some ( local) == body. spread_arg {
449475 // Make the local live once, then fill in the value field by field.
450476 self . storage_live ( local) ?;
451477 // Must be a tuple
0 commit comments