From 5240288ad2f8aaa449de52ebf0ce9dd055867879 Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 19 Nov 2025 16:08:39 +0100 Subject: [PATCH 1/2] transpile: Add support for snapshot tests that are both arch and os specific --- c2rust-transpile/tests/snapshots.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/c2rust-transpile/tests/snapshots.rs b/c2rust-transpile/tests/snapshots.rs index 0d9a59326f..48a7f858b0 100644 --- a/c2rust-transpile/tests/snapshots.rs +++ b/c2rust-transpile/tests/snapshots.rs @@ -166,11 +166,17 @@ fn transpile_all() { #[cfg(target_arch = "aarch64")] let arch = "aarch64"; + let arch_os = format!("{}-{}", arch, os); + insta::with_settings!({snapshot_suffix => os}, { insta::glob!("snapshots/os-specific/*.c", |path| transpile(Some(os), path)); }); insta::with_settings!({snapshot_suffix => arch}, { insta::glob!("snapshots/arch-specific/*.c", |path| transpile(Some(arch), path)); - }) + }); + + insta::with_settings!({snapshot_suffix => arch_os.as_str()}, { + insta::glob!("snapshots/arch-os-specific/*.c", |path| transpile(Some(arch_os.as_str()), path)); + }); } From f84c642b101eddf3834f45a1aef021e308f39c83 Mon Sep 17 00:00:00 2001 From: Rua Date: Wed, 3 Dec 2025 19:04:21 +0100 Subject: [PATCH 2/2] transpile: Add varargs snapshot test --- .../tests/snapshots/arch-os-specific/dummy.c | 0 .../snapshots/arch-os-specific/varargs.c | 114 ++++++++++++++ ...hots__transpile-aarch64-macos@dummy.c.snap | 13 ++ ...ts__transpile-aarch64-macos@varargs.c.snap | 24 +++ ...shots__transpile-x86_64-linux@dummy.c.snap | 13 ++ ...ots__transpile-x86_64-linux@varargs.c.snap | 145 ++++++++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 c2rust-transpile/tests/snapshots/arch-os-specific/dummy.c create mode 100644 c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@dummy.c.snap create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@dummy.c.snap create mode 100644 c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap diff --git a/c2rust-transpile/tests/snapshots/arch-os-specific/dummy.c b/c2rust-transpile/tests/snapshots/arch-os-specific/dummy.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c b/c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c new file mode 100644 index 0000000000..28d092d899 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c @@ -0,0 +1,114 @@ +#include +#include + +// Can we correctly call an extern varargs function +void call_printf(void) { + printf("%d, %f\n", 10, 1.5); +} + +// See #1281. Varargs don't yet work on aarch64. +#ifndef __aarch64__ + +void my_vprintf(const char *format, va_list ap) { + vprintf(format, ap); +} + +void call_vprintf(const char *format, ...) { + va_list ap; + va_start(ap, format); + my_vprintf(format, ap); + va_end(ap); +} + +// Simplified version of printf +void my_printf(const char *fmt, ...) { + va_list ap; + + va_start(ap, fmt); + while (*fmt) { + switch (*fmt) { + case '%': + fmt++; + if (!*fmt) + break; + + switch (*fmt) { + case 'i': + case 'd': + printf("%d", va_arg(ap, int)); + break; + case 'f': + printf("%f", va_arg(ap, double)); + break; + case 's': + printf("%s", va_arg(ap, char*)); + break; + } + + break; + + default: + putchar(*fmt); + break; + } + + fmt++; + } + + va_end(ap); +} + +void simple_vacopy(const char *fmt, ...) { + va_list ap, aq; + + va_start(ap, fmt); + va_copy(aq, ap); + vprintf(fmt, ap); + vprintf(fmt, aq); + va_end(aq); + va_end(ap); +} + +struct vastruct { + va_list args; +}; + +// pattern first seen in apache (util_script.c) +void valist_struct_member(const char *fmt, ...) { + struct vastruct a, b; + + va_start(a.args, fmt); + va_copy(b.args, a.args); + vprintf(fmt, a.args); + vprintf(fmt, b.args); + va_end(a.args); + va_end(b.args); +} + +// pattern first seen in graphviz (sftable.c) +void valist_struct_pointer_member(const char *fmt, ...) { + struct vastruct a, b; + struct vastruct *p = &a, *q = &b; + + va_start(p->args, fmt); + va_copy(q->args, p->args); + vprintf(fmt, p->args); + vprintf(fmt, q->args); + va_end(p->args); + va_end(q->args); +} + +// mirrors pattern from json-c's sprintbuf +void restart_valist(const char *fmt, ...) { + va_list ap; + // start + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + // restart + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); +} + +#endif diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@dummy.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@dummy.c.snap new file mode 100644 index 0000000000..2dceb6c72b --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@dummy.c.snap @@ -0,0 +1,13 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/arch-os-specific/dummy.aarch64-macos.rs +input_file: c2rust-transpile/tests/snapshots/arch-os-specific/dummy.c +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap new file mode 100644 index 0000000000..73201ffa64 --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-aarch64-macos@varargs.c.snap @@ -0,0 +1,24 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/arch-os-specific/varargs.aarch64-macos.rs +input_file: c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +extern "C" { + fn printf(_: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; +} +#[no_mangle] +pub unsafe extern "C" fn call_printf() { + printf( + b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char, + 10 as ::core::ffi::c_int, + 1.5f64, + ); +} diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@dummy.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@dummy.c.snap new file mode 100644 index 0000000000..999c23ecea --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@dummy.c.snap @@ -0,0 +1,13 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/arch-os-specific/dummy.x86_64-linux.rs +input_file: c2rust-transpile/tests/snapshots/arch-os-specific/dummy.c +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] diff --git a/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap new file mode 100644 index 0000000000..3bf7ab88be --- /dev/null +++ b/c2rust-transpile/tests/snapshots/snapshots__transpile-x86_64-linux@varargs.c.snap @@ -0,0 +1,145 @@ +--- +source: c2rust-transpile/tests/snapshots.rs +expression: cat tests/snapshots/arch-os-specific/varargs.x86_64-linux.rs +input_file: c2rust-transpile/tests/snapshots/arch-os-specific/varargs.c +--- +#![allow( + dead_code, + non_camel_case_types, + non_snake_case, + non_upper_case_globals, + unused_assignments, + unused_mut +)] +#![feature(c_variadic)] +extern "C" { + fn printf(__format: *const ::core::ffi::c_char, ...) -> ::core::ffi::c_int; + fn vprintf( + __format: *const ::core::ffi::c_char, + __arg: ::core::ffi::VaList, + ) -> ::core::ffi::c_int; + fn putchar(__c: ::core::ffi::c_int) -> ::core::ffi::c_int; +} +pub type __builtin_va_list = [__va_list_tag; 1]; +#[derive(Copy, Clone)] +#[repr(C)] +pub struct __va_list_tag { + pub gp_offset: ::core::ffi::c_uint, + pub fp_offset: ::core::ffi::c_uint, + pub overflow_arg_area: *mut ::core::ffi::c_void, + pub reg_save_area: *mut ::core::ffi::c_void, +} +pub type va_list = __builtin_va_list; +#[derive()] +#[repr(C)] +pub struct vastruct<'a> { + pub args: ::core::ffi::VaListImpl<'a>, +} +#[no_mangle] +pub unsafe extern "C" fn call_printf() { + printf( + b"%d, %f\n\0" as *const u8 as *const ::core::ffi::c_char, + 10 as ::core::ffi::c_int, + 1.5f64, + ); +} +#[no_mangle] +pub unsafe extern "C" fn my_vprintf( + mut format: *const ::core::ffi::c_char, + mut ap: ::core::ffi::VaList, +) { + vprintf(format, ap.as_va_list() as ::core::ffi::VaList); +} +#[no_mangle] +pub unsafe extern "C" fn call_vprintf(mut format: *const ::core::ffi::c_char, mut args: ...) { + let mut ap: ::core::ffi::VaListImpl; + ap = args.clone(); + my_vprintf(format, ap.as_va_list()); +} +#[no_mangle] +pub unsafe extern "C" fn my_printf(mut fmt: *const ::core::ffi::c_char, mut args: ...) { + let mut ap: ::core::ffi::VaListImpl; + ap = args.clone(); + while *fmt != 0 { + match *fmt as ::core::ffi::c_int { + 37 => { + fmt = fmt.offset(1); + if !(*fmt == 0) { + match *fmt as ::core::ffi::c_int { + 105 | 100 => { + printf( + b"%d\0" as *const u8 as *const ::core::ffi::c_char, + ap.arg::<::core::ffi::c_int>(), + ); + } + 102 => { + printf( + b"%f\0" as *const u8 as *const ::core::ffi::c_char, + ap.arg::<::core::ffi::c_double>(), + ); + } + 115 => { + printf( + b"%s\0" as *const u8 as *const ::core::ffi::c_char, + ap.arg::<*mut ::core::ffi::c_char>(), + ); + } + _ => {} + } + } + } + _ => { + putchar(*fmt as ::core::ffi::c_int); + } + } + fmt = fmt.offset(1); + } +} +#[no_mangle] +pub unsafe extern "C" fn simple_vacopy(mut fmt: *const ::core::ffi::c_char, mut args: ...) { + let mut ap: ::core::ffi::VaListImpl; + let mut aq: ::core::ffi::VaListImpl; + ap = args.clone(); + aq = ap.clone(); + vprintf(fmt, ap.as_va_list()); + vprintf(fmt, aq.as_va_list()); +} +#[no_mangle] +pub unsafe extern "C" fn valist_struct_member(mut fmt: *const ::core::ffi::c_char, mut args: ...) { + let mut a: vastruct = vastruct { + args: ::core::mem::MaybeUninit::uninit().assume_init(), + }; + let mut b: vastruct = vastruct { + args: ::core::mem::MaybeUninit::uninit().assume_init(), + }; + a.args = args.clone(); + b.args = a.args.clone(); + vprintf(fmt, a.args.as_va_list()); + vprintf(fmt, b.args.as_va_list()); +} +#[no_mangle] +pub unsafe extern "C" fn valist_struct_pointer_member( + mut fmt: *const ::core::ffi::c_char, + mut args: ... +) { + let mut a: vastruct = vastruct { + args: ::core::mem::MaybeUninit::uninit().assume_init(), + }; + let mut b: vastruct = vastruct { + args: ::core::mem::MaybeUninit::uninit().assume_init(), + }; + let mut p: *mut vastruct = &mut a; + let mut q: *mut vastruct = &mut b; + (*p).args = args.clone(); + (*q).args = (*p).args.clone(); + vprintf(fmt, (*p).args.as_va_list()); + vprintf(fmt, (*q).args.as_va_list()); +} +#[no_mangle] +pub unsafe extern "C" fn restart_valist(mut fmt: *const ::core::ffi::c_char, mut args: ...) { + let mut ap: ::core::ffi::VaListImpl; + ap = args.clone(); + vprintf(fmt, ap.as_va_list()); + ap = args.clone(); + vprintf(fmt, ap.as_va_list()); +}