155 lines
3.6 KiB
Rust
155 lines
3.6 KiB
Rust
//@ 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();
|
|
}
|