Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
return Ok(());
}

// va_end uses the fallback body (a no-op).
sym::va_start => bx.va_start(args[0].immediate()),
sym::va_end => bx.va_end(args[0].immediate()),

sym::size_of_val => {
let tp_ty = fn_args.type_at(0);
let (_, meta) = args[0].val.pointer_parts();
Expand Down
17 changes: 16 additions & 1 deletion library/core/src/ffi/va_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ impl VaList<'_> {

#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
impl<'f> const Clone for VaList<'f> {
/// Clone the [`VaList`], producing a second independent cursor into the variable argument list.
///
/// Corresponds to `va_copy` in C.
#[inline] // Avoid codegen when not used to help backends that don't support VaList.
fn clone(&self) -> Self {
// We only implement Clone and not Copy because some future target might not be able to
Expand All @@ -263,8 +266,14 @@ impl<'f> const Clone for VaList<'f> {

#[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")]
impl<'f> const Drop for VaList<'f> {
/// Drop the [`VaList`].
///
/// Corresponds to `va_end` in C.
#[inline] // Avoid codegen when not used to help backends that don't support VaList.
fn drop(&mut self) {
// Call the rust `va_end` intrinsic, which is a no-op and does not map to LLVM `va_end`.
Copy link
Copy Markdown
Member

@programmerjake programmerjake Apr 30, 2026

Choose a reason for hiding this comment

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

this is incorrect on latest nightly, it does call llvm.va_end. see #155697 (comment)

View changes since the review

// The rust intrinsic exists as a hook for Miri to check for UB.
//
// SAFETY: this variable argument list is being dropped, so won't be read from again.
unsafe { va_end(self) }
}
Expand Down Expand Up @@ -324,7 +333,7 @@ mod sealed {
// types with an alignment larger than 8, or with a non-scalar layout. Inline assembly can be used
// to accept unsupported types in the meantime.
#[lang = "va_arg_safe"]
pub unsafe trait VaArgSafe: sealed::Sealed {}
pub unsafe trait VaArgSafe: Copy + sealed::Sealed {}

crate::cfg_select! {
any(target_arch = "avr", target_arch = "msp430") => {
Expand Down Expand Up @@ -381,6 +390,12 @@ const _: () = {
va_arg_safe_check::<crate::ffi::c_ulonglong>();

va_arg_safe_check::<crate::ffi::c_double>();

va_arg_safe_check::<*const crate::ffi::c_void>();
va_arg_safe_check::<*mut crate::ffi::c_void>();

va_arg_safe_check::<*const crate::ffi::c_char>();
va_arg_safe_check::<*mut crate::ffi::c_char>();
};

impl<'f> VaList<'f> {
Expand Down
19 changes: 19 additions & 0 deletions tests/codegen-llvm/c-variadic-va-end.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//@ add-minicore
//@ compile-flags: -Copt-level=3
#![feature(c_variadic)]
#![crate_type = "lib"]

unsafe extern "C" {
fn g(v: *mut u8);
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn f(mut args: ...) {
// CHECK: call void @llvm.va_start
unsafe { g(&raw mut args as *mut u8) }
// We expect one call to the LLVM va_end from our desugaring of `...`. The `Drop` implementation
// should only call the rust va_end intrinsic, which is a no-op.
//
// CHECK: call void @llvm.va_end
// CHECK-NOT: call void @llvm.va_end
}
Loading