about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFolkert de Vries <folkert@folkertdev.nl>2025-07-03 20:39:32 +0200
committerFolkert de Vries <folkert@folkertdev.nl>2025-07-04 17:27:24 +0200
commita3277a1bbb82423416a716b13c483a13e00aef59 (patch)
tree8cbe361ed970bdd7ef60e4c241cf1e7402ba08b5
parent6268d0aa34b46981533b09827c1454b8cf27e032 (diff)
downloadrust-a3277a1bbb82423416a716b13c483a13e00aef59.tar.gz
rust-a3277a1bbb82423416a716b13c483a13e00aef59.zip
test rust calling a C C-variadic function
-rw-r--r--tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs62
-rw-r--r--tests/run-make/c-link-to-rust-va-list-fn/test.c53
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 36c9db106ec..63d8d713d62 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::<c_longlong>() == 1);
     continue_if!(ap.arg::<c_int>() == 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::<c_int>() == -1);
     continue_if!(ap.arg::<c_int>() == '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::<c_double>().floor() == 3.14f64.floor());
     continue_if!(ap.arg::<c_long>() == 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::<c_double>().floor() == 6.28f64.floor());
     continue_if!(ap.arg::<c_int>() == 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::<c_int>() == 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::<c_double>().floor() == 3.14f64.floor());
     continue_if!(ap.arg::<c_long>() == 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::<c_int>() == 1);
     continue_if!(ap.arg::<c_int>() == 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::<c_double>() == 1.0);
     continue_if!(ap.arg::<c_double>() == 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::<c_double>() == 1.0);
     continue_if!(ap.arg::<c_int>() == 1);
@@ -148,3 +149,42 @@ pub unsafe extern "C" fn check_varargs_5(_: c_int, mut ap: ...) -> usize {
     continue_if!(ap.arg::<c_double>() == 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 b47a9357880..2bb93c0b5d0 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;
 }