Skip to content

Commit 23fa1b4

Browse files
committed
on call, split the standard and c-variadic arguments
1 parent e4dffec commit 23fa1b4

1 file changed

Lines changed: 35 additions & 9 deletions

File tree

  • compiler/rustc_const_eval/src/interpret

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use tracing::{info, instrument, trace};
1717
use 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
};
2222
use crate::interpret::EnteredTraceSpan;
2323
use 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

Comments
 (0)