| //@ edition: 2021 | |
| //@ run-pass | |
| //@ ignore-backends: gcc | |
| #![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.next_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.next_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.next_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.next_arg(), ap2.next_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.next_arg::<c_double>().floor() == 3.14f64.floor()); | |
| continue_if!(ap.next_arg::<c_long>() == 12); | |
| continue_if!(ap.next_arg::<c_int>() == 'a' as c_int); | |
| continue_if!(ap.next_arg::<c_double>().floor() == 6.18f64.floor()); | |
| continue_if!(compare_c_str(ap.next_arg::<*const c_char>(), "Hello")); | |
| continue_if!(ap.next_arg::<c_int>() == 42); | |
| continue_if!(compare_c_str(ap.next_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(); | |
| } |