From d76fccc160a0405c9712538a7944570a53b1b60b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 6 Jul 2026 16:26:44 +0100 Subject: [PATCH 1/2] Avoid moves when creating variadic pointer arguments --- .../converter/models/converter_refcount.cpp | 8 ++++- .../out/refcount/va_arg_non_primitive_ptrs.rs | 15 +++++++- tests/unit/out/refcount/va_arg_printf.rs | 35 +++++++++++++++++++ tests/unit/out/unsafe/va_arg_printf.rs | 26 ++++++++++++++ tests/unit/va_arg_printf.c | 11 ++++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index c7a2be2b..abb4424b 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1825,7 +1825,13 @@ bool ConverterRefCount::VisitImplicitValueInitExpr( return Converter::VisitImplicitValueInitExpr(expr); } -void ConverterRefCount::ConvertVariadicArg(clang::Expr *arg) { Convert(arg); } +void ConverterRefCount::ConvertVariadicArg(clang::Expr *arg) { + if (arg->getType()->isPointerType()) { + StrCat(ConvertFreshPointer(arg)); + return; + } + Convert(arg); +} bool ConverterRefCount::VisitVAArgExpr(clang::VAArgExpr *expr) { auto va_list_expr = expr->getSubExpr(); diff --git a/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs b/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs index 836ccef8..7813aa0d 100644 --- a/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs +++ b/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs @@ -11,6 +11,14 @@ pub struct node { pub data: Value, pub next: Value>, } +impl Clone for node { + fn clone(&self) -> Self { + Self { + data: Rc::new(RefCell::new((*self.data.borrow()).clone())), + next: Rc::new(RefCell::new((*self.next.borrow()).clone())), + } + } +} impl ByteRepr for node { fn byte_size() -> usize { 16 @@ -109,7 +117,12 @@ fn main_0() -> i32 { ); assert!((((!((*s.borrow()).is_null())) as i32) != 0)); assert!( - (((({ dispatch_0((opt::OPT_FILE as i32), &[(libcc2rs::cout()).into(),]) }) == 1) as i32) + (((({ + dispatch_0( + (opt::OPT_FILE as i32), + &[((libcc2rs::cout()).clone()).into()], + ) + }) == 1) as i32) != 0) ); assert!( diff --git a/tests/unit/out/refcount/va_arg_printf.rs b/tests/unit/out/refcount/va_arg_printf.rs index 3ebcdadc..cd3d4009 100644 --- a/tests/unit/out/refcount/va_arg_printf.rs +++ b/tests/unit/out/refcount/va_arg_printf.rs @@ -24,6 +24,16 @@ pub fn logf_1(fmt: Ptr, __args: &[VaArg]) -> i32 { )); return (*result.borrow()); } +pub fn lenf_2(fmt: Ptr, __args: &[VaArg]) -> i32 { + let fmt: Value> = Rc::new(RefCell::new(fmt)); + let ap: Value = Rc::new(RefCell::new(VaList::default())); + (*ap.borrow_mut()) = VaList::new(__args); + let s: Value> = Rc::new(RefCell::new(((*ap.borrow_mut()).arg::>()).clone())); + let result: Value = Rc::new(RefCell::new( + ((*s.borrow()).to_string_iterator().count() as i32), + )); + return (*result.borrow()); +} pub fn main() { std::process::exit(main_0()); } @@ -50,5 +60,30 @@ fn main_0() -> i32 { }) == 3) as i32) != 0) ); + assert!( + (((({ + lenf_2( + Ptr::from_string_literal(b"%s"), + &[((*dummy.borrow()).clone()).into()], + ) + }) == 5) as i32) + != 0) + ); + assert!( + (((({ + lenf_2( + Ptr::from_string_literal(b"%s"), + &[ + (if ((((*dummy.borrow()).offset((0) as isize).read()) as i32) != 0) { + (*dummy.borrow()).clone() + } else { + Ptr::from_string_literal(b"") + }) + .into(), + ], + ) + }) == 5) as i32) + != 0) + ); return 0; } diff --git a/tests/unit/out/unsafe/va_arg_printf.rs b/tests/unit/out/unsafe/va_arg_printf.rs index 59f1cfb0..e76041db 100644 --- a/tests/unit/out/unsafe/va_arg_printf.rs +++ b/tests/unit/out/unsafe/va_arg_printf.rs @@ -16,6 +16,13 @@ pub unsafe fn logf_1(mut fmt: *const libc::c_char, __args: &[VaArg]) -> i32 { let mut result: i32 = (unsafe { logf_impl_0(fmt, ap) }); return result; } +pub unsafe fn lenf_2(mut fmt: *const libc::c_char, __args: &[VaArg]) -> i32 { + let mut ap: VaList = VaList::default(); + ap = VaList::new(__args); + let mut s: *const libc::c_char = ap.arg::<*const libc::c_char>(); + let mut result: i32 = (libc::strlen(s) as i32); + return result; +} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -41,5 +48,24 @@ unsafe fn main_0() -> i32 { }) == (3)) as i32) != 0) ); + assert!( + ((((unsafe { lenf_2((c"%s".as_ptr().cast_mut()).cast_const(), &[(dummy).into(),]) }) == (5)) + as i32) + != 0) + ); + assert!( + ((((unsafe { + lenf_2( + (c"%s".as_ptr().cast_mut()).cast_const(), + &[(if (((*dummy.offset((0) as isize)) as i32) != 0) { + dummy + } else { + (c"".as_ptr().cast_mut() as *const libc::c_char) + }) + .into()], + ) + }) == (5)) as i32) + != 0) + ); return 0; } diff --git a/tests/unit/va_arg_printf.c b/tests/unit/va_arg_printf.c index e4a072a7..e4d82531 100644 --- a/tests/unit/va_arg_printf.c +++ b/tests/unit/va_arg_printf.c @@ -15,9 +15,20 @@ int logf(const char *fmt, ...) { return result; } +int lenf(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + const char *s = va_arg(ap, const char *); + int result = (int)strlen(s); + va_end(ap); + return result; +} + int main() { const char *dummy = "dummy"; assert(logf("hello %d %d", 10, strlen(dummy)) == 15); assert(logf("x %d %d", 1, 2) == 3); + assert(lenf("%s", dummy) == 5); + assert(lenf("%s", dummy[0] ? dummy : "") == 5); return 0; } From 715341db3afa5c427a2f2fb615d0becf22d62c1a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Mon, 6 Jul 2026 17:00:43 +0100 Subject: [PATCH 2/2] Update tests --- tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs b/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs index 7813aa0d..d7bb694e 100644 --- a/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs +++ b/tests/unit/out/refcount/va_arg_non_primitive_ptrs.rs @@ -11,14 +11,6 @@ pub struct node { pub data: Value, pub next: Value>, } -impl Clone for node { - fn clone(&self) -> Self { - Self { - data: Rc::new(RefCell::new((*self.data.borrow()).clone())), - next: Rc::new(RefCell::new((*self.next.borrow()).clone())), - } - } -} impl ByteRepr for node { fn byte_size() -> usize { 16