Skip to content

Conversation

@folkertdev
Copy link
Contributor

@folkertdev folkertdev commented Jan 2, 2026

tracking issue: #44930

The new GlobalAlloc::VaList is used to create an AllocId that represents the variable argument list of a frame. The allocation itself does not store any data, all we need is the unique identifier.

The actual variable argument list is stored in Memory, and keyed by the AllocId. The Frame also stores this AllocId, so that when a frame is popped, it can deallocate the variable arguments.

At "runtime" a VaList value stores a pointer to the global allocation in its first bytes. The provenance on this pointer can be used to retrieve its AllocId, and the offset of the pointer is used to store the index of the next argument to read from the variable argument list.

Miri does not yet support va_arg, but I think that can be done separetely?

r? @RalfJung
cc @workingjubilee

@folkertdev folkertdev added A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) F-c_variadic `#![feature(c_variadic)]` labels Jan 2, 2026
@rustbot rustbot added A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Jan 2, 2026
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from d30044f to 5f98625 Compare January 2, 2026 18:57
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 5f98625 to 3368321 Compare January 2, 2026 19:09
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 3368321 to 41a34bc Compare January 2, 2026 19:32
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 41a34bc to 8608ba7 Compare January 2, 2026 20:51
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 8608ba7 to 207b032 Compare January 2, 2026 21:58
@rust-bors
Copy link
Contributor

rust-bors bot commented Jan 4, 2026

☔ The latest upstream changes made this pull request unmergeable. Please resolve the merge conflicts.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 207b032 to 1794556 Compare January 5, 2026 10:30
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch 2 times, most recently from b297adc to c081ba3 Compare January 5, 2026 11:14
@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from c081ba3 to 293ba18 Compare January 5, 2026 12:25
@folkertdev folkertdev marked this pull request as ready for review January 5, 2026 17:34
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jan 5, 2026
@rustbot
Copy link
Collaborator

rustbot commented Jan 5, 2026

This PR changes rustc_public

cc @oli-obk, @celinval, @ouz-a, @makai410

Some changes occurred to the CTFE machinery

cc @RalfJung, @oli-obk, @lcnr

Some changes occurred in compiler/rustc_codegen_cranelift

cc @bjorn3

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri

Some changes occurred to the CTFE / Miri interpreter

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

The Miri subtree was changed

cc @rust-lang/miri

Some changes occurred to the intrinsics. Make sure the CTFE / Miri interpreter
gets adapted for the changes, if necessary.

cc @rust-lang/miri, @RalfJung, @oli-obk, @lcnr

Some changes occurred in compiler/rustc_codegen_gcc

cc @antoyo, @GuillaumeGomez

@rustbot rustbot removed the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Jan 5, 2026
@rust-bors
Copy link
Contributor

rust-bors bot commented Jan 10, 2026

☔ The latest upstream changes (presumably #146923) made this pull request unmergeable. Please resolve the merge conflicts.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from e4bc4f9 to 8634e40 Compare January 29, 2026 22:06
@rustbot
Copy link
Collaborator

rustbot commented Jan 29, 2026

This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@rust-log-analyzer

This comment has been minimized.

@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 8634e40 to 03543fb Compare January 29, 2026 22:15
@rust-log-analyzer

This comment has been minimized.

@folkertdev
Copy link
Contributor Author

I believe I got everything

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 29, 2026
@rust-log-analyzer

This comment has been minimized.

Copy link
Member

@RalfJung RalfJung left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next round of comments. Also, CI seems unhappy?

View changes since this review

Comment on lines +353 to +360
// The check for the DefKind is so that we don't request the fn_sig of a closure.
// Otherwise, we hit:
//
// DefId(1:180 ~ std[269c]::rt::lang_start_internal::{closure#0}) does not have a "fn_sig"
let (fixed_count, callee_c_variadic_args) =
if matches!(self.tcx.def_kind(instance.def_id()), DefKind::Fn)
&& let callee_fn_sig = self.tcx.fn_sig(instance.def_id()).skip_binder()
&& callee_fn_sig.c_variadic()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is very odd and seems to break our usual abstractions. How does codegen deal with this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure, I asked in #t-compiler/help > no `fn_sig`for `lang_start_internal` closure. My impression is that those functions just never get fn_sig called on them, but maybe there is some logic that I'm missing somewhere.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently checking for the DefKind is fairly standard

Comment on lines 472 to 475
// NOTE: this handles the extra caller location argument
// when `#[track_caller]` is used. This attribute is only allowed on `extern "Rust"`
// functions, so the c-variadic case does not need to handle the extra argument.
callee_fn_abi.args.iter().enumerate()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand this comment. How does this line do anything wrt track_caller?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this additional argument is not reflected in fixed_count

Comment on lines 640 to 667
pub(crate) fn allocate_varargs<I>(
&mut self,
caller_args: &mut I,
) -> InterpResult<'tcx, VecDeque<MPlaceTy<'tcx, M::Provenance>>>
where
I: Iterator<Item = (&'a FnArg<'tcx, M::Provenance>, &'a ArgAbi<'tcx, Ty<'tcx>>)>,
{
// Consume the remaining arguments and store them in fresh allocations.
let mut varargs = Vec::new();
for (fn_arg, abi) in caller_args {
// FIXME: do we have to worry about in-place argument passing?
let op = self.copy_fn_arg(fn_arg);
let mplace = self.allocate(abi.layout, MemoryKind::Stack)?;
self.copy_op(&op, &mplace)?;

varargs.push(mplace);
}

// When the frame is dropped, these variable arguments are deallocated.
self.frame_mut().va_list = varargs.clone();

interp_ok(varargs.into())
}

fn deallocate_varargs(
&mut self,
varargs: &[MPlaceTy<'tcx, M::Provenance>],
) -> InterpResult<'tcx> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two functions look symmetric, but they are very different: one implicitly works on the current frame, the other takes the vararg list as argument. Such a false symmetry is quite confusing.

Any ideas how to avoid that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the self.frame_mut().va_list = varargs.clone(); line out, so now the one allocates, the other deallocates. They both receive the variadic arguments as an argument actually.

let f = helper as *const ();
let f = std::mem::transmute::<_, unsafe extern "C" fn(...)>(f);

f();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please pass an argument here so that the code looks more legit (it does pass the required number of arguments, just not in the right way)

} else {
// NOTE: this handles the extra caller location argument
// when `#[track_caller]` is used. This attribute is only allowed on `extern "Rust"`
// functions, so the c-variadic case does not need to handle the extra argument.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is relevant, it seems good to have an assertion double-checking this property.

@RalfJung
Copy link
Member

@rustbot author

@rustbot rustbot added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 31, 2026
@folkertdev folkertdev force-pushed the c-variadic-const-eval branch from 39af72b to 49ba67a Compare January 31, 2026 14:28
@folkertdev
Copy link
Contributor Author

@rustbot ready

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jan 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-const-eval Area: Constant evaluation, covers all const contexts (static, const fn, ...) A-LLVM Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues. F-c_variadic `#![feature(c_variadic)]` S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants