Skip to content

Commit 8e09112

Browse files
committed
c_variadic: use Clone instead of va_copy
1 parent 5c53093 commit 8e09112

10 files changed

Lines changed: 56 additions & 87 deletions

File tree

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
15061506
}
15071507

15081508
// FIXME implement variadics in cranelift
1509-
sym::va_copy | sym::va_arg | sym::va_end => {
1509+
sym::va_arg | sym::va_end => {
15101510
fx.tcx.dcx().span_fatal(
15111511
source_info.span,
15121512
"Defining variadic functions is not yet supported by Cranelift",

compiler/rustc_codegen_gcc/src/intrinsic/mod.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,9 +395,6 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tc
395395
sym::breakpoint => {
396396
unimplemented!();
397397
}
398-
sym::va_copy => {
399-
unimplemented!();
400-
}
401398
sym::va_arg => {
402399
unimplemented!();
403400
}

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -270,14 +270,6 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
270270
return Ok(());
271271
}
272272
sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
273-
sym::va_copy => {
274-
let dest = args[0].immediate();
275-
self.call_intrinsic(
276-
"llvm.va_copy",
277-
&[self.val_ty(dest)],
278-
&[dest, args[1].immediate()],
279-
)
280-
}
281273
sym::va_arg => {
282274
match result.layout.backend_repr {
283275
BackendRepr::Scalar(scalar) => {

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -611,12 +611,6 @@ pub(crate) fn check_intrinsic_type(
611611
(0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit)
612612
}
613613

614-
sym::va_copy => {
615-
let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not);
616-
let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
617-
(0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
618-
}
619-
620614
sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)),
621615

622616
sym::nontemporal_store => {

compiler/rustc_span/src/symbol.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2435,7 +2435,6 @@ symbols! {
24352435
v1,
24362436
v8plus,
24372437
va_arg,
2438-
va_copy,
24392438
va_end,
24402439
va_list,
24412440
va_start,

library/core/src/ffi/va_list.rs

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#[cfg(not(target_arch = "xtensa"))]
66
use crate::ffi::c_void;
77
use crate::fmt;
8-
use crate::intrinsics::{va_arg, va_copy};
8+
use crate::intrinsics::va_arg;
99
use crate::marker::PhantomCovariantLifetime;
1010

1111
// There are currently three flavors of how a C `va_list` is implemented for
@@ -48,7 +48,7 @@ crate::cfg_select! {
4848
/// [AArch64 Procedure Call Standard]:
4949
/// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf
5050
#[repr(C)]
51-
#[derive(Debug)]
51+
#[derive(Debug, Clone, Copy)]
5252
struct VaListInner {
5353
stack: *const c_void,
5454
gr_top: *const c_void,
@@ -66,7 +66,7 @@ crate::cfg_select! {
6666
/// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/PowerPC/PPCISelLowering.cpp#L4089-L4111
6767
/// [GCC header]: https://web.mit.edu/darwin/src/modules/gcc/gcc/ginclude/va-ppc.h
6868
#[repr(C)]
69-
#[derive(Debug)]
69+
#[derive(Debug, Clone, Copy)]
7070
#[rustc_pass_indirectly_in_non_rustic_abis]
7171
struct VaListInner {
7272
gpr: u8,
@@ -84,7 +84,7 @@ crate::cfg_select! {
8484
/// [S/390x ELF Application Binary Interface Supplement]:
8585
/// https://docs.google.com/gview?embedded=true&url=https://github.com/IBM/s390x-abi/releases/download/v1.7/lzsabi_s390x.pdf
8686
#[repr(C)]
87-
#[derive(Debug)]
87+
#[derive(Debug, Clone, Copy)]
8888
#[rustc_pass_indirectly_in_non_rustic_abis]
8989
struct VaListInner {
9090
gpr: i64,
@@ -101,7 +101,7 @@ crate::cfg_select! {
101101
/// [System V AMD64 ABI]:
102102
/// https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
103103
#[repr(C)]
104-
#[derive(Debug)]
104+
#[derive(Debug, Clone, Copy)]
105105
#[rustc_pass_indirectly_in_non_rustic_abis]
106106
struct VaListInner {
107107
gp_offset: i32,
@@ -118,7 +118,7 @@ crate::cfg_select! {
118118
/// [LLVM source]:
119119
/// https://github.com/llvm/llvm-project/blob/af9a4263a1a209953a1d339ef781a954e31268ff/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp#L1211-L1215
120120
#[repr(C)]
121-
#[derive(Debug)]
121+
#[derive(Debug, Clone, Copy)]
122122
#[rustc_pass_indirectly_in_non_rustic_abis]
123123
struct VaListInner {
124124
stk: *const i32,
@@ -135,7 +135,7 @@ crate::cfg_select! {
135135
/// [LLVM source]:
136136
/// https://github.com/llvm/llvm-project/blob/0cdc1b6dd4a870fc41d4b15ad97e0001882aba58/clang/lib/CodeGen/Targets/Hexagon.cpp#L407-L417
137137
#[repr(C)]
138-
#[derive(Debug)]
138+
#[derive(Debug, Clone, Copy)]
139139
#[rustc_pass_indirectly_in_non_rustic_abis]
140140
struct VaListInner {
141141
__current_saved_reg_area_pointer: *const c_void,
@@ -157,7 +157,7 @@ crate::cfg_select! {
157157
_ => {
158158
/// Basic implementation of a `va_list`.
159159
#[repr(transparent)]
160-
#[derive(Debug)]
160+
#[derive(Debug, Clone, Copy)]
161161
struct VaListInner {
162162
ptr: *const c_void,
163163
}
@@ -179,6 +179,29 @@ impl fmt::Debug for VaList<'_> {
179179
}
180180
}
181181

182+
impl Clone for VaList<'_> {
183+
#[inline]
184+
fn clone(&self) -> Self {
185+
// For all current LLVM targets `va_copy` is just a `memcpy`.
186+
//
187+
// We only implement Clone and not Copy because some future target might not be able to
188+
// implement Copy (e.g. because it allocates).
189+
Self { inner: self.inner, _marker: self._marker }
190+
}
191+
}
192+
193+
impl Drop for VaList<'_> {
194+
fn drop(&mut self) {
195+
// For all current LLVM targets `va_end` is a no-op.
196+
//
197+
// We implement `Drop` here because some future target might need to actually run
198+
// destructors (e.g. to deallocate).
199+
//
200+
// Rust requires that not calling `va_end` on a `va_list` does not cause undefined
201+
// behaviour: it is safe to leak values.
202+
}
203+
}
204+
182205
mod sealed {
183206
pub trait Sealed {}
184207

@@ -253,26 +276,6 @@ impl<'f> VaList<'f> {
253276
}
254277
}
255278

256-
impl<'f> Clone for VaList<'f> {
257-
#[inline]
258-
fn clone(&self) -> Self {
259-
let mut dest = crate::mem::MaybeUninit::uninit();
260-
// SAFETY: we write to the `MaybeUninit`, thus it is initialized and `assume_init` is legal.
261-
unsafe {
262-
va_copy(dest.as_mut_ptr(), self);
263-
dest.assume_init()
264-
}
265-
}
266-
}
267-
268-
impl<'f> Drop for VaList<'f> {
269-
fn drop(&mut self) {
270-
// Rust requires that not calling `va_end` on a `va_list` does not cause undefined behaviour
271-
// (as it is safe to leak values). As `va_end` is a no-op on all current LLVM targets, this
272-
// destructor is empty.
273-
}
274-
}
275-
276279
// Checks (via an assert in `compiler/rustc_ty_utils/src/abi.rs`) that the C ABI for the current
277280
// target correctly implements `rustc_pass_indirectly_in_non_rustic_abis`.
278281
const _: () = {

library/core/src/intrinsics/mod.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,19 +3456,6 @@ pub(crate) const fn miri_promise_symbolic_alignment(ptr: *const (), align: usize
34563456
)
34573457
}
34583458

3459-
/// Copies the current location of arglist `src` to the arglist `dst`.
3460-
///
3461-
/// # Safety
3462-
///
3463-
/// You must check the following invariants before you call this function:
3464-
///
3465-
/// - `dest` must be non-null and point to valid, writable memory.
3466-
/// - `dest` must not alias `src`.
3467-
///
3468-
#[rustc_intrinsic]
3469-
#[rustc_nounwind]
3470-
pub unsafe fn va_copy<'f>(dest: *mut VaList<'f>, src: &VaList<'f>);
3471-
34723459
/// Loads an argument of type `T` from the `va_list` `ap` and increment the
34733460
/// argument `ap` points to.
34743461
///

tests/codegen-llvm/cffi/c-variadic-copy.rs

Lines changed: 0 additions & 16 deletions
This file was deleted.

tests/codegen-llvm/cffi/c-variadic-opt.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,3 @@ pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 {
1717
vprintf(fmt, ap)
1818
// CHECK: call void @llvm.va_end
1919
}
20-
21-
// Check that `VaList::clone` gets inlined into a direct call to `llvm.va_copy`
22-
#[no_mangle]
23-
pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 {
24-
// CHECK: call void @llvm.va_start
25-
let mut ap2 = ap.clone();
26-
// CHECK: call void @llvm.va_copy
27-
let res = vprintf(fmt, ap2);
28-
res
29-
// CHECK: call void @llvm.va_end
30-
}

tests/ui/c-variadic/copy.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ run-pass
2+
//@ ignore-backends: gcc
3+
#![feature(c_variadic)]
4+
5+
// Test the behavior of `VaList::clone`. In C a `va_list` is duplicated using `va_copy`, but the
6+
// rust api just uses `Clone`. This should create a completely independent cursor into the
7+
// variable argument list: advancing the original has no effect on the copy and vice versa.
8+
9+
fn main() {
10+
unsafe { variadic(1, 2, 3) }
11+
}
12+
13+
unsafe extern "C" fn variadic(mut ap1: ...) {
14+
let mut ap2 = ap1.clone();
15+
16+
assert_eq!(ap1.arg::<i32>(), 1);
17+
assert_eq!(ap2.arg::<i32>(), 1);
18+
19+
assert_eq!(ap2.arg::<i32>(), 2);
20+
assert_eq!(ap1.arg::<i32>(), 2);
21+
22+
drop(ap1);
23+
assert_eq!(ap2.arg::<i32>(), 3);
24+
}

0 commit comments

Comments
 (0)