blob: 2f8d043fb5db65f2b9aa92d179e543e05b7f2a69 [file] [log] [blame] [edit]
//@ edition: 2021
//@ run-pass
//@ ignore-backends: gcc
#![feature(c_variadic)]
#![feature(const_c_variadic)]
#![feature(const_destruct)]
#![feature(const_cmp)]
#![feature(const_trait_impl)]
use std::ffi::*;
fn ignores_arguments() {
const unsafe extern "C" fn variadic(_: ...) {}
const {
unsafe { variadic() };
unsafe { variadic(1, 2, 3) };
}
}
fn echo() {
const unsafe extern "C" fn variadic(mut ap: ...) -> i32 {
ap.arg()
}
assert_eq!(unsafe { variadic(1) }, 1);
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
const {
assert!(unsafe { variadic(1) } == 1);
assert!(unsafe { variadic(3, 2, 1) } == 3);
}
}
fn forward_by_val() {
const unsafe fn helper(mut ap: VaList) -> i32 {
ap.arg()
}
const unsafe extern "C" fn variadic(ap: ...) -> i32 {
helper(ap)
}
assert_eq!(unsafe { variadic(1) }, 1);
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
const {
assert!(unsafe { variadic(1) } == 1);
assert!(unsafe { variadic(3, 2, 1) } == 3);
}
}
fn forward_by_ref() {
const unsafe fn helper(ap: &mut VaList) -> i32 {
ap.arg()
}
const unsafe extern "C" fn variadic(mut ap: ...) -> i32 {
helper(&mut ap)
}
assert_eq!(unsafe { variadic(1) }, 1);
assert_eq!(unsafe { variadic(3, 2, 1) }, 3);
const {
assert!(unsafe { variadic(1) } == 1);
assert!(unsafe { variadic(3, 2, 1) } == 3);
}
}
#[allow(improper_ctypes_definitions)]
fn nested() {
const unsafe fn helper(mut ap1: VaList, mut ap2: VaList) -> (i32, i32) {
(ap1.arg(), ap2.arg())
}
const unsafe extern "C" fn variadic2(ap1: VaList, ap2: ...) -> (i32, i32) {
helper(ap1, ap2)
}
const unsafe extern "C" fn variadic1(ap1: ...) -> (i32, i32) {
variadic2(ap1, 2, 2)
}
assert_eq!(unsafe { variadic1(1) }, (1, 2));
const {
let (a, b) = unsafe { variadic1(1, 1) };
assert!(a != 2);
assert!(a == 1);
assert!(b != 1);
assert!(b == 2);
}
}
fn various_types() {
const unsafe extern "C" fn check_list_2(mut ap: ...) {
macro_rules! continue_if {
($cond:expr) => {
if !($cond) {
panic!();
}
};
}
const unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool {
match CStr::from_ptr(ptr).to_str() {
Ok(cstr) => cstr == val,
Err(_) => panic!(),
}
}
continue_if!(ap.arg::<c_double>().floor() == 3.14f64.floor());
continue_if!(ap.arg::<c_long>() == 12);
continue_if!(ap.arg::<c_int>() == 'a' as c_int);
continue_if!(ap.arg::<c_double>().floor() == 6.18f64.floor());
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello"));
continue_if!(ap.arg::<c_int>() == 42);
continue_if!(compare_c_str(ap.arg::<*const c_char>(), "World"));
}
unsafe {
check_list_2(
3.14 as c_double,
12 as c_long,
b'a' as c_int,
6.28 as c_double,
c"Hello".as_ptr(),
42 as c_int,
c"World".as_ptr(),
);
const {
check_list_2(
3.14 as c_double,
12 as c_long,
b'a' as c_int,
6.28 as c_double,
c"Hello".as_ptr(),
42 as c_int,
c"World".as_ptr(),
)
};
}
}
fn main() {
ignores_arguments();
echo();
forward_by_val();
forward_by_ref();
nested();
various_types();
}