From a3277a1bbb82423416a716b13c483a13e00aef59 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Thu, 3 Jul 2025 20:39:32 +0200 Subject: [PATCH] test rust calling a C C-variadic function --- .../c-link-to-rust-va-list-fn/checkrust.rs | 62 +++++++++++++++---- .../run-make/c-link-to-rust-va-list-fn/test.c | 53 ++++++++++++++++ 2 files changed, 104 insertions(+), 11 deletions(-) diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs index 36c9db106ec45..63d8d713d6226 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs +++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs @@ -1,7 +1,8 @@ #![crate_type = "staticlib"] #![feature(c_variadic)] +#![feature(cfg_select)] -use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong}; +use std::ffi::{CStr, CString, VaList, VaListImpl, c_char, c_double, c_int, c_long, c_longlong}; macro_rules! continue_if { ($cond:expr) => { @@ -19,7 +20,7 @@ unsafe fn compare_c_str(ptr: *const c_char, val: &str) -> bool { } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -27,7 +28,7 @@ pub unsafe extern "C" fn check_list_0(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { continue_if!(ap.arg::() == -1); continue_if!(ap.arg::() == 'A' as c_int); @@ -39,7 +40,7 @@ pub unsafe extern "C" fn check_list_1(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -51,7 +52,7 @@ pub unsafe extern "C" fn check_list_2(mut ap: VaList) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { continue_if!(ap.arg::().floor() == 6.28f64.floor()); continue_if!(ap.arg::() == 16); @@ -64,14 +65,14 @@ pub unsafe extern "C" fn check_list_copy_0(mut ap: VaList) -> usize { ) } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_0(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 42); continue_if!(compare_c_str(ap.arg::<*const c_char>(), "Hello, World!")); 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::().floor() == 3.14f64.floor()); continue_if!(ap.arg::() == 12); @@ -80,12 +81,12 @@ pub unsafe extern "C" fn check_varargs_1(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_2(_: c_int, _ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1); continue_if!(ap.arg::() == 2); @@ -100,7 +101,7 @@ pub unsafe extern "C" fn check_varargs_3(_: c_int, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 2.0); @@ -118,7 +119,7 @@ pub unsafe extern "C" fn check_varargs_4(_: c_double, mut ap: ...) -> usize { 0 } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 1.0); continue_if!(ap.arg::() == 1); @@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize { continue_if!(ap.arg::() == 13.0); 0 } + +unsafe extern "C" { + fn test_variadic(_: c_int, ...) -> usize; + fn test_va_list_by_value(_: VaList) -> usize; + fn test_va_list_by_pointer(_: *mut VaListImpl) -> usize; + fn test_va_list_by_pointer_pointer(_: *mut *mut VaListImpl) -> usize; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_variadic() -> usize { + return unsafe { test_variadic(0, 1 as c_longlong, 2 as c_int, 3 as c_longlong) }; +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_value() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_value(ap.as_va_list()) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer(&mut ap) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} + +#[unsafe(no_mangle)] +extern "C" fn run_test_va_list_by_pointer_pointer() -> usize { + unsafe extern "C" fn helper(mut ap: ...) -> usize { + unsafe { test_va_list_by_pointer_pointer(&mut (&mut ap as *mut _)) } + } + + unsafe { helper(1 as c_longlong, 2 as c_int, 3 as c_longlong) } +} diff --git a/tests/run-make/c-link-to-rust-va-list-fn/test.c b/tests/run-make/c-link-to-rust-va-list-fn/test.c index b47a9357880f1..2bb93c0b5d0ef 100644 --- a/tests/run-make/c-link-to-rust-va-list-fn/test.c +++ b/tests/run-make/c-link-to-rust-va-list-fn/test.c @@ -15,6 +15,11 @@ extern size_t check_varargs_3(int fixed, ...); extern size_t check_varargs_4(double fixed, ...); extern size_t check_varargs_5(int fixed, ...); +extern size_t run_test_variadic(); +extern size_t run_test_va_list_by_value(); +extern size_t run_test_va_list_by_pointer(); +extern size_t run_test_va_list_by_pointer_pointer(); + int test_rust(size_t (*fn)(va_list), ...) { size_t ret = 0; va_list ap; @@ -47,5 +52,53 @@ int main(int argc, char* argv[]) { assert(check_varargs_5(0, 1.0, 1, 2.0, 2, 3.0, 3, 4.0, 4, 5, 5.0, 6, 6.0, 7, 7.0, 8, 8.0, 9, 9.0, 10, 10.0, 11, 11.0, 12, 12.0, 13, 13.0) == 0); + assert(run_test_variadic() == 0); + assert(run_test_va_list_by_value() == 0); + assert(run_test_va_list_by_pointer() == 0); + assert(run_test_va_list_by_pointer_pointer() == 0); + + return 0; +} + +#define continue_if_else_end(cond) \ + do { if (!(cond)) { va_end(ap); return 0xff; } } while (0) + +size_t test_variadic(int unused, ...) { + va_list ap; + va_start(ap, unused); + + continue_if_else_end(va_arg(ap, long long) == 1); + continue_if_else_end(va_arg(ap, int) == 2); + continue_if_else_end(va_arg(ap, long long) == 3); + + va_end(ap); + + return 0; +} + +#define continue_if(cond) \ + do { if (!(cond)) { return 0xff; } } while (0) + +size_t test_va_list_by_value(va_list ap) { + continue_if(va_arg(ap, long long) == 1); + continue_if(va_arg(ap, int) == 2); + continue_if(va_arg(ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer(va_list *ap) { + continue_if(va_arg(*ap, long long) == 1); + continue_if(va_arg(*ap, int) == 2); + continue_if(va_arg(*ap, long long) == 3); + + return 0; +} + +size_t test_va_list_by_pointer_pointer(va_list **ap) { + continue_if(va_arg(**ap, long long) == 1); + continue_if(va_arg(**ap, int) == 2); + continue_if(va_arg(**ap, long long) == 3); + return 0; }