Rollup merge of #155821 - folkertdev:doc-va-list-clone, r=joshtriplett

c-variadic: document `Clone` and `Drop` instances and require `VaArgSafe: Copy`

tracking issue: https://github.com/rust-lang/rust/issues/44930

Fixing some things that came up in the stabilization PR

r? tgross35
cc @kpreid
This commit is contained in:
Jacob Pratt
2026-04-30 22:28:32 -04:00
committed by GitHub
3 changed files with 37 additions and 2 deletions
@@ -148,8 +148,9 @@ pub fn codegen_intrinsic_call(
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();
+16 -1
View File
@@ -251,6 +251,9 @@ pub(crate) const fn duplicate(&self) -> Self {
#[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
@@ -263,8 +266,14 @@ fn clone(&self) -> Self {
#[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`.
// 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) }
}
@@ -324,7 +333,7 @@ impl<T> Sealed for *const T {}
// 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") => {
@@ -381,6 +390,12 @@ const fn va_arg_safe_check<T: VaArgSafe>() {}
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> {
+19
View File
@@ -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
}