diff --git a/tests/ui/c-variadic/roundtrip.rs b/tests/ui/c-variadic/roundtrip.rs new file mode 100644 index 000000000000..b6a858c715df --- /dev/null +++ b/tests/ui/c-variadic/roundtrip.rs @@ -0,0 +1,78 @@ +//@ run-pass +//@ ignore-backends: gcc +#![feature(c_variadic, const_c_variadic, const_destruct, const_raw_ptr_comparison)] + +use std::ffi::*; + +// In rustc we implement `va_arg` for the callee reading from a VaList, but still rely on LLVM +// for exactly how to pass c-variadic arguments and for constructing the VaList. Here we test +// that the rustc implementation works with what LLVM gives us. + +#[allow(improper_ctypes_definitions)] +const unsafe extern "C" fn variadic(mut ap: ...) -> (T, T) { + let x = ap.arg::(); + // Intersperse a small type to test alignment logic. A `u32` (i.e. `c_uint`) is the smallest + // type that implements `VaArgSafe`: smaller types would automatically be promoted. + assert!(ap.arg::() == 0xAAAA_AAAA); + let y = ap.arg::(); + + (x, y) +} + +macro_rules! roundtrip { + ($ty:ty, $a:expr, $b:expr) => { + const { + let a: $ty = $a; + let b: $ty = $b; + let (x, y) = variadic::<$ty>(a, 0xAAAA_AAAAu32, b); + assert!(a == x); + assert!(b == y); + } + + let a: $ty = $a; + let b: $ty = $b; + assert_eq!(variadic::<$ty>(a, 0xAAAA_AAAAu32, b), (a, b)) + }; +} + +macro_rules! roundtrip_ptr { + ($ty:ty, $a:expr, $b:expr) => { + const { + let a: $ty = $a; + let b: $ty = $b; + let (x, y) = variadic::<$ty>(a, 0xAAAA_AAAAu32, b); + assert!(a.guaranteed_eq(x).unwrap()); + assert!(b.guaranteed_eq(y).unwrap()); + } + + let a: $ty = $a; + let b: $ty = $b; + assert_eq!(variadic::<$ty>(a, 0xAAAA_AAAAu32, b), (a, b)) + }; +} + +fn main() { + unsafe { + roundtrip!(i32, -1, -2); + roundtrip!(i64, -1, -2); + roundtrip!(isize, -1, -2); + roundtrip!(c_int, -1, -2); + roundtrip!(c_long, -1, -2); + roundtrip!(c_longlong, -1, -2); + + roundtrip!(u32, 1, 2); + roundtrip!(u64, 1, 2); + roundtrip!(usize, 1, 2); + roundtrip!(c_uint, 1, 2); + roundtrip!(c_ulong, 1, 2); + roundtrip!(c_ulonglong, 1, 2); + + roundtrip!(f64, 3.14, 6.28); + roundtrip!(c_double, 3.14, 6.28); + + static mut A: u32 = 1u32; + static mut B: u32 = 2u32; + roundtrip_ptr!(*const u32, &raw const A, &raw const B); + roundtrip_ptr!(*mut u32, &raw mut A, &raw mut B); + } +}