From a18b0586713da7bd6d841402f330d1f6d0752019 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:40:44 +0100 Subject: [PATCH 01/43] Add Callable trait --- libcc2rs/src/callable.rs | 52 ++++++++++++++++++++++++++++++++++++++++ libcc2rs/src/lib.rs | 3 +++ 2 files changed, 55 insertions(+) create mode 100644 libcc2rs/src/callable.rs diff --git a/libcc2rs/src/callable.rs b/libcc2rs/src/callable.rs new file mode 100644 index 00000000..747277d0 --- /dev/null +++ b/libcc2rs/src/callable.rs @@ -0,0 +1,52 @@ +// Copyright (c) 2022-present INESC-ID. +// Distributed under the MIT license that can be found in the LICENSE file. + +macro_rules! callable { + ($name:ident; $($a:ident: $A:ident),*) => { + pub trait $name<$($A,)* R> { + fn call(&self, $($a: $A),*) -> R; + } + + impl $name<$($A,)* R> for F + where + F: Fn($($A),*) -> R, + { + #[inline] + fn call(&self, $($a: $A),*) -> R { + self($($a),*) + } + } + + impl $name<$($A,)* R> for Option + where + F: Fn($($A),*) -> R, + { + #[inline] + fn call(&self, $($a: $A),*) -> R { + self.as_ref().unwrap()($($a),*) + } + } + + impl<$($A,)* R> $name<$($A,)* R> for Option R> { + #[inline] + fn call(&self, $($a: $A),*) -> R { + unsafe { self.unwrap()($($a),*) } + } + } + + impl $name<$($A,)* R> for crate::fn_ptr::FnPtr + where + F: Fn($($A),*) -> R + 'static, + { + #[inline] + fn call(&self, $($a: $A),*) -> R { + (**self)($($a),*) + } + } + }; +} + +callable!(Callable0;); +callable!(Callable1; a1: A1); +callable!(Callable2; a1: A1, a2: A2); +callable!(Callable3; a1: A1, a2: A2, a3: A3); diff --git a/libcc2rs/src/lib.rs b/libcc2rs/src/lib.rs index fb1f9be0..06b1e779 100644 --- a/libcc2rs/src/lib.rs +++ b/libcc2rs/src/lib.rs @@ -21,6 +21,9 @@ pub use libc_shims::*; mod fn_ptr; pub use fn_ptr::FnPtr; +mod callable; +pub use callable::*; + mod inc; pub use inc::*; From f9f5fd75eef9a9b0f21424eb709c6f3b92afd11f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:42:43 +0100 Subject: [PATCH 02/43] Deduplicate rules using the Callable trait --- rules/algorithm/src.cpp | 19 ++----------- rules/algorithm/tgt_refcount.rs | 23 +++------------- rules/algorithm/tgt_unsafe.rs | 49 ++++++--------------------------- rules/cstdlib/tgt_refcount.rs | 14 +++++++--- rules/cstdlib/tgt_unsafe.rs | 24 +++++++++------- rules/rustls/tgt_unsafe.rs | 34 ++++++++++++++--------- 6 files changed, 61 insertions(+), 102 deletions(-) diff --git a/rules/algorithm/src.cpp b/rules/algorithm/src.cpp index 097b05cb..0d2946cd 100644 --- a/rules/algorithm/src.cpp +++ b/rules/algorithm/src.cpp @@ -9,6 +9,7 @@ struct T2 { friend bool operator<(T2 a, T2 b) { return false; } + bool operator()(const T2 &, const T2 &) const; }; struct T1 { @@ -91,14 +92,7 @@ template T1 f3(T1 first, T1 last, const T2 &value) { return std::find(first, last, value); } -// TODO -auto lambda = [](const T2 &a, const T2 &b) { return false; }; -void f6(T1 first, T1 last, decltype(lambda) comp) { - return std::stable_sort(first, last, comp); -} - -template -void f7(T1 first, T1 last, bool (*comp)(const T2 &, const T2 &)) { +void f6(T1 first, T1 last, T2 comp) { return std::stable_sort(first, last, comp); } @@ -126,14 +120,7 @@ std::ostream_iterator f13(std::string::iterator a0, return std::copy(a0, a1, a2); } -// TODO -auto lambda_nref = [](T2 a, T2 b) { return false; }; -void f14(T1 *first, T1 *last, decltype(lambda_nref) comp) { - return std::stable_sort(first, last, comp); -} - -template -void f15(T1 *first, T1 *last, bool (*comp)(T2, T2)) { +void f14(T1 *first, T1 *last, T2 comp) { return std::stable_sort(first, last, comp); } diff --git a/rules/algorithm/tgt_refcount.rs b/rules/algorithm/tgt_refcount.rs index 74866b39..66b8a801 100644 --- a/rules/algorithm/tgt_refcount.rs +++ b/rules/algorithm/tgt_refcount.rs @@ -38,16 +38,9 @@ fn f3(a0: Ptr, a1: Ptr, a2: T1) -> Ptr fn f6(a0: Ptr, a1: Ptr, a2: T2) where - T2: FnMut(Ptr, Ptr) -> bool, + T2: Callable2, Ptr, bool>, { - a0.sort_with_cmp(a1.get_offset(), a2) -} - -fn f7(a0: Ptr, a1: Ptr, a2: T2) -where - T2: FnMut(Ptr, Ptr) -> bool, -{ - a0.sort_with_cmp(a1.get_offset(), a2) + a0.sort_with_cmp(a1.get_offset(), |x, y| a2.call(x, y)) } fn f8(a0: Ptr, a1: Ptr) -> Ptr { @@ -109,17 +102,9 @@ fn f13(a0: Ptr, a1: Ptr, a2: &mut ::std::fs::File) -> ::std::fs::File { fn f14(a0: Ptr, a1: Ptr, a2: T2) where - T2: Fn(T1, T1) -> bool, -{ - let fun = |x: Ptr, y: Ptr| a2((x.read()).clone(), (y.read()).clone()); - a0.sort_with_cmp(a1.get_offset(), fun) -} - -fn f15(a0: Ptr, a1: Ptr, a2: T2) -where - T2: Fn(T1, T1) -> bool, + T2: Callable2, { - let fun = |x: Ptr, y: Ptr| a2((x.read()).clone(), (y.read()).clone()); + let fun = |x: Ptr, y: Ptr| a2.call((x.read()).clone(), (y.read()).clone()); a0.sort_with_cmp(a1.get_offset(), fun) } diff --git a/rules/algorithm/tgt_unsafe.rs b/rules/algorithm/tgt_unsafe.rs index 101a2060..dbf6650e 100644 --- a/rules/algorithm/tgt_unsafe.rs +++ b/rules/algorithm/tgt_unsafe.rs @@ -1,6 +1,7 @@ // Copyright (c) 2022-present INESC-ID. // Distributed under the MIT license that can be found in the LICENSE file. +use libcc2rs::*; use std::io::{Seek, Write}; unsafe fn f1(a0: *mut T1, a1: *mut T1) { @@ -27,31 +28,15 @@ unsafe fn f3(a0: *mut T1, a1: *mut T1, a2: T1) -> *mut T1 { it } -unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(&T1, &T1) -> bool, + T2: Callable2<*const T1, *const T1, bool>, { let len = a1.offset_from(a0) as usize; ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(x, y) { + if a2.call(x as *const _, y as *const _) { std::cmp::Ordering::Less - } else if (a2)(y, x) { - std::cmp::Ordering::Greater - } else { - std::cmp::Ordering::Equal - } - }) -} - -unsafe fn f7(a0: *mut T1, a1: *mut T1, a2: &mut T2) -where - T2: FnMut(&T1, &T1) -> bool, -{ - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(x, y) { - std::cmp::Ordering::Less - } else if (a2)(y, x) { + } else if a2.call(y as *const _, x as *const _) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -113,31 +98,15 @@ unsafe fn f13( a2.try_clone().unwrap() } -unsafe fn f14(a0: *mut T1, a1: *mut T1, a2: &mut T2) -where - T2: FnMut(T1, T1) -> bool, -{ - let len = a1.offset_from(a0) as usize; - ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(*x, *y) { - std::cmp::Ordering::Less - } else if (a2)(*y, *x) { - std::cmp::Ordering::Greater - } else { - std::cmp::Ordering::Equal - } - }) -} - -unsafe fn f15(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f14(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(T1, T1) -> bool, + T2: Callable2, { let len = a1.offset_from(a0) as usize; ::std::slice::from_raw_parts_mut(a0, len).sort_by(|x, y| { - if (a2)(*x, *y) { + if a2.call(*x, *y) { std::cmp::Ordering::Less - } else if (a2)(*y, *x) { + } else if a2.call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal diff --git a/rules/cstdlib/tgt_refcount.rs b/rules/cstdlib/tgt_refcount.rs index 534d4472..db6d8d7d 100644 --- a/rules/cstdlib/tgt_refcount.rs +++ b/rules/cstdlib/tgt_refcount.rs @@ -50,7 +50,13 @@ fn f10(a0: Ptr, a1: Ptr) -> Ptr { } } -fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i32) -> AnyPtr { +fn f8( + a0: AnyPtr, + a1: AnyPtr, + a2: usize, + a3: usize, + a4: FnPtr i32>, +) -> AnyPtr { let __base = a1.reinterpret_cast::(); let mut __lo: isize = 0; let mut __hi: isize = a2 as isize - 1; @@ -58,7 +64,7 @@ fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i3 while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * a3); - let __r = a4(a0.clone(), __elem.to_any()); + let __r = a4.call(a0.clone(), __elem.to_any()); if __r == 0 { __found = __elem.to_any(); } else if __r < 0 { @@ -70,12 +76,12 @@ fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i3 __found } -fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: fn(AnyPtr, AnyPtr) -> i32) { +fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: FnPtr i32>) { let __base = a0.reinterpret_cast::(); for __i in 0..a1 { let mut __min = __i; for __j in (__i + 1)..a1 { - if a3( + if a3.call( __base.offset(__j * a2).to_any(), __base.offset(__min * a2).to_any(), ) < 0 diff --git a/rules/cstdlib/tgt_unsafe.rs b/rules/cstdlib/tgt_unsafe.rs index 5b983c43..9d0d0327 100644 --- a/rules/cstdlib/tgt_unsafe.rs +++ b/rules/cstdlib/tgt_unsafe.rs @@ -34,17 +34,19 @@ unsafe fn f8( a1: *const ::libc::c_void, a2: usize, a3: usize, - a4: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + a4: Option i32>, ) -> *mut ::libc::c_void { libc::bsearch( a0, a1, a2, a3, - Some(std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(a4 as *const ())), + a4.map(|__f| { + std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(__f as *const ()) + }), ) } @@ -52,16 +54,18 @@ unsafe fn f9( a0: *mut ::libc::c_void, a1: usize, a2: usize, - a3: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + a3: Option i32>, ) { libc::qsort( a0, a1, a2, - Some(std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(a3 as *const ())), + a3.map(|__f| { + std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(__f as *const ()) + }), ) } diff --git a/rules/rustls/tgt_unsafe.rs b/rules/rustls/tgt_unsafe.rs index db78cc47..59c3d3f1 100644 --- a/rules/rustls/tgt_unsafe.rs +++ b/rules/rustls/tgt_unsafe.rs @@ -433,13 +433,15 @@ unsafe fn f57(a0: u32) -> bool { unsafe fn f58( a0: *mut ::rustls_ffi::connection::rustls_connection, - a1: unsafe fn(*mut ::libc::c_void, *mut u8, u64, *mut u64) -> i32, + a1: Option i32>, a2: *mut ::libc::c_void, a3: *mut u64, ) -> i32 { ::rustls_ffi::connection::rustls_connection::rustls_connection_read_tls( a0, - std::mem::transmute::<*const (), ::rustls_ffi::io::rustls_read_callback>(a1 as *const ()), + std::mem::transmute::( + a1.map_or(0_usize, |__f| __f as usize), + ), a2, a3 as *mut usize, ) @@ -447,13 +449,15 @@ unsafe fn f58( } unsafe fn f59( a0: *mut ::rustls_ffi::connection::rustls_connection, - a1: unsafe fn(*mut ::libc::c_void, *const u8, u64, *mut u64) -> i32, + a1: Option i32>, a2: *mut ::libc::c_void, a3: *mut u64, ) -> i32 { ::rustls_ffi::connection::rustls_connection::rustls_connection_write_tls( a0, - std::mem::transmute::<*const (), ::rustls_ffi::io::rustls_write_callback>(a1 as *const ()), + std::mem::transmute::( + a1.map_or(0_usize, |__f| __f as usize), + ), a2, a3 as *mut usize, ) @@ -461,13 +465,15 @@ unsafe fn f59( } unsafe fn f60( a0: *mut ::rustls_ffi::client::rustls_client_config_builder, - a1: unsafe fn(::rustls_ffi::rslice::rustls_str<'static>, *const u8, u64, *const u8, u64), + a1: Option< + unsafe fn(::rustls_ffi::rslice::rustls_str<'static>, *const u8, u64, *const u8, u64), + >, a2: Option) -> i32>, ) -> ::rustls_ffi::rustls_result { ::rustls_ffi::client::rustls_client_config_builder::rustls_client_config_builder_set_key_log( a0, - std::mem::transmute::<*const (), ::rustls_ffi::keylog::rustls_keylog_log_callback>( - a1 as *const (), + std::mem::transmute::( + a1.map_or(0_usize, |__f| __f as usize), ), std::mem::transmute::< Option) -> i32>, @@ -477,15 +483,17 @@ unsafe fn f60( } unsafe fn f61( a0: *mut ::rustls_ffi::client::rustls_client_config_builder, - a1: unsafe fn( - *mut ::libc::c_void, - *const ::rustls_ffi::client::rustls_verify_server_cert_params<'static>, - ) -> ::rustls_ffi::rustls_result, + a1: Option< + unsafe fn( + *mut ::libc::c_void, + *const ::rustls_ffi::client::rustls_verify_server_cert_params<'static>, + ) -> ::rustls_ffi::rustls_result, + >, ) -> ::rustls_ffi::rustls_result { ::rustls_ffi::client::rustls_client_config_builder::rustls_client_config_builder_dangerous_set_certificate_verifier( a0, - std::mem::transmute::<*const (), ::rustls_ffi::client::rustls_verify_server_cert_callback>( - a1 as *const (), + std::mem::transmute::( + a1.map_or(0_usize, |__f| __f as usize), ), ) } From 3a7cbc4ea48f364b4826062c9c487449cb79d8dc Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:44:15 +0100 Subject: [PATCH 03/43] Use fully qualified syntax for FnPtr::new --- cpp2rust/converter/models/converter_refcount.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 8b6b7a19..e63e34be 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2085,9 +2085,13 @@ std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type, Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - StrCat("FnPtr::new("); + auto proto = lambda->getCallOperator() + ->getType() + ->getAs(); + StrCat( + std::format("FnPtr::<{}>::new", ConvertFunctionPointerType(proto))); + PushParen paren(*this); VisitLambdaExpr(lambda); - StrCat(')'); } else { VisitLambdaExpr(lambda); } From 8d5f2d12247f076745915055c4f93a6bbc0463b6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:44:42 +0100 Subject: [PATCH 04/43] Map types lazily --- cpp2rust/converter/mapper.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 4def2784..b5ad34e4 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -682,10 +682,9 @@ std::string InstantiateTemplate(const clang::Expr *expr, unsigned n) { if (!rule) { return text; } - for (auto &ty : subs) { - if (ty) { - ty = mapTypeStringRecursive(*ty); - } + auto &ty = subs.at(n - 1); + if (ty) { + ty = mapTypeStringRecursive(*ty); } return instantiateTgt(subs, text); } From 6eeeeb71ff7367ca6c34a3c8bbfbc27f60573801 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:45:22 +0100 Subject: [PATCH 05/43] Convert casted type lazily --- cpp2rust/converter/converter.cpp | 14 ++++++++------ cpp2rust/converter/converter.h | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 99d7b036..a4aaa2ba 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -4607,7 +4607,7 @@ void Converter::PlaceholderCtx::dump() const { << ", declared_in_rule_as_rust_ptr: " << declared_in_rule_as_rust_ptr << ", access: " << static_cast(access) - << ", param_type: " << param_type + << ", arg_idx: " << arg_idx << ", materialize_idx: " << materialize_idx << '\n'; } @@ -4621,8 +4621,9 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, } if (ph_ctx.declared_in_rule_as_rust_ptr && arg->getType()->isArrayType()) { - return std::format("({} as {})", ConvertFreshPointer(arg), - ph_ctx.param_type); + return std::format( + "({} as {})", ConvertFreshPointer(arg), + Mapper::GetParamType(GetCalleeOrExpr(expr), ph_ctx.arg_idx)); } if (ph_ctx.needs_materialization()) { @@ -4637,8 +4638,9 @@ std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, } if (ph_ctx.needs_pointer_receiver()) { - return std::format("({} as {})", ConvertFreshObject(arg), - ph_ctx.param_type); + return std::format( + "({} as {})", ConvertFreshObject(arg), + Mapper::GetParamType(GetCalleeOrExpr(expr), ph_ctx.arg_idx)); } if (ph_ctx.needs_object_receiver()) { @@ -4717,7 +4719,7 @@ std::string Converter::ConvertIRFragment( bool is_receiver = HasReceiver(expr) && arg_idx == 0; PlaceholderCtx ph_ctx{ - .param_type = Mapper::GetParamType(GetCalleeOrExpr(expr), arg_idx), + .arg_idx = arg_idx, .implicit_convert_to = GetParamImplicitConvertTarget(expr, arg_idx), .materialize_ctx = ctx, .materialize_idx = diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 6a4996cf..d735f75f 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -221,7 +221,7 @@ class Converter : public clang::RecursiveASTVisitor { }; struct PlaceholderCtx { - std::string param_type; + unsigned arg_idx; std::optional implicit_convert_to; TempMaterializationCtx *materialize_ctx; int materialize_idx; // <0 = no idx, >=0 idx valid From 2b7394a67559f78c2c4cb134097f5c06e68620d3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 13:48:51 +0100 Subject: [PATCH 06/43] Pass nullable function to rules --- cpp2rust/converter/converter.cpp | 55 +++++++++++++++++++------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index a4aaa2ba..e9559524 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1812,7 +1812,9 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) { void Converter::ConvertFunctionToFunctionPointer( const clang::FunctionDecl *fn_decl) { - StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl))); + auto proto = fn_decl->getType()->getAs(); + StrCat(std::format("Some({} as {} {})", Mapper::MapFunctionName(fn_decl), + keyword_unsafe_, ConvertFunctionPointerType(proto))); computed_expr_type_ = ComputedExprType::FreshPointer; } @@ -2407,6 +2409,12 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { computed_expr_type_ = ComputedExprType::FreshPointer; break; default: + if (type->isFunctionPointerType() && + clang::isa( + sub_expr->IgnoreUnlessSpelledInSource())) { + ConvertVarInit(type, sub_expr); + break; + } if (auto *literal = clang::dyn_cast(sub_expr)) { auto type = expr->getType(); StrCat(getIntegerLiteral(literal, true, &type)); @@ -3589,21 +3597,31 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { } bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { - if (isAddrOf() && expr->capture_size() == 0) { - StrCat("Some"); + bool to_fn_ptr = isAddrOf() && expr->capture_size() == 0; + if (to_fn_ptr) { + StrCat("Some("); + } + { + PushParen paren(*this); + StrCat('|'); + for (auto p : + expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { + StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), + token::kComma); + } + StrCat("| {"); + EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); + PushCurrFunction push_fn(*this, + expr->getLambdaClass()->getLambdaCallOperator()); + ConvertFunctionBody(curr_function_); + StrCat('}'); + } + if (to_fn_ptr) { + auto proto = + expr->getCallOperator()->getType()->getAs(); + StrCat(std::format(" as {} {})", keyword_unsafe_, + ConvertFunctionPointerType(proto))); } - PushParen paren(*this); - StrCat('|'); - for (auto p : expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { - StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), - token::kComma); - } - StrCat("| {"); - EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); - PushCurrFunction push_fn(*this, - expr->getLambdaClass()->getLambdaCallOperator()); - ConvertFunctionBody(curr_function_); - StrCat('}'); return false; } @@ -4613,13 +4631,6 @@ void Converter::PlaceholderCtx::dump() const { std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, const PlaceholderCtx &ph_ctx) { - if (arg->getType()->isFunctionPointerType()) { - PushExprKind push(*this, ExprKind::Callee); - Buffer buf(*this); - Convert(arg); - return std::move(buf).str(); - } - if (ph_ctx.declared_in_rule_as_rust_ptr && arg->getType()->isArrayType()) { return std::format( "({} as {})", ConvertFreshPointer(arg), From 2bc199ea4cedd2a3d916e468bfa192512130c220 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 14:09:53 +0100 Subject: [PATCH 07/43] Update tests --- tests/unit/out/refcount/fn_ptr_default_arg.rs | 2 +- tests/unit/out/refcount/fn_ptr_stable_sort.rs | 2 +- tests/unit/out/refcount/qsort_bsearch.rs | 6 +-- tests/unit/out/refcount/stable_sort.rs | 3 +- tests/unit/out/unsafe/fn_ptr.rs | 6 +-- tests/unit/out/unsafe/fn_ptr_arity.rs | 20 +++++++- tests/unit/out/unsafe/fn_ptr_array.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_as_condition.rs | 9 +++- tests/unit/out/unsafe/fn_ptr_cast.rs | 15 +++--- tests/unit/out/unsafe/fn_ptr_conditional.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_global.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_reassign.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_return.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_stable_sort.rs | 8 +++- .../unit/out/unsafe/fn_ptr_stdlib_compare.rs | 46 +++++++++++++++---- tests/unit/out/unsafe/fn_ptr_struct.rs | 6 +-- tests/unit/out/unsafe/fn_ptr_void_return.rs | 11 +++-- tests/unit/out/unsafe/fn_ptr_vtable.rs | 6 +-- tests/unit/out/unsafe/malloc_realloc_free.rs | 12 +++-- tests/unit/out/unsafe/no_direct_callee.rs | 2 +- tests/unit/out/unsafe/qsort_bsearch.rs | 36 ++++++++++----- tests/unit/out/unsafe/stable_sort.rs | 6 ++- .../out/unsafe/string_literal_ptr_init.rs | 2 +- tests/unit/out/unsafe/va_arg_fn_ptr.rs | 23 ++++------ tests/unit/out/unsafe/void_cast.rs | 4 +- 26 files changed, 181 insertions(+), 98 deletions(-) diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 0348fc82..4a0d282c 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,7 +26,7 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( + let negate: Value i32>> = Rc::new(RefCell::new(FnPtr:: i32>::new( (|x: i32| { let x: Value = Rc::new(RefCell::new(x)); return -(*x.borrow()); diff --git a/tests/unit/out/refcount/fn_ptr_stable_sort.rs b/tests/unit/out/refcount/fn_ptr_stable_sort.rs index be45ffe6..d294121b 100644 --- a/tests/unit/out/refcount/fn_ptr_stable_sort.rs +++ b/tests/unit/out/refcount/fn_ptr_stable_sort.rs @@ -61,7 +61,7 @@ fn main_0() -> i32 { }); (v.as_pointer() as Ptr).sort_with_cmp( (v.as_pointer() as Ptr).to_end().get_offset(), - Compare_0, + |x, y| FnPtr::, Ptr) -> bool>::new(Compare_0).call(x, y), ); assert!( ((*(*(v.as_pointer() as Ptr) diff --git a/tests/unit/out/refcount/qsort_bsearch.rs b/tests/unit/out/refcount/qsort_bsearch.rs index d53ecb1d..c200ac0c 100644 --- a/tests/unit/out/refcount/qsort_bsearch.rs +++ b/tests/unit/out/refcount/qsort_bsearch.rs @@ -29,7 +29,7 @@ fn main_0() -> i32 { for __i in 0..8_usize { let mut __min = __i; for __j in (__i + 1)..8_usize { - if cmp_int_0( + if FnPtr:: i32>::new(cmp_int_0).call( __base.offset(__j * ::std::mem::size_of::()).to_any(), __base.offset(__min * ::std::mem::size_of::()).to_any(), ) < 0 @@ -76,7 +76,7 @@ fn main_0() -> i32 { while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); - let __r = cmp_int_0( + let __r = FnPtr:: i32>::new(cmp_int_0).call( ((key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); @@ -106,7 +106,7 @@ fn main_0() -> i32 { while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); - let __r = cmp_int_0( + let __r = FnPtr:: i32>::new(cmp_int_0).call( ((miss_key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 5da4a391..784fbf00 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -17,7 +17,8 @@ fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(x)); let y: Value = Rc::new(RefCell::new(y)); return ((*x.borrow()) < (*y.borrow())); - })((x.read()).clone(), (y.read()).clone()) + }) + .call((x.read()).clone(), (y.read()).clone()) }; (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) diff --git a/tests/unit/out/unsafe/fn_ptr.rs b/tests/unit/out/unsafe/fn_ptr.rs index dcaacdaf..6faa1392 100644 --- a/tests/unit/out/unsafe/fn_ptr.rs +++ b/tests/unit/out/unsafe/fn_ptr.rs @@ -23,10 +23,10 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut fn_: Option i32> = None; assert!((fn_).is_none()); - assert!(((fn_) != (Some(my_foo_0)))); - fn_ = Some(my_foo_0); + assert!(((fn_) != (Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32)))); + fn_ = Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32); assert!(!((fn_).is_none())); - assert!(((fn_) == (Some(my_foo_0)))); + assert!(((fn_) == (Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32)))); let mut a: i32 = 10; assert!(((unsafe { foo_1(fn_, (&mut a as *mut i32),) }) == (a))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_arity.rs b/tests/unit/out/unsafe/fn_ptr_arity.rs index 912c17c4..d92ca088 100644 --- a/tests/unit/out/unsafe/fn_ptr_arity.rs +++ b/tests/unit/out/unsafe/fn_ptr_arity.rs @@ -32,7 +32,25 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut f: Option< unsafe fn(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32, - > = (Some(foo_0)); + > = (Some( + foo_0 + as unsafe fn( + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + ) -> i32, + )); assert!(((unsafe { (f).unwrap()(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,) }) == (22))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_array.rs b/tests/unit/out/unsafe/fn_ptr_array.rs index c41968b9..6f37ac66 100644 --- a/tests/unit/out/unsafe/fn_ptr_array.rs +++ b/tests/unit/out/unsafe/fn_ptr_array.rs @@ -21,12 +21,16 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut ops: [Option i32>; 3] = [Some(add_0), Some(sub_1), Some(mul_2)]; + let mut ops: [Option i32>; 3] = [ + Some(add_0 as unsafe fn(i32, i32) -> i32), + Some(sub_1 as unsafe fn(i32, i32) -> i32), + Some(mul_2 as unsafe fn(i32, i32) -> i32), + ]; assert!(((unsafe { (ops[(0) as usize]).unwrap()(2, 3,) }) == (5))); assert!(((unsafe { (ops[(1) as usize]).unwrap()(7, 4,) }) == (3))); assert!(((unsafe { (ops[(2) as usize]).unwrap()(6, 5,) }) == (30))); assert!(!((ops[(0) as usize]).is_none())); - assert!(((ops[(0) as usize]) == (Some(add_0)))); - assert!(((ops[(0) as usize]) != (Some(sub_1)))); + assert!(((ops[(0) as usize]) == (Some(add_0 as unsafe fn(i32, i32) -> i32)))); + assert!(((ops[(0) as usize]) != (Some(sub_1 as unsafe fn(i32, i32) -> i32)))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_as_condition.rs b/tests/unit/out/unsafe/fn_ptr_as_condition.rs index e4d6574c..8ca0d487 100644 --- a/tests/unit/out/unsafe/fn_ptr_as_condition.rs +++ b/tests/unit/out/unsafe/fn_ptr_as_condition.rs @@ -21,14 +21,19 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: i32 = 5; - (unsafe { maybe_call_1(Some(double_it_0), (&mut a as *mut i32)) }); + (unsafe { + maybe_call_1( + Some(double_it_0 as unsafe fn(*mut i32)), + (&mut a as *mut i32), + ) + }); assert!(((a) == (10))); let mut b: i32 = 5; (unsafe { maybe_call_1(None, (&mut b as *mut i32)) }); assert!(((b) == (5))); let mut fn_: Option = None; if !(!(fn_).is_none()) { - fn_ = Some(double_it_0); + fn_ = Some(double_it_0 as unsafe fn(*mut i32)); } let mut c: i32 = 3; if !(fn_).is_none() { diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs index 014c5387..64aafc26 100644 --- a/tests/unit/out/unsafe/fn_ptr_cast.rs +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -10,7 +10,7 @@ pub unsafe fn double_it_0(mut x: i32) -> i32 { return ((x) * (2)); } pub unsafe fn test_roundtrip_1() { - let mut fn_: Option i32> = Some(double_it_0); + let mut fn_: Option i32> = Some(double_it_0 as unsafe fn(i32) -> i32); assert!(((unsafe { (fn_).unwrap()(5,) }) == (10))); let mut gfn: Option = std::mem::transmute:: i32>, Option>(fn_); @@ -21,7 +21,7 @@ pub unsafe fn test_roundtrip_1() { assert!(((fn2) == (fn_))); } pub unsafe fn test_double_cast_2() { - let mut fn_: Option i32> = Some(double_it_0); + let mut fn_: Option i32> = Some(double_it_0 as unsafe fn(i32) -> i32); let mut fn2: Option i32> = std::mem::transmute::, Option i32>>( std::mem::transmute:: i32>, Option>(fn_), @@ -37,7 +37,7 @@ pub struct Command { pub unsafe fn test_void_ptr_to_fn_3() { let mut cmd: Command = ::default(); cmd.data = std::mem::transmute:: i32>, *mut ::libc::c_void>(Some( - double_it_0, + double_it_0 as unsafe fn(i32) -> i32, )); let mut fn_: Option i32> = std::mem::transmute::<*mut ::libc::c_void, Option i32>>(cmd.data); @@ -47,10 +47,11 @@ pub unsafe fn add_offset_4(mut base: *mut i32, mut offset: i32) -> i32 { return ((*base) + (offset)); } pub unsafe fn test_call_through_cast_5() { - let mut gfn: Option i32> = std::mem::transmute::< - Option i32>, - Option i32>, - >(Some(add_offset_4)); + let mut gfn: Option i32> = + std::mem::transmute::< + Option i32>, + Option i32>, + >(Some(add_offset_4 as unsafe fn(*mut i32, i32) -> i32)); let mut val: i32 = 100; let mut result: i32 = (unsafe { (gfn).unwrap()( diff --git a/tests/unit/out/unsafe/fn_ptr_conditional.rs b/tests/unit/out/unsafe/fn_ptr_conditional.rs index 1e8d5e9f..d8927b07 100644 --- a/tests/unit/out/unsafe/fn_ptr_conditional.rs +++ b/tests/unit/out/unsafe/fn_ptr_conditional.rs @@ -17,12 +17,12 @@ pub unsafe fn identity_2(mut x: i32) -> i32 { } pub unsafe fn pick_3(mut mode: i32) -> Option i32> { return if ((mode) > (0)) { - Some(inc_0) + Some(inc_0 as unsafe fn(i32) -> i32) } else { if ((mode) < (0)) { - Some(dec_1) + Some(dec_1 as unsafe fn(i32) -> i32) } else { - Some(identity_2) + Some(identity_2 as unsafe fn(i32) -> i32) } }; } @@ -30,7 +30,7 @@ pub unsafe fn apply_4(mut fn_: Option i32>, mut x: i32) -> i32 let mut actual: Option i32> = if !(fn_).is_none() { fn_ } else { - Some(identity_2) + Some(identity_2 as unsafe fn(i32) -> i32) }; return (unsafe { (actual).unwrap()(x) }); } @@ -43,7 +43,7 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { (unsafe { pick_3(1,) }).unwrap()(10,) }) == (11))); assert!(((unsafe { (unsafe { pick_3(-1_i32,) }).unwrap()(10,) }) == (9))); assert!(((unsafe { (unsafe { pick_3(0,) }).unwrap()(10,) }) == (10))); - assert!(((unsafe { apply_4(Some(inc_0), 5,) }) == (6))); + assert!(((unsafe { apply_4(Some(inc_0 as unsafe fn(i32) -> i32), 5,) }) == (6))); assert!(((unsafe { apply_4(None, 5,) }) == (5))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index 43d6ddab..0ff33bdb 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -24,10 +24,12 @@ pub fn main() { unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); - assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(|x: i32| { - return -x; - }); + assert!(((unsafe { apply_1(5, Some(Some(identity_0 as unsafe fn(i32) -> i32)),) }) == (5))); + let mut negate: Option i32> = Some( + (|x: i32| { + return -x; + }) as unsafe fn(i32) -> i32, + ); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_global.rs b/tests/unit/out/unsafe/fn_ptr_global.rs index 5cca8fd5..bfb228f0 100644 --- a/tests/unit/out/unsafe/fn_ptr_global.rs +++ b/tests/unit/out/unsafe/fn_ptr_global.rs @@ -29,12 +29,12 @@ pub fn main() { } unsafe fn main_0() -> i32 { assert!(((unsafe { call_op_4(5,) }) == (5))); - (unsafe { set_op_3(Some(double_it_0)) }); + (unsafe { set_op_3(Some(double_it_0 as unsafe fn(i32) -> i32)) }); assert!(!((g_op_2).is_none())); - assert!(((g_op_2) == (Some(double_it_0)))); + assert!(((g_op_2) == (Some(double_it_0 as unsafe fn(i32) -> i32)))); assert!(((unsafe { call_op_4(5,) }) == (10))); - (unsafe { set_op_3(Some(triple_it_1)) }); - assert!(((g_op_2) == (Some(triple_it_1)))); + (unsafe { set_op_3(Some(triple_it_1 as unsafe fn(i32) -> i32)) }); + assert!(((g_op_2) == (Some(triple_it_1 as unsafe fn(i32) -> i32)))); assert!(((unsafe { call_op_4(5,) }) == (15))); (unsafe { set_op_3(None) }); assert!((g_op_2).is_none()); diff --git a/tests/unit/out/unsafe/fn_ptr_reassign.rs b/tests/unit/out/unsafe/fn_ptr_reassign.rs index 4c8b0e3f..0fa0ce9b 100644 --- a/tests/unit/out/unsafe/fn_ptr_reassign.rs +++ b/tests/unit/out/unsafe/fn_ptr_reassign.rs @@ -21,15 +21,15 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut fn_: Option i32> = Some(add_0); + let mut fn_: Option i32> = Some(add_0 as unsafe fn(i32, i32) -> i32); assert!(((unsafe { (fn_).unwrap()(3, 4,) }) == (7))); - fn_ = Some(sub_1); + fn_ = Some(sub_1 as unsafe fn(i32, i32) -> i32); assert!(((unsafe { (fn_).unwrap()(10, 3,) }) == (7))); - fn_ = Some(mul_2); + fn_ = Some(mul_2 as unsafe fn(i32, i32) -> i32); assert!(((unsafe { (fn_).unwrap()(6, 7,) }) == (42))); fn_ = None; assert!((fn_).is_none()); - fn_ = Some(add_0); + fn_ = Some(add_0 as unsafe fn(i32, i32) -> i32); assert!(!((fn_).is_none())); assert!(((unsafe { (fn_).unwrap()(1, 1,) }) == (2))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_return.rs b/tests/unit/out/unsafe/fn_ptr_return.rs index 5f3b8ec7..f2114159 100644 --- a/tests/unit/out/unsafe/fn_ptr_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_return.rs @@ -14,9 +14,9 @@ pub unsafe fn dec_1(mut x: i32) -> i32 { } pub unsafe fn pick_2(mut choose_inc: i32) -> Option i32> { if (choose_inc != 0) { - return Some(inc_0); + return Some(inc_0 as unsafe fn(i32) -> i32); } - return Some(dec_1); + return Some(dec_1 as unsafe fn(i32) -> i32); } pub fn main() { unsafe { @@ -26,10 +26,10 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut f: Option i32> = (unsafe { pick_2(1) }); assert!(!((f).is_none())); - assert!(((f) == (Some(inc_0)))); + assert!(((f) == (Some(inc_0 as unsafe fn(i32) -> i32)))); assert!(((unsafe { (f).unwrap()(10,) }) == (11))); let mut g: Option i32> = (unsafe { pick_2(0) }); - assert!(((g) == (Some(dec_1)))); + assert!(((g) == (Some(dec_1 as unsafe fn(i32) -> i32)))); assert!(((unsafe { (g).unwrap()(10,) }) == (9))); assert!(((f) != (g))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs index a0fd886a..b466017a 100644 --- a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs +++ b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs @@ -28,9 +28,13 @@ unsafe fn main_0() -> i32 { { let len = v.as_mut_ptr().add(v.len()).offset_from(v.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(v.as_mut_ptr(), len).sort_by(|x, y| { - if (Compare_0)(x, y) { + if Some(Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + .call(x as *const _, y as *const _) + { std::cmp::Ordering::Less - } else if (Compare_0)(y, x) { + } else if Some(Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + .call(y as *const _, x as *const _) + { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs index f4601563..dbe1e1d0 100644 --- a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -29,14 +29,26 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut fn1: Option usize> = - Some(libcc2rs::fread_unsafe); - assert!(((fn1) == (Some(libcc2rs::fread_unsafe)))); + Some( + libcc2rs::fread_unsafe + as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, + ); + assert!( + ((fn1) + == (Some( + libcc2rs::fread_unsafe + as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize + ))) + ); assert!(!((fn1).is_none())); let mut fn2: Option usize> = std::mem::transmute::< Option usize>, Option usize>, - >(Some(libcc2rs::fread_unsafe)); + >(Some( + libcc2rs::fread_unsafe + as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, + )); assert!( ((fn1) == (std::mem::transmute::< @@ -48,7 +60,10 @@ unsafe fn main_0() -> i32 { std::mem::transmute::< Option usize>, Option usize>, - >(Some(my_alternative_fread_0)); + >(Some( + my_alternative_fread_0 + as unsafe fn(*mut libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, + )); assert!( ((unsafe { (f3).unwrap()(std::ptr::null_mut(), 0_usize, 0_usize, std::ptr::null_mut(),) }) == (22_usize)) @@ -121,15 +136,27 @@ unsafe fn main_0() -> i32 { } let mut gn1: Option< unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - > = Some(libcc2rs::fwrite_unsafe); - assert!(((gn1) == (Some(libcc2rs::fwrite_unsafe)))); + > = Some( + libcc2rs::fwrite_unsafe + as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, + ); + assert!( + ((gn1) + == (Some( + libcc2rs::fwrite_unsafe + as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize + ))) + ); assert!(!((gn1).is_none())); let mut gn2: Option< unsafe fn(*const libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, > = std::mem::transmute::< Option usize>, Option usize>, - >(Some(libcc2rs::fwrite_unsafe)); + >(Some( + libcc2rs::fwrite_unsafe + as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, + )); assert!( ((gn1) == (std::mem::transmute::< @@ -141,7 +168,10 @@ unsafe fn main_0() -> i32 { std::mem::transmute::< Option usize>, Option usize>, - >(Some(my_alternative_fwrite_1)); + >(Some( + my_alternative_fwrite_1 + as unsafe fn(*const libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, + )); assert!( ((unsafe { (g3).unwrap()(std::ptr::null(), 0_usize, 0_usize, std::ptr::null_mut(),) }) == (33_usize)) diff --git a/tests/unit/out/unsafe/fn_ptr_struct.rs b/tests/unit/out/unsafe/fn_ptr_struct.rs index c8480075..26d4b33d 100644 --- a/tests/unit/out/unsafe/fn_ptr_struct.rs +++ b/tests/unit/out/unsafe/fn_ptr_struct.rs @@ -34,16 +34,16 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut h1: Handler = Handler { tag: 1, - cb: Some(double_it_0), + cb: Some(double_it_0 as unsafe fn(i32) -> i32), }; let mut h2: Handler = Handler { tag: 2, - cb: Some(negate_1), + cb: Some(negate_1 as unsafe fn(i32) -> i32), }; assert!(!((h1.cb).is_none())); assert!(((unsafe { (h1.cb).unwrap()(5,) }) == (10))); assert!(((unsafe { (h2.cb).unwrap()(7,) }) == (-7_i32))); - (h1.cb) = Some(negate_1); + (h1.cb) = Some(negate_1 as unsafe fn(i32) -> i32); assert!(((unsafe { (h1.cb).unwrap()(3,) }) == (-3_i32))); assert!(((h1.cb) == (h2.cb))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_void_return.rs b/tests/unit/out/unsafe/fn_ptr_void_return.rs index 4a98d7f1..83f75ce1 100644 --- a/tests/unit/out/unsafe/fn_ptr_void_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_void_return.rs @@ -22,11 +22,16 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: i32 = 42; - (unsafe { run_2(Some(negate_0), (&mut a as *mut i32)) }); + (unsafe { run_2(Some(negate_0 as unsafe fn(*mut i32)), (&mut a as *mut i32)) }); assert!(((a) == (-42_i32))); - (unsafe { run_2(Some(zero_out_1), (&mut a as *mut i32)) }); + (unsafe { + run_2( + Some(zero_out_1 as unsafe fn(*mut i32)), + (&mut a as *mut i32), + ) + }); assert!(((a) == (0))); - let mut fn_: Option = Some(negate_0); + let mut fn_: Option = Some(negate_0 as unsafe fn(*mut i32)); assert!(!((fn_).is_none())); let mut b: i32 = 10; (unsafe { (fn_).unwrap()((&mut b as *mut i32)) }); diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs index 5eff7364..97fcb1e6 100644 --- a/tests/unit/out/unsafe/fn_ptr_vtable.rs +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -40,9 +40,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut vt: Vtable = Vtable { - create: Some(int_create_1), - get: Some(int_get_2), - destroy: Some(int_destroy_3), + create: Some(int_create_1 as unsafe fn(i32) -> *mut ::libc::c_void), + get: Some(int_get_2 as unsafe fn(*mut ::libc::c_void) -> i32), + destroy: Some(int_destroy_3 as unsafe fn(*mut ::libc::c_void)), }; assert!(!((vt.create).is_none())); assert!(!((vt.get).is_none())); diff --git a/tests/unit/out/unsafe/malloc_realloc_free.rs b/tests/unit/out/unsafe/malloc_realloc_free.rs index 588a7219..ec25809c 100644 --- a/tests/unit/out/unsafe/malloc_realloc_free.rs +++ b/tests/unit/out/unsafe/malloc_realloc_free.rs @@ -56,12 +56,14 @@ unsafe fn main_0() -> i32 { libcc2rs::free_unsafe((zeros as *mut i32 as *mut ::libc::c_void)); } let mut pmalloc: Option *mut ::libc::c_void> = - Some(libcc2rs::malloc_unsafe); - let mut pfree: Option = Some(libcc2rs::free_unsafe); - let mut prealloc: Option *mut ::libc::c_void> = - Some(libcc2rs::realloc_unsafe); + Some(libcc2rs::malloc_unsafe as unsafe fn(usize) -> *mut ::libc::c_void); + let mut pfree: Option = + Some(libcc2rs::free_unsafe as unsafe fn(*mut ::libc::c_void)); + let mut prealloc: Option *mut ::libc::c_void> = Some( + libcc2rs::realloc_unsafe as unsafe fn(*mut ::libc::c_void, usize) -> *mut ::libc::c_void, + ); let mut pcalloc: Option *mut ::libc::c_void> = - Some(libcc2rs::calloc_unsafe); + Some(libcc2rs::calloc_unsafe as unsafe fn(usize, usize) -> *mut ::libc::c_void); let mut __do_while = true; 'loop_: while __do_while || (0 != 0) { __do_while = false; diff --git a/tests/unit/out/unsafe/no_direct_callee.rs b/tests/unit/out/unsafe/no_direct_callee.rs index 311d4c17..143e065e 100644 --- a/tests/unit/out/unsafe/no_direct_callee.rs +++ b/tests/unit/out/unsafe/no_direct_callee.rs @@ -21,6 +21,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - assert!(((unsafe { test_1(Some(test1_0),) }) == (1))); + assert!(((unsafe { test_1(Some(test1_0 as unsafe fn() -> bool),) }) == (1))); return 0; } diff --git a/tests/unit/out/unsafe/qsort_bsearch.rs b/tests/unit/out/unsafe/qsort_bsearch.rs index 2a1ff8a6..d1c9ea7b 100644 --- a/tests/unit/out/unsafe/qsort_bsearch.rs +++ b/tests/unit/out/unsafe/qsort_bsearch.rs @@ -22,10 +22,14 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *mut i32 as *mut ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( + |__f| { + std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(__f as *const ()) + }, + ), ); let mut i: i32 = 0; 'loop_: while ((((i) < (7)) as i32) != 0) { @@ -38,10 +42,14 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( + |__f| { + std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(__f as *const ()) + }, + ), ) as *mut i32); assert!((((!((hit).is_null())) as i32) != 0)); assert!(((((*hit) == (7)) as i32) != 0)); @@ -51,10 +59,14 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(cmp_int_0 as *const ())), + Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( + |__f| { + std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(__f as *const ()) + }, + ), ) as *mut i32); assert!(((((miss).is_null()) as i32) != 0)); return 0; diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index 7427395a..da3cd9de 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -21,12 +21,14 @@ unsafe fn main_0() -> i32 { ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { if (|x: i32, y: i32| { return ((x) < (y)); - })(*x, *y) + }) + .call(*x, *y) { std::cmp::Ordering::Less } else if (|x: i32, y: i32| { return ((x) < (y)); - })(*y, *x) + }) + .call(*y, *x) { std::cmp::Ordering::Greater } else { diff --git a/tests/unit/out/unsafe/string_literal_ptr_init.rs b/tests/unit/out/unsafe/string_literal_ptr_init.rs index c6395ccf..ab58d771 100644 --- a/tests/unit/out/unsafe/string_literal_ptr_init.rs +++ b/tests/unit/out/unsafe/string_literal_ptr_init.rs @@ -34,7 +34,7 @@ pub static mut table_1: [label; 2] = unsafe { }, label { name: ((c"second").as_ptr().cast_mut()).cast_const(), - probe: (Some(probe_two_0)), + probe: (Some(probe_two_0 as unsafe fn() -> i32)), mask: ((1) << (5)), }, ] diff --git a/tests/unit/out/unsafe/va_arg_fn_ptr.rs b/tests/unit/out/unsafe/va_arg_fn_ptr.rs index a02eea3d..f6b375d2 100644 --- a/tests/unit/out/unsafe/va_arg_fn_ptr.rs +++ b/tests/unit/out/unsafe/va_arg_fn_ptr.rs @@ -55,10 +55,9 @@ unsafe fn main_0() -> i32 { ((((unsafe { apply_unary_3( 5, - &[ - (Some(square_0).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into(), - ], + &[(Some(square_0 as unsafe fn(i32) -> i32) + .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into()], ) }) == (25)) as i32) != 0) @@ -67,10 +66,9 @@ unsafe fn main_0() -> i32 { ((((unsafe { apply_unary_3( 7, - &[ - (Some(negate_1).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into(), - ], + &[(Some(negate_1 as unsafe fn(i32) -> i32) + .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into()], ) }) == (-7_i32)) as i32) != 0) @@ -80,10 +78,9 @@ unsafe fn main_0() -> i32 { apply_binary_4( 3, 4, - &[ - (Some(add_2).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into(), - ], + &[(Some(add_2 as unsafe fn(i32, i32) -> i32) + .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into()], ) }) == (7)) as i32) != 0) @@ -95,7 +92,7 @@ unsafe fn main_0() -> i32 { ((&mut dummy as *mut i32) as *mut i32 as *mut ::libc::c_void); let _extra: *mut ::libc::c_void = ((&mut dummy as *mut i32) as *mut i32 as *mut ::libc::c_void); - not_supported_5(_ctx, Some(square_0), _extra) + not_supported_5(_ctx, Some(square_0 as unsafe fn(i32) -> i32), _extra) }) == (-3_i32)) as i32) != 0) ); diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index aea1827d..0d6b373e 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -84,10 +84,10 @@ unsafe fn main_0() -> i32 { assert!(((chosen) == (123))); &(bump_and_return_4); assert!(((side_effect_counter_3) == (2))); - &(Some(bump_and_return_4)); + &(Some(bump_and_return_4 as unsafe fn() -> i32)); assert!(((side_effect_counter_3) == (2))); &(std::mem::transmute:: i32>, Option i32>>( - (Some(bump_and_return_4)), + (Some(bump_and_return_4 as unsafe fn() -> i32)), )); assert!(((side_effect_counter_3) == (2))); let mut storage: i32 = 11; From fd22c476202972a551c7d2968da57a169c7f764a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 14:14:26 +0100 Subject: [PATCH 08/43] Remove nullability of arguments --- cpp2rust/converter/converter.cpp | 66 +++++++++---------- cpp2rust/converter/converter.h | 3 + .../converter/models/converter_refcount.cpp | 4 ++ .../converter/models/converter_refcount.h | 2 + libcc2rs/src/callable.rs | 24 +------ rules/cstdlib/tgt_refcount.rs | 14 ++-- rules/cstdlib/tgt_unsafe.rs | 24 +++---- rules/rustls/tgt_unsafe.rs | 34 ++++------ 8 files changed, 71 insertions(+), 100 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e9559524..a5c0a469 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1812,12 +1812,24 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) { void Converter::ConvertFunctionToFunctionPointer( const clang::FunctionDecl *fn_decl) { - auto proto = fn_decl->getType()->getAs(); - StrCat(std::format("Some({} as {} {})", Mapper::MapFunctionName(fn_decl), - keyword_unsafe_, ConvertFunctionPointerType(proto))); + StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl))); computed_expr_type_ = ComputedExprType::FreshPointer; } +std::string Converter::ConvertFnPtrCallee(clang::Expr *arg) { + PushExprKind push(*this, ExprKind::Callee); + Buffer buf(*this); + Convert(arg); + return std::move(buf).str(); +} + +std::string Converter::ConvertFnPtrPlaceholder(clang::Expr *arg) { + auto proto = + arg->getType()->getPointeeType()->getAs(); + return std::format("({} as {} {})", ConvertFnPtrCallee(arg), keyword_unsafe_, + ConvertFunctionPointerType(proto)); +} + Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) { using Kind = CallArg::Kind; @@ -2409,12 +2421,6 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { computed_expr_type_ = ComputedExprType::FreshPointer; break; default: - if (type->isFunctionPointerType() && - clang::isa( - sub_expr->IgnoreUnlessSpelledInSource())) { - ConvertVarInit(type, sub_expr); - break; - } if (auto *literal = clang::dyn_cast(sub_expr)) { auto type = expr->getType(); StrCat(getIntegerLiteral(literal, true, &type)); @@ -3597,31 +3603,21 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { } bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { - bool to_fn_ptr = isAddrOf() && expr->capture_size() == 0; - if (to_fn_ptr) { - StrCat("Some("); - } - { - PushParen paren(*this); - StrCat('|'); - for (auto p : - expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { - StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), - token::kComma); - } - StrCat("| {"); - EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); - PushCurrFunction push_fn(*this, - expr->getLambdaClass()->getLambdaCallOperator()); - ConvertFunctionBody(curr_function_); - StrCat('}'); - } - if (to_fn_ptr) { - auto proto = - expr->getCallOperator()->getType()->getAs(); - StrCat(std::format(" as {} {})", keyword_unsafe_, - ConvertFunctionPointerType(proto))); + if (isAddrOf() && expr->capture_size() == 0) { + StrCat("Some"); } + PushParen paren(*this); + StrCat('|'); + for (auto p : expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { + StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), + token::kComma); + } + StrCat("| {"); + EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); + PushCurrFunction push_fn(*this, + expr->getLambdaClass()->getLambdaCallOperator()); + ConvertFunctionBody(curr_function_); + StrCat('}'); return false; } @@ -4631,6 +4627,10 @@ void Converter::PlaceholderCtx::dump() const { std::string Converter::ConvertPlaceholder(clang::Expr *expr, clang::Expr *arg, const PlaceholderCtx &ph_ctx) { + if (arg->getType()->isFunctionPointerType()) { + return ConvertFnPtrPlaceholder(arg); + } + if (ph_ctx.declared_in_rule_as_rust_ptr && arg->getType()->isArrayType()) { return std::format( "({} as {})", ConvertFreshPointer(arg), diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index d735f75f..f2cb8c7b 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -309,6 +309,9 @@ class Converter : public clang::RecursiveASTVisitor { virtual void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl); + std::string ConvertFnPtrCallee(clang::Expr *arg); + virtual std::string ConvertFnPtrPlaceholder(clang::Expr *arg); + // Option implements Copy virtual bool FunctionPointerImplementsCopy() const { return true; } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e63e34be..bda2078c 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1287,6 +1287,10 @@ void ConverterRefCount::ConvertFunctionToFunctionPointer( computed_expr_type_ = ComputedExprType::FreshPointer; } +std::string ConverterRefCount::ConvertFnPtrPlaceholder(clang::Expr *arg) { + return ConvertFnPtrCallee(arg); +} + void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) { StrCat('('); Convert(expr); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index f588f6d1..790f7530 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -103,6 +103,8 @@ class ConverterRefCount final : public Converter { void ConvertFunctionToFunctionPointer(const clang::FunctionDecl *fn_decl) override; + std::string ConvertFnPtrPlaceholder(clang::Expr *arg) override; + // FnPtr does not implement Copy bool FunctionPointerImplementsCopy() const override { return false; } diff --git a/libcc2rs/src/callable.rs b/libcc2rs/src/callable.rs index 747277d0..f35dcfdc 100644 --- a/libcc2rs/src/callable.rs +++ b/libcc2rs/src/callable.rs @@ -17,30 +17,10 @@ macro_rules! callable { } } - impl $name<$($A,)* R> for Option - where - F: Fn($($A),*) -> R, - { - #[inline] - fn call(&self, $($a: $A),*) -> R { - self.as_ref().unwrap()($($a),*) - } - } - - impl<$($A,)* R> $name<$($A,)* R> for Option R> { - #[inline] - fn call(&self, $($a: $A),*) -> R { - unsafe { self.unwrap()($($a),*) } - } - } - - impl $name<$($A,)* R> for crate::fn_ptr::FnPtr - where - F: Fn($($A),*) -> R + 'static, - { + impl<$($A,)* R> $name<$($A,)* R> for unsafe fn($($A),*) -> R { #[inline] fn call(&self, $($a: $A),*) -> R { - (**self)($($a),*) + unsafe { self($($a),*) } } } }; diff --git a/rules/cstdlib/tgt_refcount.rs b/rules/cstdlib/tgt_refcount.rs index db6d8d7d..534d4472 100644 --- a/rules/cstdlib/tgt_refcount.rs +++ b/rules/cstdlib/tgt_refcount.rs @@ -50,13 +50,7 @@ fn f10(a0: Ptr, a1: Ptr) -> Ptr { } } -fn f8( - a0: AnyPtr, - a1: AnyPtr, - a2: usize, - a3: usize, - a4: FnPtr i32>, -) -> AnyPtr { +fn f8(a0: AnyPtr, a1: AnyPtr, a2: usize, a3: usize, a4: fn(AnyPtr, AnyPtr) -> i32) -> AnyPtr { let __base = a1.reinterpret_cast::(); let mut __lo: isize = 0; let mut __hi: isize = a2 as isize - 1; @@ -64,7 +58,7 @@ fn f8( while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * a3); - let __r = a4.call(a0.clone(), __elem.to_any()); + let __r = a4(a0.clone(), __elem.to_any()); if __r == 0 { __found = __elem.to_any(); } else if __r < 0 { @@ -76,12 +70,12 @@ fn f8( __found } -fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: FnPtr i32>) { +fn f9(a0: AnyPtr, a1: usize, a2: usize, a3: fn(AnyPtr, AnyPtr) -> i32) { let __base = a0.reinterpret_cast::(); for __i in 0..a1 { let mut __min = __i; for __j in (__i + 1)..a1 { - if a3.call( + if a3( __base.offset(__j * a2).to_any(), __base.offset(__min * a2).to_any(), ) < 0 diff --git a/rules/cstdlib/tgt_unsafe.rs b/rules/cstdlib/tgt_unsafe.rs index 9d0d0327..5b983c43 100644 --- a/rules/cstdlib/tgt_unsafe.rs +++ b/rules/cstdlib/tgt_unsafe.rs @@ -34,19 +34,17 @@ unsafe fn f8( a1: *const ::libc::c_void, a2: usize, a3: usize, - a4: Option i32>, + a4: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, ) -> *mut ::libc::c_void { libc::bsearch( a0, a1, a2, a3, - a4.map(|__f| { - std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(__f as *const ()) - }), + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(a4 as *const ())), ) } @@ -54,18 +52,16 @@ unsafe fn f9( a0: *mut ::libc::c_void, a1: usize, a2: usize, - a3: Option i32>, + a3: unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, ) { libc::qsort( a0, a1, a2, - a3.map(|__f| { - std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(__f as *const ()) - }), + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >(a3 as *const ())), ) } diff --git a/rules/rustls/tgt_unsafe.rs b/rules/rustls/tgt_unsafe.rs index 59c3d3f1..db78cc47 100644 --- a/rules/rustls/tgt_unsafe.rs +++ b/rules/rustls/tgt_unsafe.rs @@ -433,15 +433,13 @@ unsafe fn f57(a0: u32) -> bool { unsafe fn f58( a0: *mut ::rustls_ffi::connection::rustls_connection, - a1: Option i32>, + a1: unsafe fn(*mut ::libc::c_void, *mut u8, u64, *mut u64) -> i32, a2: *mut ::libc::c_void, a3: *mut u64, ) -> i32 { ::rustls_ffi::connection::rustls_connection::rustls_connection_read_tls( a0, - std::mem::transmute::( - a1.map_or(0_usize, |__f| __f as usize), - ), + std::mem::transmute::<*const (), ::rustls_ffi::io::rustls_read_callback>(a1 as *const ()), a2, a3 as *mut usize, ) @@ -449,15 +447,13 @@ unsafe fn f58( } unsafe fn f59( a0: *mut ::rustls_ffi::connection::rustls_connection, - a1: Option i32>, + a1: unsafe fn(*mut ::libc::c_void, *const u8, u64, *mut u64) -> i32, a2: *mut ::libc::c_void, a3: *mut u64, ) -> i32 { ::rustls_ffi::connection::rustls_connection::rustls_connection_write_tls( a0, - std::mem::transmute::( - a1.map_or(0_usize, |__f| __f as usize), - ), + std::mem::transmute::<*const (), ::rustls_ffi::io::rustls_write_callback>(a1 as *const ()), a2, a3 as *mut usize, ) @@ -465,15 +461,13 @@ unsafe fn f59( } unsafe fn f60( a0: *mut ::rustls_ffi::client::rustls_client_config_builder, - a1: Option< - unsafe fn(::rustls_ffi::rslice::rustls_str<'static>, *const u8, u64, *const u8, u64), - >, + a1: unsafe fn(::rustls_ffi::rslice::rustls_str<'static>, *const u8, u64, *const u8, u64), a2: Option) -> i32>, ) -> ::rustls_ffi::rustls_result { ::rustls_ffi::client::rustls_client_config_builder::rustls_client_config_builder_set_key_log( a0, - std::mem::transmute::( - a1.map_or(0_usize, |__f| __f as usize), + std::mem::transmute::<*const (), ::rustls_ffi::keylog::rustls_keylog_log_callback>( + a1 as *const (), ), std::mem::transmute::< Option) -> i32>, @@ -483,17 +477,15 @@ unsafe fn f60( } unsafe fn f61( a0: *mut ::rustls_ffi::client::rustls_client_config_builder, - a1: Option< - unsafe fn( - *mut ::libc::c_void, - *const ::rustls_ffi::client::rustls_verify_server_cert_params<'static>, - ) -> ::rustls_ffi::rustls_result, - >, + a1: unsafe fn( + *mut ::libc::c_void, + *const ::rustls_ffi::client::rustls_verify_server_cert_params<'static>, + ) -> ::rustls_ffi::rustls_result, ) -> ::rustls_ffi::rustls_result { ::rustls_ffi::client::rustls_client_config_builder::rustls_client_config_builder_dangerous_set_certificate_verifier( a0, - std::mem::transmute::( - a1.map_or(0_usize, |__f| __f as usize), + std::mem::transmute::<*const (), ::rustls_ffi::client::rustls_verify_server_cert_callback>( + a1 as *const (), ), ) } From 028e45d7e4488da57397a5a539cdf340c43f16a7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 14:17:26 +0100 Subject: [PATCH 09/43] Update tests --- .../converter/models/converter_refcount.cpp | 8 +--- tests/unit/out/refcount/fn_ptr_default_arg.rs | 2 +- tests/unit/out/refcount/fn_ptr_stable_sort.rs | 2 +- tests/unit/out/refcount/qsort_bsearch.rs | 6 +-- tests/unit/out/unsafe/fn_ptr.rs | 6 +-- tests/unit/out/unsafe/fn_ptr_arity.rs | 20 +------- tests/unit/out/unsafe/fn_ptr_array.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_as_condition.rs | 9 +--- tests/unit/out/unsafe/fn_ptr_cast.rs | 15 +++--- tests/unit/out/unsafe/fn_ptr_conditional.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 10 ++-- tests/unit/out/unsafe/fn_ptr_global.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_reassign.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_return.rs | 8 ++-- tests/unit/out/unsafe/fn_ptr_stable_sort.rs | 4 +- .../unit/out/unsafe/fn_ptr_stdlib_compare.rs | 46 ++++--------------- tests/unit/out/unsafe/fn_ptr_struct.rs | 6 +-- tests/unit/out/unsafe/fn_ptr_void_return.rs | 11 ++--- tests/unit/out/unsafe/fn_ptr_vtable.rs | 6 +-- tests/unit/out/unsafe/malloc_realloc_free.rs | 12 ++--- tests/unit/out/unsafe/no_direct_callee.rs | 2 +- tests/unit/out/unsafe/qsort_bsearch.rs | 45 +++++++++--------- .../out/unsafe/string_literal_ptr_init.rs | 2 +- tests/unit/out/unsafe/va_arg_fn_ptr.rs | 23 ++++++---- tests/unit/out/unsafe/void_cast.rs | 4 +- 25 files changed, 106 insertions(+), 177 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index bda2078c..625e62fc 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2089,13 +2089,9 @@ std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type, Buffer buf(*this); PushConversionKind push(*this, ConversionKind::Unboxed); if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - auto proto = lambda->getCallOperator() - ->getType() - ->getAs(); - StrCat( - std::format("FnPtr::<{}>::new", ConvertFunctionPointerType(proto))); - PushParen paren(*this); + StrCat("FnPtr::new("); VisitLambdaExpr(lambda); + StrCat(')'); } else { VisitLambdaExpr(lambda); } diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 4a0d282c..0348fc82 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,7 +26,7 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr:: i32>::new( + let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( (|x: i32| { let x: Value = Rc::new(RefCell::new(x)); return -(*x.borrow()); diff --git a/tests/unit/out/refcount/fn_ptr_stable_sort.rs b/tests/unit/out/refcount/fn_ptr_stable_sort.rs index d294121b..6ca928be 100644 --- a/tests/unit/out/refcount/fn_ptr_stable_sort.rs +++ b/tests/unit/out/refcount/fn_ptr_stable_sort.rs @@ -61,7 +61,7 @@ fn main_0() -> i32 { }); (v.as_pointer() as Ptr).sort_with_cmp( (v.as_pointer() as Ptr).to_end().get_offset(), - |x, y| FnPtr::, Ptr) -> bool>::new(Compare_0).call(x, y), + |x, y| Compare_0.call(x, y), ); assert!( ((*(*(v.as_pointer() as Ptr) diff --git a/tests/unit/out/refcount/qsort_bsearch.rs b/tests/unit/out/refcount/qsort_bsearch.rs index c200ac0c..d53ecb1d 100644 --- a/tests/unit/out/refcount/qsort_bsearch.rs +++ b/tests/unit/out/refcount/qsort_bsearch.rs @@ -29,7 +29,7 @@ fn main_0() -> i32 { for __i in 0..8_usize { let mut __min = __i; for __j in (__i + 1)..8_usize { - if FnPtr:: i32>::new(cmp_int_0).call( + if cmp_int_0( __base.offset(__j * ::std::mem::size_of::()).to_any(), __base.offset(__min * ::std::mem::size_of::()).to_any(), ) < 0 @@ -76,7 +76,7 @@ fn main_0() -> i32 { while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); - let __r = FnPtr:: i32>::new(cmp_int_0).call( + let __r = cmp_int_0( ((key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); @@ -106,7 +106,7 @@ fn main_0() -> i32 { while __lo <= __hi && __found.is_null() { let __mid = __lo + (__hi - __lo) / 2; let __elem = __base.offset(__mid as usize * ::std::mem::size_of::()); - let __r = FnPtr:: i32>::new(cmp_int_0).call( + let __r = cmp_int_0( ((miss_key.as_pointer()) as Ptr).to_any().clone(), __elem.to_any(), ); diff --git a/tests/unit/out/unsafe/fn_ptr.rs b/tests/unit/out/unsafe/fn_ptr.rs index 6faa1392..dcaacdaf 100644 --- a/tests/unit/out/unsafe/fn_ptr.rs +++ b/tests/unit/out/unsafe/fn_ptr.rs @@ -23,10 +23,10 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut fn_: Option i32> = None; assert!((fn_).is_none()); - assert!(((fn_) != (Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32)))); - fn_ = Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32); + assert!(((fn_) != (Some(my_foo_0)))); + fn_ = Some(my_foo_0); assert!(!((fn_).is_none())); - assert!(((fn_) == (Some(my_foo_0 as unsafe fn(*mut ::libc::c_void) -> i32)))); + assert!(((fn_) == (Some(my_foo_0)))); let mut a: i32 = 10; assert!(((unsafe { foo_1(fn_, (&mut a as *mut i32),) }) == (a))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_arity.rs b/tests/unit/out/unsafe/fn_ptr_arity.rs index d92ca088..912c17c4 100644 --- a/tests/unit/out/unsafe/fn_ptr_arity.rs +++ b/tests/unit/out/unsafe/fn_ptr_arity.rs @@ -32,25 +32,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut f: Option< unsafe fn(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) -> i32, - > = (Some( - foo_0 - as unsafe fn( - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - i32, - ) -> i32, - )); + > = (Some(foo_0)); assert!(((unsafe { (f).unwrap()(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,) }) == (22))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_array.rs b/tests/unit/out/unsafe/fn_ptr_array.rs index 6f37ac66..c41968b9 100644 --- a/tests/unit/out/unsafe/fn_ptr_array.rs +++ b/tests/unit/out/unsafe/fn_ptr_array.rs @@ -21,16 +21,12 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut ops: [Option i32>; 3] = [ - Some(add_0 as unsafe fn(i32, i32) -> i32), - Some(sub_1 as unsafe fn(i32, i32) -> i32), - Some(mul_2 as unsafe fn(i32, i32) -> i32), - ]; + let mut ops: [Option i32>; 3] = [Some(add_0), Some(sub_1), Some(mul_2)]; assert!(((unsafe { (ops[(0) as usize]).unwrap()(2, 3,) }) == (5))); assert!(((unsafe { (ops[(1) as usize]).unwrap()(7, 4,) }) == (3))); assert!(((unsafe { (ops[(2) as usize]).unwrap()(6, 5,) }) == (30))); assert!(!((ops[(0) as usize]).is_none())); - assert!(((ops[(0) as usize]) == (Some(add_0 as unsafe fn(i32, i32) -> i32)))); - assert!(((ops[(0) as usize]) != (Some(sub_1 as unsafe fn(i32, i32) -> i32)))); + assert!(((ops[(0) as usize]) == (Some(add_0)))); + assert!(((ops[(0) as usize]) != (Some(sub_1)))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_as_condition.rs b/tests/unit/out/unsafe/fn_ptr_as_condition.rs index 8ca0d487..e4d6574c 100644 --- a/tests/unit/out/unsafe/fn_ptr_as_condition.rs +++ b/tests/unit/out/unsafe/fn_ptr_as_condition.rs @@ -21,19 +21,14 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: i32 = 5; - (unsafe { - maybe_call_1( - Some(double_it_0 as unsafe fn(*mut i32)), - (&mut a as *mut i32), - ) - }); + (unsafe { maybe_call_1(Some(double_it_0), (&mut a as *mut i32)) }); assert!(((a) == (10))); let mut b: i32 = 5; (unsafe { maybe_call_1(None, (&mut b as *mut i32)) }); assert!(((b) == (5))); let mut fn_: Option = None; if !(!(fn_).is_none()) { - fn_ = Some(double_it_0 as unsafe fn(*mut i32)); + fn_ = Some(double_it_0); } let mut c: i32 = 3; if !(fn_).is_none() { diff --git a/tests/unit/out/unsafe/fn_ptr_cast.rs b/tests/unit/out/unsafe/fn_ptr_cast.rs index 64aafc26..014c5387 100644 --- a/tests/unit/out/unsafe/fn_ptr_cast.rs +++ b/tests/unit/out/unsafe/fn_ptr_cast.rs @@ -10,7 +10,7 @@ pub unsafe fn double_it_0(mut x: i32) -> i32 { return ((x) * (2)); } pub unsafe fn test_roundtrip_1() { - let mut fn_: Option i32> = Some(double_it_0 as unsafe fn(i32) -> i32); + let mut fn_: Option i32> = Some(double_it_0); assert!(((unsafe { (fn_).unwrap()(5,) }) == (10))); let mut gfn: Option = std::mem::transmute:: i32>, Option>(fn_); @@ -21,7 +21,7 @@ pub unsafe fn test_roundtrip_1() { assert!(((fn2) == (fn_))); } pub unsafe fn test_double_cast_2() { - let mut fn_: Option i32> = Some(double_it_0 as unsafe fn(i32) -> i32); + let mut fn_: Option i32> = Some(double_it_0); let mut fn2: Option i32> = std::mem::transmute::, Option i32>>( std::mem::transmute:: i32>, Option>(fn_), @@ -37,7 +37,7 @@ pub struct Command { pub unsafe fn test_void_ptr_to_fn_3() { let mut cmd: Command = ::default(); cmd.data = std::mem::transmute:: i32>, *mut ::libc::c_void>(Some( - double_it_0 as unsafe fn(i32) -> i32, + double_it_0, )); let mut fn_: Option i32> = std::mem::transmute::<*mut ::libc::c_void, Option i32>>(cmd.data); @@ -47,11 +47,10 @@ pub unsafe fn add_offset_4(mut base: *mut i32, mut offset: i32) -> i32 { return ((*base) + (offset)); } pub unsafe fn test_call_through_cast_5() { - let mut gfn: Option i32> = - std::mem::transmute::< - Option i32>, - Option i32>, - >(Some(add_offset_4 as unsafe fn(*mut i32, i32) -> i32)); + let mut gfn: Option i32> = std::mem::transmute::< + Option i32>, + Option i32>, + >(Some(add_offset_4)); let mut val: i32 = 100; let mut result: i32 = (unsafe { (gfn).unwrap()( diff --git a/tests/unit/out/unsafe/fn_ptr_conditional.rs b/tests/unit/out/unsafe/fn_ptr_conditional.rs index d8927b07..1e8d5e9f 100644 --- a/tests/unit/out/unsafe/fn_ptr_conditional.rs +++ b/tests/unit/out/unsafe/fn_ptr_conditional.rs @@ -17,12 +17,12 @@ pub unsafe fn identity_2(mut x: i32) -> i32 { } pub unsafe fn pick_3(mut mode: i32) -> Option i32> { return if ((mode) > (0)) { - Some(inc_0 as unsafe fn(i32) -> i32) + Some(inc_0) } else { if ((mode) < (0)) { - Some(dec_1 as unsafe fn(i32) -> i32) + Some(dec_1) } else { - Some(identity_2 as unsafe fn(i32) -> i32) + Some(identity_2) } }; } @@ -30,7 +30,7 @@ pub unsafe fn apply_4(mut fn_: Option i32>, mut x: i32) -> i32 let mut actual: Option i32> = if !(fn_).is_none() { fn_ } else { - Some(identity_2 as unsafe fn(i32) -> i32) + Some(identity_2) }; return (unsafe { (actual).unwrap()(x) }); } @@ -43,7 +43,7 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { (unsafe { pick_3(1,) }).unwrap()(10,) }) == (11))); assert!(((unsafe { (unsafe { pick_3(-1_i32,) }).unwrap()(10,) }) == (9))); assert!(((unsafe { (unsafe { pick_3(0,) }).unwrap()(10,) }) == (10))); - assert!(((unsafe { apply_4(Some(inc_0 as unsafe fn(i32) -> i32), 5,) }) == (6))); + assert!(((unsafe { apply_4(Some(inc_0), 5,) }) == (6))); assert!(((unsafe { apply_4(None, 5,) }) == (5))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index 0ff33bdb..43d6ddab 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -24,12 +24,10 @@ pub fn main() { unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); - assert!(((unsafe { apply_1(5, Some(Some(identity_0 as unsafe fn(i32) -> i32)),) }) == (5))); - let mut negate: Option i32> = Some( - (|x: i32| { - return -x; - }) as unsafe fn(i32) -> i32, - ); + assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); + let mut negate: Option i32> = Some(|x: i32| { + return -x; + }); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_global.rs b/tests/unit/out/unsafe/fn_ptr_global.rs index bfb228f0..5cca8fd5 100644 --- a/tests/unit/out/unsafe/fn_ptr_global.rs +++ b/tests/unit/out/unsafe/fn_ptr_global.rs @@ -29,12 +29,12 @@ pub fn main() { } unsafe fn main_0() -> i32 { assert!(((unsafe { call_op_4(5,) }) == (5))); - (unsafe { set_op_3(Some(double_it_0 as unsafe fn(i32) -> i32)) }); + (unsafe { set_op_3(Some(double_it_0)) }); assert!(!((g_op_2).is_none())); - assert!(((g_op_2) == (Some(double_it_0 as unsafe fn(i32) -> i32)))); + assert!(((g_op_2) == (Some(double_it_0)))); assert!(((unsafe { call_op_4(5,) }) == (10))); - (unsafe { set_op_3(Some(triple_it_1 as unsafe fn(i32) -> i32)) }); - assert!(((g_op_2) == (Some(triple_it_1 as unsafe fn(i32) -> i32)))); + (unsafe { set_op_3(Some(triple_it_1)) }); + assert!(((g_op_2) == (Some(triple_it_1)))); assert!(((unsafe { call_op_4(5,) }) == (15))); (unsafe { set_op_3(None) }); assert!((g_op_2).is_none()); diff --git a/tests/unit/out/unsafe/fn_ptr_reassign.rs b/tests/unit/out/unsafe/fn_ptr_reassign.rs index 0fa0ce9b..4c8b0e3f 100644 --- a/tests/unit/out/unsafe/fn_ptr_reassign.rs +++ b/tests/unit/out/unsafe/fn_ptr_reassign.rs @@ -21,15 +21,15 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut fn_: Option i32> = Some(add_0 as unsafe fn(i32, i32) -> i32); + let mut fn_: Option i32> = Some(add_0); assert!(((unsafe { (fn_).unwrap()(3, 4,) }) == (7))); - fn_ = Some(sub_1 as unsafe fn(i32, i32) -> i32); + fn_ = Some(sub_1); assert!(((unsafe { (fn_).unwrap()(10, 3,) }) == (7))); - fn_ = Some(mul_2 as unsafe fn(i32, i32) -> i32); + fn_ = Some(mul_2); assert!(((unsafe { (fn_).unwrap()(6, 7,) }) == (42))); fn_ = None; assert!((fn_).is_none()); - fn_ = Some(add_0 as unsafe fn(i32, i32) -> i32); + fn_ = Some(add_0); assert!(!((fn_).is_none())); assert!(((unsafe { (fn_).unwrap()(1, 1,) }) == (2))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_return.rs b/tests/unit/out/unsafe/fn_ptr_return.rs index f2114159..5f3b8ec7 100644 --- a/tests/unit/out/unsafe/fn_ptr_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_return.rs @@ -14,9 +14,9 @@ pub unsafe fn dec_1(mut x: i32) -> i32 { } pub unsafe fn pick_2(mut choose_inc: i32) -> Option i32> { if (choose_inc != 0) { - return Some(inc_0 as unsafe fn(i32) -> i32); + return Some(inc_0); } - return Some(dec_1 as unsafe fn(i32) -> i32); + return Some(dec_1); } pub fn main() { unsafe { @@ -26,10 +26,10 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut f: Option i32> = (unsafe { pick_2(1) }); assert!(!((f).is_none())); - assert!(((f) == (Some(inc_0 as unsafe fn(i32) -> i32)))); + assert!(((f) == (Some(inc_0)))); assert!(((unsafe { (f).unwrap()(10,) }) == (11))); let mut g: Option i32> = (unsafe { pick_2(0) }); - assert!(((g) == (Some(dec_1 as unsafe fn(i32) -> i32)))); + assert!(((g) == (Some(dec_1)))); assert!(((unsafe { (g).unwrap()(10,) }) == (9))); assert!(((f) != (g))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs index b466017a..2165c81e 100644 --- a/tests/unit/out/unsafe/fn_ptr_stable_sort.rs +++ b/tests/unit/out/unsafe/fn_ptr_stable_sort.rs @@ -28,11 +28,11 @@ unsafe fn main_0() -> i32 { { let len = v.as_mut_ptr().add(v.len()).offset_from(v.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(v.as_mut_ptr(), len).sort_by(|x, y| { - if Some(Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + if (Compare_0 as unsafe fn(*const Item, *const Item) -> bool) .call(x as *const _, y as *const _) { std::cmp::Ordering::Less - } else if Some(Compare_0 as unsafe fn(*const Item, *const Item) -> bool) + } else if (Compare_0 as unsafe fn(*const Item, *const Item) -> bool) .call(y as *const _, x as *const _) { std::cmp::Ordering::Greater diff --git a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs index dbe1e1d0..f4601563 100644 --- a/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs +++ b/tests/unit/out/unsafe/fn_ptr_stdlib_compare.rs @@ -29,26 +29,14 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut fn1: Option usize> = - Some( - libcc2rs::fread_unsafe - as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - ); - assert!( - ((fn1) - == (Some( - libcc2rs::fread_unsafe - as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize - ))) - ); + Some(libcc2rs::fread_unsafe); + assert!(((fn1) == (Some(libcc2rs::fread_unsafe)))); assert!(!((fn1).is_none())); let mut fn2: Option usize> = std::mem::transmute::< Option usize>, Option usize>, - >(Some( - libcc2rs::fread_unsafe - as unsafe fn(*mut ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - )); + >(Some(libcc2rs::fread_unsafe)); assert!( ((fn1) == (std::mem::transmute::< @@ -60,10 +48,7 @@ unsafe fn main_0() -> i32 { std::mem::transmute::< Option usize>, Option usize>, - >(Some( - my_alternative_fread_0 - as unsafe fn(*mut libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, - )); + >(Some(my_alternative_fread_0)); assert!( ((unsafe { (f3).unwrap()(std::ptr::null_mut(), 0_usize, 0_usize, std::ptr::null_mut(),) }) == (22_usize)) @@ -136,27 +121,15 @@ unsafe fn main_0() -> i32 { } let mut gn1: Option< unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - > = Some( - libcc2rs::fwrite_unsafe - as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - ); - assert!( - ((gn1) - == (Some( - libcc2rs::fwrite_unsafe - as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize - ))) - ); + > = Some(libcc2rs::fwrite_unsafe); + assert!(((gn1) == (Some(libcc2rs::fwrite_unsafe)))); assert!(!((gn1).is_none())); let mut gn2: Option< unsafe fn(*const libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, > = std::mem::transmute::< Option usize>, Option usize>, - >(Some( - libcc2rs::fwrite_unsafe - as unsafe fn(*const ::libc::c_void, usize, usize, *mut ::libc::FILE) -> usize, - )); + >(Some(libcc2rs::fwrite_unsafe)); assert!( ((gn1) == (std::mem::transmute::< @@ -168,10 +141,7 @@ unsafe fn main_0() -> i32 { std::mem::transmute::< Option usize>, Option usize>, - >(Some( - my_alternative_fwrite_1 - as unsafe fn(*const libc::c_char, usize, usize, *mut ::libc::c_void) -> usize, - )); + >(Some(my_alternative_fwrite_1)); assert!( ((unsafe { (g3).unwrap()(std::ptr::null(), 0_usize, 0_usize, std::ptr::null_mut(),) }) == (33_usize)) diff --git a/tests/unit/out/unsafe/fn_ptr_struct.rs b/tests/unit/out/unsafe/fn_ptr_struct.rs index 26d4b33d..c8480075 100644 --- a/tests/unit/out/unsafe/fn_ptr_struct.rs +++ b/tests/unit/out/unsafe/fn_ptr_struct.rs @@ -34,16 +34,16 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut h1: Handler = Handler { tag: 1, - cb: Some(double_it_0 as unsafe fn(i32) -> i32), + cb: Some(double_it_0), }; let mut h2: Handler = Handler { tag: 2, - cb: Some(negate_1 as unsafe fn(i32) -> i32), + cb: Some(negate_1), }; assert!(!((h1.cb).is_none())); assert!(((unsafe { (h1.cb).unwrap()(5,) }) == (10))); assert!(((unsafe { (h2.cb).unwrap()(7,) }) == (-7_i32))); - (h1.cb) = Some(negate_1 as unsafe fn(i32) -> i32); + (h1.cb) = Some(negate_1); assert!(((unsafe { (h1.cb).unwrap()(3,) }) == (-3_i32))); assert!(((h1.cb) == (h2.cb))); return 0; diff --git a/tests/unit/out/unsafe/fn_ptr_void_return.rs b/tests/unit/out/unsafe/fn_ptr_void_return.rs index 83f75ce1..4a98d7f1 100644 --- a/tests/unit/out/unsafe/fn_ptr_void_return.rs +++ b/tests/unit/out/unsafe/fn_ptr_void_return.rs @@ -22,16 +22,11 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: i32 = 42; - (unsafe { run_2(Some(negate_0 as unsafe fn(*mut i32)), (&mut a as *mut i32)) }); + (unsafe { run_2(Some(negate_0), (&mut a as *mut i32)) }); assert!(((a) == (-42_i32))); - (unsafe { - run_2( - Some(zero_out_1 as unsafe fn(*mut i32)), - (&mut a as *mut i32), - ) - }); + (unsafe { run_2(Some(zero_out_1), (&mut a as *mut i32)) }); assert!(((a) == (0))); - let mut fn_: Option = Some(negate_0 as unsafe fn(*mut i32)); + let mut fn_: Option = Some(negate_0); assert!(!((fn_).is_none())); let mut b: i32 = 10; (unsafe { (fn_).unwrap()((&mut b as *mut i32)) }); diff --git a/tests/unit/out/unsafe/fn_ptr_vtable.rs b/tests/unit/out/unsafe/fn_ptr_vtable.rs index 97fcb1e6..5eff7364 100644 --- a/tests/unit/out/unsafe/fn_ptr_vtable.rs +++ b/tests/unit/out/unsafe/fn_ptr_vtable.rs @@ -40,9 +40,9 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut vt: Vtable = Vtable { - create: Some(int_create_1 as unsafe fn(i32) -> *mut ::libc::c_void), - get: Some(int_get_2 as unsafe fn(*mut ::libc::c_void) -> i32), - destroy: Some(int_destroy_3 as unsafe fn(*mut ::libc::c_void)), + create: Some(int_create_1), + get: Some(int_get_2), + destroy: Some(int_destroy_3), }; assert!(!((vt.create).is_none())); assert!(!((vt.get).is_none())); diff --git a/tests/unit/out/unsafe/malloc_realloc_free.rs b/tests/unit/out/unsafe/malloc_realloc_free.rs index ec25809c..588a7219 100644 --- a/tests/unit/out/unsafe/malloc_realloc_free.rs +++ b/tests/unit/out/unsafe/malloc_realloc_free.rs @@ -56,14 +56,12 @@ unsafe fn main_0() -> i32 { libcc2rs::free_unsafe((zeros as *mut i32 as *mut ::libc::c_void)); } let mut pmalloc: Option *mut ::libc::c_void> = - Some(libcc2rs::malloc_unsafe as unsafe fn(usize) -> *mut ::libc::c_void); - let mut pfree: Option = - Some(libcc2rs::free_unsafe as unsafe fn(*mut ::libc::c_void)); - let mut prealloc: Option *mut ::libc::c_void> = Some( - libcc2rs::realloc_unsafe as unsafe fn(*mut ::libc::c_void, usize) -> *mut ::libc::c_void, - ); + Some(libcc2rs::malloc_unsafe); + let mut pfree: Option = Some(libcc2rs::free_unsafe); + let mut prealloc: Option *mut ::libc::c_void> = + Some(libcc2rs::realloc_unsafe); let mut pcalloc: Option *mut ::libc::c_void> = - Some(libcc2rs::calloc_unsafe as unsafe fn(usize, usize) -> *mut ::libc::c_void); + Some(libcc2rs::calloc_unsafe); let mut __do_while = true; 'loop_: while __do_while || (0 != 0) { __do_while = false; diff --git a/tests/unit/out/unsafe/no_direct_callee.rs b/tests/unit/out/unsafe/no_direct_callee.rs index 143e065e..311d4c17 100644 --- a/tests/unit/out/unsafe/no_direct_callee.rs +++ b/tests/unit/out/unsafe/no_direct_callee.rs @@ -21,6 +21,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - assert!(((unsafe { test_1(Some(test1_0 as unsafe fn() -> bool),) }) == (1))); + assert!(((unsafe { test_1(Some(test1_0),) }) == (1))); return 0; } diff --git a/tests/unit/out/unsafe/qsort_bsearch.rs b/tests/unit/out/unsafe/qsort_bsearch.rs index d1c9ea7b..c3fa5eb6 100644 --- a/tests/unit/out/unsafe/qsort_bsearch.rs +++ b/tests/unit/out/unsafe/qsort_bsearch.rs @@ -22,14 +22,13 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *mut i32 as *mut ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( - |__f| { - std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(__f as *const ()) - }, - ), + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ); let mut i: i32 = 0; 'loop_: while ((((i) < (7)) as i32) != 0) { @@ -42,14 +41,13 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( - |__f| { - std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(__f as *const ()) - }, - ), + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ) as *mut i32); assert!((((!((hit).is_null())) as i32) != 0)); assert!(((((*hit) == (7)) as i32) != 0)); @@ -59,14 +57,13 @@ unsafe fn main_0() -> i32 { (arr.as_mut_ptr() as *const i32 as *const ::libc::c_void), 8_usize, ::std::mem::size_of::(), - Some(cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32).map( - |__f| { - std::mem::transmute::< - *const (), - unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, - >(__f as *const ()) - }, - ), + Some(std::mem::transmute::< + *const (), + unsafe extern "C" fn(*const ::libc::c_void, *const ::libc::c_void) -> i32, + >( + (cmp_int_0 as unsafe fn(*const ::libc::c_void, *const ::libc::c_void) -> i32) + as *const (), + )), ) as *mut i32); assert!(((((miss).is_null()) as i32) != 0)); return 0; diff --git a/tests/unit/out/unsafe/string_literal_ptr_init.rs b/tests/unit/out/unsafe/string_literal_ptr_init.rs index ab58d771..c6395ccf 100644 --- a/tests/unit/out/unsafe/string_literal_ptr_init.rs +++ b/tests/unit/out/unsafe/string_literal_ptr_init.rs @@ -34,7 +34,7 @@ pub static mut table_1: [label; 2] = unsafe { }, label { name: ((c"second").as_ptr().cast_mut()).cast_const(), - probe: (Some(probe_two_0 as unsafe fn() -> i32)), + probe: (Some(probe_two_0)), mask: ((1) << (5)), }, ] diff --git a/tests/unit/out/unsafe/va_arg_fn_ptr.rs b/tests/unit/out/unsafe/va_arg_fn_ptr.rs index f6b375d2..a02eea3d 100644 --- a/tests/unit/out/unsafe/va_arg_fn_ptr.rs +++ b/tests/unit/out/unsafe/va_arg_fn_ptr.rs @@ -55,9 +55,10 @@ unsafe fn main_0() -> i32 { ((((unsafe { apply_unary_3( 5, - &[(Some(square_0 as unsafe fn(i32) -> i32) - .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into()], + &[ + (Some(square_0).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], ) }) == (25)) as i32) != 0) @@ -66,9 +67,10 @@ unsafe fn main_0() -> i32 { ((((unsafe { apply_unary_3( 7, - &[(Some(negate_1 as unsafe fn(i32) -> i32) - .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into()], + &[ + (Some(negate_1).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], ) }) == (-7_i32)) as i32) != 0) @@ -78,9 +80,10 @@ unsafe fn main_0() -> i32 { apply_binary_4( 3, 4, - &[(Some(add_2 as unsafe fn(i32, i32) -> i32) - .map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) - .into()], + &[ + (Some(add_2).map_or(::std::ptr::null_mut(), |f| f as *mut ::libc::c_void)) + .into(), + ], ) }) == (7)) as i32) != 0) @@ -92,7 +95,7 @@ unsafe fn main_0() -> i32 { ((&mut dummy as *mut i32) as *mut i32 as *mut ::libc::c_void); let _extra: *mut ::libc::c_void = ((&mut dummy as *mut i32) as *mut i32 as *mut ::libc::c_void); - not_supported_5(_ctx, Some(square_0 as unsafe fn(i32) -> i32), _extra) + not_supported_5(_ctx, Some(square_0), _extra) }) == (-3_i32)) as i32) != 0) ); diff --git a/tests/unit/out/unsafe/void_cast.rs b/tests/unit/out/unsafe/void_cast.rs index 0d6b373e..aea1827d 100644 --- a/tests/unit/out/unsafe/void_cast.rs +++ b/tests/unit/out/unsafe/void_cast.rs @@ -84,10 +84,10 @@ unsafe fn main_0() -> i32 { assert!(((chosen) == (123))); &(bump_and_return_4); assert!(((side_effect_counter_3) == (2))); - &(Some(bump_and_return_4 as unsafe fn() -> i32)); + &(Some(bump_and_return_4)); assert!(((side_effect_counter_3) == (2))); &(std::mem::transmute:: i32>, Option i32>>( - (Some(bump_and_return_4 as unsafe fn() -> i32)), + (Some(bump_and_return_4)), )); assert!(((side_effect_counter_3) == (2))); let mut storage: i32 = 11; From 5af540018a40d0af6f3cfa5845649dc5455f34e5 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 15:38:03 +0100 Subject: [PATCH 10/43] Translate lambdas as struct + operator call --- cpp2rust/converter/converter.cpp | 201 +++++++++++------- cpp2rust/converter/converter.h | 19 +- cpp2rust/converter/converter_lib.cpp | 70 +++++- cpp2rust/converter/converter_lib.h | 7 + cpp2rust/converter/mapper.cpp | 2 +- .../converter/models/converter_refcount.cpp | 72 +++++-- .../converter/models/converter_refcount.h | 11 +- tests/unit/out/refcount/anonymous-struct.rs | 60 +++--- tests/unit/out/refcount/anonymous-struct_c.rs | 56 ++--- tests/unit/out/refcount/anonymous_enum.rs | 6 +- tests/unit/out/refcount/anonymous_enum_c.rs | 6 +- tests/unit/out/refcount/fn_ptr_default_arg.rs | 43 +++- .../unit/out/refcount/lambda_capture_pass.rs | 98 +++++++-- tests/unit/out/refcount/lambda_nested.rs | 85 ++++++-- .../refcount/local_anon_struct_collision.rs | 108 +++++----- tests/unit/out/refcount/stable_sort.rs | 44 +++- .../out/refcount/union_pointer_pun_address.rs | 76 +++---- .../union_pointer_pun_writethrough.rs | 72 +++---- tests/unit/out/unsafe/anonymous-struct.rs | 12 +- tests/unit/out/unsafe/anonymous-struct_c.rs | 12 +- tests/unit/out/unsafe/anonymous_enum.rs | 6 +- tests/unit/out/unsafe/anonymous_enum_c.rs | 6 +- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 19 +- tests/unit/out/unsafe/lambda_capture_pass.rs | 78 +++---- tests/unit/out/unsafe/lambda_nested.rs | 62 ++++-- .../out/unsafe/local_anon_struct_collision.rs | 24 +-- tests/unit/out/unsafe/stable_sort.rs | 26 ++- .../out/unsafe/union_pointer_pun_address.rs | 22 +- .../unsafe/union_pointer_pun_writethrough.rs | 22 +- 29 files changed, 858 insertions(+), 467 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index a5c0a469..3fd03729 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -197,21 +197,6 @@ bool Converter::VisitBuiltinType(clang::BuiltinType *type) { bool Converter::VisitRecordType(clang::RecordType *type) { auto *decl = type->getDecl(); - if (auto lambda = clang::dyn_cast(decl)) { - if (lambda->isLambda()) { - if (in_function_formals_) { - StrCat( - ConvertFunctionPointerType(lambda->getLambdaCallOperator() - ->getType() - ->getAs(), - FnProtoType::LambdaCallOperator)); - } else { - StrCat('_'); - } - return false; - } - } - StrCat(GetRecordName(decl)); Mapper::AddRuleForUserDefinedType(decl); return false; @@ -308,10 +293,8 @@ bool Converter::VisitReferenceType(clang::ReferenceType *type) { } std::string -Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind) { - std::string result = - (kind == FnProtoType::LambdaCallOperator ? "impl Fn(" : "fn("); +Converter::ConvertFunctionPointerType(const clang::FunctionProtoType *proto) { + std::string result = "fn("; for (auto p_ty : proto->param_types()) { result += ToString(p_ty); result += ','; @@ -363,6 +346,10 @@ bool Converter::VisitTranslationUnitDecl(clang::TranslationUnitDecl *decl) { if (IsUserDefinedDecl(child) && (IsInMainFile(child) || !decl_ids_.contains(GetID(child)))) { Convert(child); + if (!hoisted_records_.empty()) { + StrCat(hoisted_records_); + hoisted_records_.clear(); + } } } return false; @@ -539,20 +526,6 @@ bool Converter::ConvertVarDeclSkipInit(clang::VarDecl *decl) { return true; } -bool Converter::ConvertLambdaVarDecl(clang::VarDecl *decl) { - if (decl->getType()->isFunctionPointerType()) { - return false; - } - if (decl->hasInit()) { - if (clang::isa( - decl->getInit()->IgnoreUnlessSpelledInSource())) { - // Lambdas are inlined at the call site. - return true; - } - } - return false; -} - void Converter::ConvertVarDeclInitializer(clang::VarDecl *decl) { if (decl->hasInit()) { ConvertVarInit(decl->getType(), decl->getInit()); @@ -606,10 +579,6 @@ void Converter::ConvertGlobalVarDecl(clang::VarDecl *decl) { } bool Converter::VisitVarDecl(clang::VarDecl *decl) { - if (ConvertLambdaVarDecl(decl)) { - return false; - } - if (IsGlobalVar(decl)) { ConvertGlobalVarDecl(decl); } else { @@ -987,6 +956,9 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { } EmitRustStructOrUnion(decl); + if (decl->isLambda()) { + ConvertLambdaCallable(decl); + } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { return false; @@ -1257,6 +1229,12 @@ bool Converter::VisitCompoundStmt(clang::CompoundStmt *stmt) { bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) { for (auto *decl : stmt->decls()) { + if (clang::isa(decl)) { + Buffer buf(*this); + Convert(decl); + hoisted_records_ += std::move(buf).str(); + continue; + } Convert(decl); StrCat(token::kSemiColon); } @@ -2896,6 +2874,10 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { } bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { + if (auto *capture = LambdaCaptureAccess(expr->getDecl())) { + Convert(capture); + return false; + } auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); @@ -2916,20 +2898,6 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (auto var_decl = clang::dyn_cast(decl)) { - if (!var_decl->getType()->isFunctionPointerType()) { - if (auto init = var_decl->getInit()) { - if (auto lambda = clang::dyn_cast( - init->IgnoreUnlessSpelledInSource())) { - PushParen paren(*this); - VisitLambdaExpr(lambda); - computed_expr_type_ = ComputedExprType::FreshValue; - return false; - } - } - } - } - if (!decl->getType()->getAs() && isAddrOf()) { StrCat(token::kRef, decl->getType().isConstQualified() ? "" : keyword_mut_, str); @@ -3084,7 +3052,8 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, const clang::CXXMethodDecl *method) { - if (clang::isa(base->IgnoreParenImpCasts())) { + if (clang::isa(base->IgnoreParenImpCasts()) && + !IsCapturedThis(base)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); ufcs_receiver_ = in_ctor ? "&mut this" : keyword::kSelfValue; @@ -3158,8 +3127,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } auto *base = expr->getBase(); - bool base_is_this = - clang::isa(base->IgnoreCasts()) && !ThisIsRustPtr(); + bool base_is_this = clang::isa(base->IgnoreCasts()) && + !ThisIsRustPtr() && !IsCapturedThis(base); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); if (base_is_this) { StrCat(clang::isa(curr_function_) @@ -3184,6 +3153,10 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { + if (IsCapturedThis(expr)) { + Convert(LambdaCaptureAccess(nullptr)); + return false; + } if (clang::isa(curr_function_)) { StrCat("&raw mut this"); } else { @@ -3603,24 +3576,112 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { } bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { - if (isAddrOf() && expr->capture_size() == 0) { - StrCat("Some"); - } + auto *record = expr->getLambdaClass(); + ConvertLambdaClass(record); PushParen paren(*this); - StrCat('|'); - for (auto p : expr->getLambdaClass()->getLambdaCallOperator()->parameters()) { - StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()), - token::kComma); - } - StrCat("| {"); - EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator()); - PushCurrFunction push_fn(*this, - expr->getLambdaClass()->getLambdaCallOperator()); - ConvertFunctionBody(curr_function_); - StrCat('}'); + StrCat(GetRecordName(record)); + { + PushBrace brace(*this); + auto init = expr->capture_init_begin(); + for (auto *field : record->fields()) { + StrCat(GetNamedDeclAsString(field), token::kColon); + ConvertVarInit(field->getType(), *init++); + StrCat(token::kComma); + } + } + computed_expr_type_ = ComputedExprType::FreshValue; return false; } +void Converter::ConvertLambdaClass(clang::CXXRecordDecl *decl) { + Buffer buf(*this); + std::vector saved_expr_kinds; + saved_expr_kinds.swap(curr_expr_kind_); + VisitCXXRecordDecl(decl); + curr_expr_kind_.swap(saved_expr_kinds); + hoisted_records_ += std::move(buf).str(); +} + +std::string Converter::LambdaCallParams(const clang::CXXMethodDecl *op, + std::string &args) { + std::string params; + unsigned i = 0; + for (auto *p : op->parameters()) { + auto name = std::format("a{}", ++i); + params += std::format("{}: {},", name, ToString(p->getType())); + args += name + ','; + } + return params; +} + +static constexpr unsigned kMaxCallableArity = 3; + +void Converter::ConvertLambdaCallable(clang::CXXRecordDecl *decl) { + auto *op = decl->getLambdaCallOperator(); + if (!op->isConst() || op->getNumParams() > kMaxCallableArity) { + return; + } + std::string args; + auto params = LambdaCallParams(op, args); + auto ret = op->getReturnType()->isVoidType() ? std::string("()") + : ToString(op->getReturnType()); + StrCat(keyword::kImpl, std::format("Callable{}<", op->getNumParams())); + for (auto *p : op->parameters()) { + StrCat(ToString(p->getType()), token::kComma); + } + StrCat(ret, "> for", GetRecordName(decl)); + PushBrace impl_brace(*this); + StrCat(keyword::kFn, "call(&self,", params, ")", token::kArrow, ret); + PushBrace fn_brace(*this); + StrCat(LambdaCallBody(decl, "self.clone()", args)); +} + +std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, + std::string_view value, + std::string_view args) { + auto *op = decl->getLambdaCallOperator(); + return std::format( + "let __this: {0} = {1}; unsafe {{ {2}::{3}(&__this, {4}) }}", + GetRecordName(decl), value, GetUFCSName(op), GetMethodName(op), args); +} + +void Converter::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { + auto *decl = expr->getLambdaClass(); + ConvertLambdaClass(decl); + std::string args; + auto params = LambdaCallParams(decl->getLambdaCallOperator(), args); + StrCat("Some(|", params, "| {", + LambdaCallBody(decl, GetRecordName(decl) + " {}", args), "})"); + computed_expr_type_ = ComputedExprType::FreshValue; +} + +clang::MemberExpr *Converter::LambdaCaptureAccess(const clang::ValueDecl *var) { + auto *lambda = GetLambdaOf(curr_function_); + if (!lambda) { + return nullptr; + } + auto *field = GetLambdaCaptureField(lambda, var); + if (!field) { + return nullptr; + } + auto *this_expr = clang::CXXThisExpr::Create( + ctx_, {}, lambda->getLambdaCallOperator()->getThisType(), true); + return clang::MemberExpr::CreateImplicit( + ctx_, this_expr, true, field, field->getType().getNonReferenceType(), + clang::VK_LValue, clang::OK_Ordinary); +} + +bool Converter::IsCapturedThis(const clang::Expr *expr) const { + auto *this_expr = + clang::dyn_cast(expr->IgnoreParenImpCasts()); + if (!this_expr) { + return false; + } + auto *lambda = GetLambdaOf(curr_function_); + return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda && + GetLambdaCaptureField(lambda, nullptr); +} + bool Converter::VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr) { if (auto arr_ty = clang::dyn_cast( expr->getType()->getCanonicalTypeInternal().getTypePtr())) { @@ -4032,9 +4093,7 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) { if (qual_type->isFunctionPointerType()) { if (auto *lambda = clang::dyn_cast( expr->IgnoreUnlessSpelledInSource())) { - PushExprKind push(*this, ExprKind::AddrOf); - PushInitType init_type(*this, qual_type); - VisitLambdaExpr(lambda); + ConvertLambdaAsFnPtr(lambda); return; } } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index f2cb8c7b..9b237c72 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -67,11 +67,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitPointerType(clang::PointerType *type); - enum class FnProtoType { LambdaCallOperator, FnPtr }; - virtual std::string - ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind = FnProtoType::FnPtr); + ConvertFunctionPointerType(const clang::FunctionProtoType *proto); virtual bool VisitDecayedType(clang::DecayedType *type); @@ -111,8 +108,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool ConvertVarDeclSkipInit(clang::VarDecl *decl); - virtual bool ConvertLambdaVarDecl(clang::VarDecl *decl); - bool VisitRecordDecl(clang::RecordDecl *decl); virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl); @@ -422,6 +417,16 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitConstantExpr(clang::ConstantExpr *expr); virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); + virtual void ConvertLambdaClass(clang::CXXRecordDecl *decl); + virtual void ConvertLambdaCallable(clang::CXXRecordDecl *decl); + virtual void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr); + virtual std::string LambdaCallBody(const clang::CXXRecordDecl *decl, + std::string_view value, + std::string_view args); + std::string LambdaCallParams(const clang::CXXMethodDecl *op, + std::string &args); + clang::MemberExpr *LambdaCaptureAccess(const clang::ValueDecl *var); + bool IsCapturedThis(const clang::Expr *expr) const; virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); virtual bool VisitCXXScalarValueInitExpr(clang::CXXScalarValueInitExpr *expr); @@ -883,6 +888,8 @@ class Converter : public clang::RecursiveASTVisitor { // translation units. static std::map methods_on_ptr_; + std::string hoisted_records_; + enum class ExprKind : uint8_t { Callee, LValue, diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 7a031734..cf892b49 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -153,7 +153,9 @@ bool IsUserDefinedDecl(const clang::Decl *decl) { const auto &ctx = decl->getASTContext(); const auto &src_mgr = ctx.getSourceManager(); const auto src_loc = decl->getLocation(); - return !decl->getBeginLoc().isInvalid() && !decl->isImplicit() && + auto *cxx = clang::dyn_cast(decl); + bool implicit = decl->isImplicit() && !(cxx && cxx->isLambda()); + return !decl->getBeginLoc().isInvalid() && !implicit && !src_mgr.isInSystemHeader(src_loc) && !src_mgr.isInSystemMacro(src_loc); } @@ -358,6 +360,9 @@ bool IsPassThroughConstructor(const clang::CXXConstructorDecl *ctor) { } bool IsConvertibleCXXRecordDecl(const clang::CXXRecordDecl *decl) { + if (decl->isLambda()) { + return decl->getLambdaCallOperator()->hasBody(); + } return decl->isThisDeclarationADefinition() && std::all_of( decl->method_begin(), decl->method_end(), [](auto *method) { @@ -591,6 +596,43 @@ static size_t GetDeclId(const clang::NamedDecl *decl, bool internal) { return type_mapping.try_emplace(key, type_mapping.size()).first->second; } +const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field) { + auto *cxx = clang::dyn_cast(field->getParent()); + if (!cxx || !cxx->isLambda()) { + return nullptr; + } + auto capture = cxx->captures_begin(); + for (auto *f : cxx->fields()) { + assert(capture != cxx->captures_end()); + if (f == field) { + return capture; + } + ++capture; + } + assert(0 && "field is not a lambda capture"); + return nullptr; +} + +clang::FieldDecl *GetLambdaCaptureField(const clang::CXXRecordDecl *lambda, + const clang::ValueDecl *var) { + llvm::DenseMap captures; + clang::FieldDecl *this_capture = nullptr; + lambda->getCaptureFields(captures, this_capture); + if (!var) { + return this_capture; + } + auto it = captures.find(var); + return it == captures.end() ? nullptr : it->second; +} + +const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn) { + auto *method = clang::dyn_cast_or_null(fn); + if (!method || !method->getParent()->isLambda()) { + return nullptr; + } + return method->getParent(); +} + std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); @@ -598,6 +640,21 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { name = GetFunctionBaseName(fn); } + if (auto *cxx = clang::dyn_cast(decl); + cxx && cxx->isLambda()) { + return std::format("lambda_{}", + type_mapping.try_emplace(GetID(cxx), type_mapping.size()) + .first->second); + } + if (auto *field = clang::dyn_cast(decl)) { + if (auto *capture = GetLambdaCapture(field)) { + if (capture->capturesThis()) { + return "this_"; + } + return GetNamedDeclAsString(capture->getCapturedVar()); + } + } + // Anonymous record or enum if (name.empty() && (clang::isa(decl) || clang::isa(decl) || @@ -814,13 +871,7 @@ bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) { method && method->isDefaulted() && IsComparisonOperator(method)) { return IsUserDefinedDecl(method->getParent()); } - if (!callee->isUserProvided() || !IsUserDefinedDecl(callee)) { - return false; - } - if (const auto *method = clang::dyn_cast(callee)) { - return !method->getParent()->isLambda(); - } - return true; + return callee->isUserProvided() && IsUserDefinedDecl(callee); } std::string GetFunctionBaseName(const clang::FunctionDecl *decl) { @@ -924,8 +975,7 @@ bool IsMethodOnPtr(const clang::CXXMethodDecl *method) { if (method->isImplicit() && !IsComparisonOperator(method)) { return false; } - if (!IsUserDefinedDecl(method->getParent()) || - method->getParent()->isLambda()) { + if (!IsUserDefinedDecl(method->getParent())) { return false; } if (auto *definition = method->getDefinition(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index df20998c..7ebbd795 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -165,6 +165,13 @@ bool RecordNeedsDestruction(const clang::CXXRecordDecl *decl); clang::Expr *ToAddrOf(clang::ASTContext &ctx, clang::Expr *expr); +const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field); + +clang::FieldDecl *GetLambdaCaptureField(const clang::CXXRecordDecl *lambda, + const clang::ValueDecl *var); + +const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); + std::vector GetNestedStructs(const clang::CXXRecordDecl *decl); diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index b5ad34e4..318b5ca5 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -872,7 +872,7 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { if (auto cxx_record_decl = qual_type->getAsCXXRecordDecl()) { if (cxx_record_decl->isLambda()) { - return ToString(cxx_record_decl->getLambdaCallOperator()); + return GetNamedDeclAsString(cxx_record_decl); } } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 625e62fc..1c1e1c04 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -247,9 +247,9 @@ std::string ConverterRefCount::BuildFnAdapter( } std::string ConverterRefCount::ConvertFunctionPointerType( - const clang::FunctionProtoType *proto, FnProtoType kind) { + const clang::FunctionProtoType *proto) { PushConversionKind push(*this, ConversionKind::Unboxed); - return Converter::ConvertFunctionPointerType(proto, kind); + return Converter::ConvertFunctionPointerType(proto); } bool ConverterRefCount::VisitPointerType(clang::PointerType *type) { @@ -691,10 +691,6 @@ void ConverterRefCount::ConvertVaListVarDecl(clang::VarDecl *decl) { StrCat(GetNamedDeclAsString(decl), token::kColon, "Value"); } -bool ConverterRefCount::ConvertLambdaVarDecl(clang::VarDecl *decl) { - return false; -} - bool ConverterRefCount::ConvertVarDeclSkipInit(clang::VarDecl *decl) { bool unboxed = in_function_formals_; PushConversionKind push(*this, unboxed ? ConversionKind::Unboxed @@ -807,6 +803,10 @@ bool ConverterRefCount::VisitConditionalOperator( } bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { + if (auto *capture = LambdaCaptureAccess(expr->getDecl())) { + Convert(capture); + return false; + } if (isAddrOf()) { clang::Expr *addrof_op = ToAddrOf(ctx_, expr); if (auto str = GetMappedAsString(addrof_op); !str.empty()) { @@ -2085,16 +2085,10 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type, clang::Expr *expr) { if (auto lambda = clang::dyn_cast( - expr->IgnoreUnlessSpelledInSource())) { + expr->IgnoreUnlessSpelledInSource()); + lambda && qual_type->isFunctionPointerType()) { Buffer buf(*this); - PushConversionKind push(*this, ConversionKind::Unboxed); - if (qual_type->isFunctionPointerType() && lambda->capture_size() == 0) { - StrCat("FnPtr::new("); - VisitLambdaExpr(lambda); - StrCat(')'); - } else { - VisitLambdaExpr(lambda); - } + ConvertLambdaAsFnPtr(lambda); return std::move(buf).str(); } @@ -2684,7 +2678,8 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow, } bool base_is_pointer = is_arrow && !clang::isa( base->IgnoreParenImpCasts()); - if (clang::isa(base->IgnoreParenImpCasts())) { + if (clang::isa(base->IgnoreParenImpCasts()) && + !IsCapturedThis(base)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2860,8 +2855,11 @@ void ConverterRefCount::ConvertCXXConstructorBody( StrCat("Rc::try_unwrap(__this).ok().unwrap().into_inner()"); } -bool ConverterRefCount::VisitCXXThisExpr( - [[maybe_unused]] clang::CXXThisExpr *expr) { +bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { + if (IsCapturedThis(expr)) { + Convert(LambdaCaptureAccess(nullptr)); + return false; + } bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2872,4 +2870,42 @@ bool ConverterRefCount::VisitCXXThisExpr( computed_expr_type_ = ComputedExprType::Pointer; return false; } + +bool ConverterRefCount::VisitLambdaExpr(clang::LambdaExpr *expr) { + PushConversionKind push(*this, ConversionKind::FullRefCount); + return Converter::VisitLambdaExpr(expr); +} + +void ConverterRefCount::ConvertLambdaCallable(clang::CXXRecordDecl *decl) { + PushConversionKind push(*this, ConversionKind::Unboxed); + Converter::ConvertLambdaCallable(decl); +} + +void ConverterRefCount::ConvertLambdaClass(clang::CXXRecordDecl *decl) { + std::vector saved_conversion_kinds({ConversionKind::Unboxed}); + saved_conversion_kinds.swap(conversion_kind_); + Converter::ConvertLambdaClass(decl); + conversion_kind_.swap(saved_conversion_kinds); +} + +void ConverterRefCount::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { + auto *decl = expr->getLambdaClass(); + ConvertLambdaClass(decl); + PushConversionKind push(*this, ConversionKind::Unboxed); + std::string args; + auto params = LambdaCallParams(decl->getLambdaCallOperator(), args); + StrCat("FnPtr::new(|", params, "| {", + LambdaCallBody(decl, GetRecordName(decl) + " {}", args), "})"); + computed_expr_type_ = ComputedExprType::FreshValue; +} + +std::string ConverterRefCount::LambdaCallBody(const clang::CXXRecordDecl *decl, + std::string_view value, + std::string_view args) { + auto *op = decl->getLambdaCallOperator(); + return std::format("let __this: Value<{0}> = Rc::new(RefCell::new({1})); " + "{2}::{3}(&__this.as_pointer(), {4})", + GetRecordName(decl), value, GetUFCSName(op), + GetMethodName(op), args); +} } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 790f7530..8a65b674 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -23,8 +23,7 @@ class ConverterRefCount final : public Converter { bool VisitPointerType(clang::PointerType *type) override; std::string - ConvertFunctionPointerType(const clang::FunctionProtoType *proto, - FnProtoType kind = FnProtoType::FnPtr) override; + ConvertFunctionPointerType(const clang::FunctionProtoType *proto) override; bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override; @@ -88,7 +87,13 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; - bool ConvertLambdaVarDecl(clang::VarDecl *decl) override; + bool VisitLambdaExpr(clang::LambdaExpr *expr) override; + void ConvertLambdaClass(clang::CXXRecordDecl *decl) override; + void ConvertLambdaCallable(clang::CXXRecordDecl *decl) override; + void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) override; + std::string LambdaCallBody(const clang::CXXRecordDecl *decl, + std::string_view value, + std::string_view args) override; bool VisitDeclRefExpr(clang::DeclRefExpr *expr) override; diff --git a/tests/unit/out/refcount/anonymous-struct.rs b/tests/unit/out/refcount/anonymous-struct.rs index 64d82f14..3ef5f74c 100644 --- a/tests/unit/out/refcount/anonymous-struct.rs +++ b/tests/unit/out/refcount/anonymous-struct.rs @@ -321,36 +321,6 @@ fn main_0() -> i32 { .borrow()) == 11) ); - #[derive(Default)] - pub struct anon_6 { - pub x: Value, - pub z: Value, - } - impl Clone for anon_6 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x: Rc::new(RefCell::new((*self.x.borrow()))), - z: Rc::new(RefCell::new((*self.z.borrow()))), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } - } - impl ByteRepr for anon_6 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.z.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let s: Value = Rc::new(RefCell::new(::default())); (*(*s.borrow()).x.borrow_mut()) = 1; (*(*s.borrow()).z.borrow_mut()) = 2; @@ -368,3 +338,33 @@ fn main_0() -> i32 { ); return 0; } +#[derive(Default)] +pub struct anon_6 { + pub x: Value, + pub z: Value, +} +impl Clone for anon_6 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + z: Rc::new(RefCell::new((*self.z.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.z.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} diff --git a/tests/unit/out/refcount/anonymous-struct_c.rs b/tests/unit/out/refcount/anonymous-struct_c.rs index 065fd2cc..5473ea07 100644 --- a/tests/unit/out/refcount/anonymous-struct_c.rs +++ b/tests/unit/out/refcount/anonymous-struct_c.rs @@ -290,34 +290,6 @@ fn main_0() -> i32 { == 11) as i32) != 0) ); - #[derive(Default)] - pub struct anon_6 { - pub x: Value, - pub z: Value, - } - impl Clone for anon_6 { - fn clone(&self) -> Self { - Self { - x: Rc::new(RefCell::new((*self.x.borrow()).clone())), - z: Rc::new(RefCell::new((*self.z.borrow()).clone())), - } - } - } - impl ByteRepr for anon_6 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.z.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let s: Value = >::default(); (*(*s.borrow()).x.borrow_mut()) = 1; (*(*s.borrow()).z.borrow_mut()) = 2; @@ -335,3 +307,31 @@ fn main_0() -> i32 { ); return 0; } +#[derive(Default)] +pub struct anon_6 { + pub x: Value, + pub z: Value, +} +impl Clone for anon_6 { + fn clone(&self) -> Self { + Self { + x: Rc::new(RefCell::new((*self.x.borrow()).clone())), + z: Rc::new(RefCell::new((*self.z.borrow()).clone())), + } + } +} +impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.z.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index 2e954d73..f630eea9 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -78,9 +78,6 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32))); assert!(((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32))); assert!(((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32))); @@ -95,3 +92,6 @@ fn main_0() -> i32 { assert!((((*(*w.borrow()).field.borrow()) as i32) == (anon_2_FIELD_B as i32))); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 82240be2..dd356a26 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -74,9 +74,6 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)) as i32) != 0)); @@ -97,3 +94,6 @@ fn main_0() -> i32 { ); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 0348fc82..fdb3093a 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,12 +26,43 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - }), - ))); + let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new(|a1: i32| { + let __this: Value = Rc::new(RefCell::new(lambda_2 {})); + lambda_2Impl::operator_call(&__this.as_pointer(), a1) + }))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } +#[derive(Default)] +pub struct lambda_2 {} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self {})); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_2Impl::operator_call(&__this.as_pointer(), a1) + } +} +pub trait lambda_2Impl { + fn operator_call(&self, x: i32) -> i32; +} +impl lambda_2Impl for Ptr { + fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_capture_pass.rs index 378003b7..da55c3a6 100644 --- a/tests/unit/out/refcount/lambda_capture_pass.rs +++ b/tests/unit/out/refcount/lambda_capture_pass.rs @@ -6,37 +6,105 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -pub fn apply_0(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { - let fn_: Value<_> = Rc::new(RefCell::new(fn_)); +pub fn apply_0(fn_: lambda_1, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return ({ (*fn_.borrow_mut())((*x.borrow())) }); + return ({ lambda_1Impl::operator_call(&fn_.as_pointer(), (*x.borrow())) }); } -pub fn apply_1(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { - let fn_: Value<_> = Rc::new(RefCell::new(fn_)); +pub fn apply_2(fn_: lambda_3, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return ({ (*fn_.borrow_mut())((*x.borrow())) }); + return ({ lambda_3Impl::operator_call(&fn_.as_pointer(), (*x.borrow())) }); } pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { let base: Value = Rc::new(RefCell::new(10)); - let add_base: Value<_> = Rc::new(RefCell::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return ((*x.borrow()) + (*base.borrow())); + let add_base: Value = Rc::new(RefCell::new( + (lambda_1 { + base: base.as_pointer(), }), )); assert!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 15)); (*base.borrow_mut()) = 100; assert!((({ apply_0((*add_base.borrow()).clone(), 5,) }) == 105)); let factor: Value = Rc::new(RefCell::new(3)); - let scale: Value<_> = Rc::new(RefCell::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return ((*x.borrow()) * (*factor.borrow())); + let scale: Value = Rc::new(RefCell::new( + (lambda_3 { + factor: Rc::new(RefCell::new((*factor.borrow()))), }), )); - assert!((({ apply_1((*scale.borrow()).clone(), 4,) }) == 12)); + assert!((({ apply_2((*scale.borrow()).clone(), 4,) }) == 12)); return 0; } +#[derive(Default)] +pub struct lambda_1 { + base: Ptr, +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + base: (self.base).clone(), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_1 {} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_1Impl::operator_call(&__this.as_pointer(), a1) + } +} +#[derive(Default)] +pub struct lambda_3 { + factor: Value, +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + factor: Rc::new(RefCell::new((*self.factor.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.factor.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + factor: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_3Impl::operator_call(&__this.as_pointer(), a1) + } +} +pub trait lambda_1Impl { + fn operator_call(&self, x: i32) -> i32; +} +impl lambda_1Impl for Ptr { + fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + ((*(*self).upgrade().deref()).base.read())); + } +} +pub trait lambda_3Impl { + fn operator_call(&self, x: i32) -> i32; +} +impl lambda_3Impl for Ptr { + fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*(*(*self).upgrade().deref()).factor.borrow())); + } +} diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index a1e03c77..765219f6 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -11,20 +11,77 @@ pub fn main() { } fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(10)); - let outer: Value<_> = Rc::new(RefCell::new( - (|y: i32| { - let y: Value = Rc::new(RefCell::new(y)); - let inner: Value<_> = Rc::new(RefCell::new( - (|z: i32| { - let z: Value = Rc::new(RefCell::new(z)); - return (((*x.borrow()) + (*y.borrow())) + (*z.borrow())); - }), - )); - return ({ (*inner.borrow_mut())(1) }); - }), - )); - assert!((({ (*outer.borrow_mut())(20,) }) == 31)); + let outer: Value = Rc::new(RefCell::new((lambda_0 { x: x.as_pointer() }))); + assert!((({ lambda_0Impl::operator_call(&outer.as_pointer(), 20,) }) == 31)); (*x.borrow_mut()) = 100; - assert!((({ (*outer.borrow_mut())(20,) }) == 121)); + assert!((({ lambda_0Impl::operator_call(&outer.as_pointer(), 20,) }) == 121)); return 0; } +#[derive(Default)] +pub struct lambda_1 { + x: Ptr, + y: Value, +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: (self.x).clone(), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_1 {} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_1Impl::operator_call(&__this.as_pointer(), a1) + } +} +#[derive(Default)] +pub struct lambda_0 { + x: Ptr, +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: (self.x).clone(), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_0 {} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_0Impl::operator_call(&__this.as_pointer(), a1) + } +} +pub trait lambda_0Impl { + fn operator_call(&self, y: i32) -> i32; +} +impl lambda_0Impl for Ptr { + fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_1 { + x: ((*(*self).upgrade().deref()).x).clone(), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_1Impl::operator_call(&inner.as_pointer(), 1) }); + } +} +pub trait lambda_1Impl { + fn operator_call(&self, z: i32) -> i32; +} +impl lambda_1Impl for Ptr { + fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return ((((*(*self).upgrade().deref()).x.read()) + + (*(*(*self).upgrade().deref()).y.borrow())) + + (*z.borrow())); + } +} diff --git a/tests/unit/out/refcount/local_anon_struct_collision.rs b/tests/unit/out/refcount/local_anon_struct_collision.rs index d717fab0..f9deb5f2 100644 --- a/tests/unit/out/refcount/local_anon_struct_collision.rs +++ b/tests/unit/out/refcount/local_anon_struct_collision.rs @@ -7,73 +7,73 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn first_0() -> i32 { - #[derive(Default)] - pub struct anon_1 { - pub x: Value, - pub y: Value, - } - impl Clone for anon_1 { - fn clone(&self) -> Self { - Self { - x: Rc::new(RefCell::new((*self.x.borrow()).clone())), - y: Rc::new(RefCell::new((*self.y.borrow()).clone())), - } - } - } - impl ByteRepr for anon_1 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.y.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let p: Value = >::default(); (*(*p.borrow()).x.borrow_mut()) = 1; (*(*p.borrow()).y.borrow_mut()) = 2; return ((*(*p.borrow()).x.borrow()) + (*(*p.borrow()).y.borrow())); } -pub fn second_2() -> i32 { - #[derive(Default)] - pub struct anon_3 { - pub a: Value, - pub b: Value, - } - impl Clone for anon_3 { - fn clone(&self) -> Self { - Self { - a: Rc::new(RefCell::new((*self.a.borrow()).clone())), - b: Rc::new(RefCell::new((*self.b.borrow()).clone())), - } +#[derive(Default)] +pub struct anon_1 { + pub x: Value, + pub y: Value, +} +impl Clone for anon_1 { + fn clone(&self) -> Self { + Self { + x: Rc::new(RefCell::new((*self.x.borrow()).clone())), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), } } - impl ByteRepr for anon_3 { - fn byte_size() -> usize { - 16 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.a.borrow()).to_bytes(&mut buf[0..8]); - (*self.b.borrow()).to_bytes(&mut buf[8..16]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - a: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), - b: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), - } +} +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), } - }; + } +} +pub fn second_2() -> i32 { let q: Value = >::default(); (*(*q.borrow()).a.borrow_mut()) = 10_i64; (*(*q.borrow()).b.borrow_mut()) = 20_i64; return (((*(*q.borrow()).a.borrow()) + (*(*q.borrow()).b.borrow())) as i32); } +#[derive(Default)] +pub struct anon_3 { + pub a: Value, + pub b: Value, +} +impl Clone for anon_3 { + fn clone(&self) -> Self { + Self { + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + } + } +} +impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..8]); + (*self.b.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 784fbf00..f5d7e452 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -12,14 +12,8 @@ pub fn main() { fn main_0() -> i32 { let arr1: Value> = Rc::new(RefCell::new(Box::new([5, 2, 8, 1, 3]))); { - let fun = |x: Ptr, y: Ptr| { - (|x: i32, y: i32| { - let x: Value = Rc::new(RefCell::new(x)); - let y: Value = Rc::new(RefCell::new(y)); - return ((*x.borrow()) < (*y.borrow())); - }) - .call((x.read()).clone(), (y.read()).clone()) - }; + let fun = + |x: Ptr, y: Ptr| (lambda_0 {}).call((x.read()).clone(), (y.read()).clone()); (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) .offset((5) as isize) @@ -29,3 +23,37 @@ fn main_0() -> i32 { }; return 0; } +#[derive(Default)] +pub struct lambda_0 {} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self {})); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + let __this: Value = Rc::new(RefCell::new(self.clone())); + lambda_0Impl::operator_call(&__this.as_pointer(), a1, a2) + } +} +pub trait lambda_0Impl { + fn operator_call(&self, x: i32, y: i32) -> bool; +} +impl lambda_0Impl for Ptr { + fn operator_call(&self, x: i32, y: i32) -> bool { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + return ((*x.borrow()) < (*y.borrow())); + } +} diff --git a/tests/unit/out/refcount/union_pointer_pun_address.rs b/tests/unit/out/refcount/union_pointer_pun_address.rs index 4a0cb1bb..464f78bd 100644 --- a/tests/unit/out/refcount/union_pointer_pun_address.rs +++ b/tests/unit/out/refcount/union_pointer_pun_address.rs @@ -65,44 +65,6 @@ fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(node_a { n: Rc::new(RefCell::new(123)), })); - pub struct anon_0 { - __bytes: Value>, - } - impl anon_0 { - pub fn to_a(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - pub fn to_b(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - } - impl Clone for anon_0 { - fn clone(&self) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), - } - } - } - impl Default for anon_0 { - fn default() -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), - } - } - } - impl ByteRepr for anon_0 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - buf.copy_from_slice(&self.__bytes.borrow()); - } - fn from_bytes(buf: &[u8]) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from(buf))), - } - } - }; let ptr: Value = >::default(); (*ptr.borrow_mut()).to_a().write((a.as_pointer())); let out: Value> = Rc::new(RefCell::new(((*ptr.borrow()).to_b().read()).clone())); @@ -115,3 +77,41 @@ fn main_0() -> i32 { ); return 0; } +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn to_a(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn to_b(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } +} diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs index dd2f9369..3d470727 100644 --- a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -11,47 +11,47 @@ pub fn main() { } fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new((-1_i32 as i64))); - pub struct anon_0 { - __bytes: Value>, + let pp: Value = >::default(); + (*pp.borrow_mut()).as_signed().write((x.as_pointer())); + ((*pp.borrow()).as_unsigned().read()).write(42_u64); + assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); + return 0; +} +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn as_unsigned(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - impl anon_0 { - pub fn as_unsigned(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - pub fn as_signed(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } + pub fn as_signed(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - impl Clone for anon_0 { - fn clone(&self) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), - } +} +impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), } } - impl Default for anon_0 { - fn default() -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), - } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), } } - impl ByteRepr for anon_0 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - buf.copy_from_slice(&self.__bytes.borrow()); - } - fn from_bytes(buf: &[u8]) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from(buf))), - } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), } - }; - let pp: Value = >::default(); - (*pp.borrow_mut()).as_signed().write((x.as_pointer())); - ((*pp.borrow()).as_unsigned().read()).write(42_u64); - assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); - return 0; + } } diff --git a/tests/unit/out/unsafe/anonymous-struct.rs b/tests/unit/out/unsafe/anonymous-struct.rs index 59c69a7f..705075f8 100644 --- a/tests/unit/out/unsafe/anonymous-struct.rs +++ b/tests/unit/out/unsafe/anonymous-struct.rs @@ -95,12 +95,6 @@ unsafe fn main_0() -> i32 { assert!(((o.anon_3.i) == (9))); assert!(((o.anon_3.inner_named.j) == (10))); assert!(((o.anon_3.anon_5.k) == (11))); - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_6 { - pub x: i32, - pub z: i32, - }; let mut s: anon_6 = ::default(); s.x = 1; s.z = 2; @@ -118,3 +112,9 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_6 { + pub x: i32, + pub z: i32, +} diff --git a/tests/unit/out/unsafe/anonymous-struct_c.rs b/tests/unit/out/unsafe/anonymous-struct_c.rs index 1c9915d9..5de7e6b6 100644 --- a/tests/unit/out/unsafe/anonymous-struct_c.rs +++ b/tests/unit/out/unsafe/anonymous-struct_c.rs @@ -91,12 +91,6 @@ unsafe fn main_0() -> i32 { assert!(((((o.anon_3.i) == (9)) as i32) != 0)); assert!(((((o.anon_3.inner_named.j) == (10)) as i32) != 0)); assert!(((((o.anon_3.anon_5.k) == (11)) as i32) != 0)); - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_6 { - pub x: i32, - pub z: i32, - }; let mut s: anon_6 = ::default(); s.x = 1; s.z = 2; @@ -114,3 +108,9 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_6 { + pub x: i32, + pub z: i32, +} diff --git a/tests/unit/out/unsafe/anonymous_enum.rs b/tests/unit/out/unsafe/anonymous_enum.rs index 02028c3c..e5e75562 100644 --- a/tests/unit/out/unsafe/anonymous_enum.rs +++ b/tests/unit/out/unsafe/anonymous_enum.rs @@ -35,9 +35,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32))); assert!(((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32))); assert!(((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32))); @@ -52,3 +49,6 @@ unsafe fn main_0() -> i32 { assert!(((w.field as i32) == (anon_2_FIELD_B as i32))); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/unsafe/anonymous_enum_c.rs b/tests/unit/out/unsafe/anonymous_enum_c.rs index 9b405228..3913926e 100644 --- a/tests/unit/out/unsafe/anonymous_enum_c.rs +++ b/tests/unit/out/unsafe/anonymous_enum_c.rs @@ -35,9 +35,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)) as i32) != 0)); @@ -52,3 +49,6 @@ unsafe fn main_0() -> i32 { assert!(((((w.field as u32) == ((anon_2_FIELD_B as i32) as u32)) as i32) != 0)); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index 43d6ddab..ad4e1298 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -25,9 +25,24 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(|x: i32| { - return -x; + let mut negate: Option i32> = Some(|a1: i32| { + let __this: lambda_2 = lambda_2 {}; + unsafe { lambda_2::operator_call(&__this, a1) } }); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + let __this: lambda_2 = self.clone(); + unsafe { lambda_2::operator_call(&__this, a1) } + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_pass.rs b/tests/unit/out/unsafe/lambda_capture_pass.rs index b987c95d..99366db7 100644 --- a/tests/unit/out/unsafe/lambda_capture_pass.rs +++ b/tests/unit/out/unsafe/lambda_capture_pass.rs @@ -6,11 +6,11 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub unsafe fn apply_0(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return (unsafe { fn_(x) }); +pub unsafe fn apply_0(mut fn_: lambda_1, mut x: i32) -> i32 { + return (unsafe { lambda_1::operator_call(&fn_, x) }); } -pub unsafe fn apply_1(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return (unsafe { fn_(x) }); +pub unsafe fn apply_2(mut fn_: lambda_3, mut x: i32) -> i32 { + return (unsafe { lambda_3::operator_call(&fn_, x) }); } pub fn main() { unsafe { @@ -19,40 +19,44 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut base: i32 = 10; - assert!( - ((unsafe { - apply_0( - (|x: i32| { - return ((x) + (base)); - }) - .clone(), - 5, - ) - }) == (15)) - ); + let mut add_base: lambda_1 = (lambda_1 { base: &mut base }); + assert!(((unsafe { apply_0(add_base, 5,) }) == (15))); base = 100; - assert!( - ((unsafe { - apply_0( - (|x: i32| { - return ((x) + (base)); - }) - .clone(), - 5, - ) - }) == (105)) - ); + assert!(((unsafe { apply_0(add_base, 5,) }) == (105))); let mut factor: i32 = 3; - assert!( - ((unsafe { - apply_1( - (|x: i32| { - return ((x) * (factor)); - }) - .clone(), - 4, - ) - }) == (12)) - ); + let mut scale: lambda_3 = (lambda_3 { factor: factor }); + assert!(((unsafe { apply_2(scale, 4,) }) == (12))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + base: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + let __this: lambda_1 = self.clone(); + unsafe { lambda_1::operator_call(&__this, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + factor: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) * (self.factor)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + let __this: lambda_3 = self.clone(); + unsafe { lambda_3::operator_call(&__this, a1) } + } +} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index a117ad16..6381f56c 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -13,28 +13,46 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 10; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (31)) - ); + let mut outer: lambda_0 = (lambda_0 { x: &mut x }); + assert!(((unsafe { lambda_0::operator_call(&outer, 20,) }) == (31))); x = 100; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (121)) - ); + assert!(((unsafe { lambda_0::operator_call(&outer, 20,) }) == (121))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + x: *mut i32, + y: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return (((*self.x) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + let __this: lambda_1 = self.clone(); + unsafe { lambda_1::operator_call(&__this, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + x: *mut i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_1 = (lambda_1 { + x: &mut (*self.x), + y: y, + }); + return (unsafe { lambda_1::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + let __this: lambda_0 = self.clone(); + unsafe { lambda_0::operator_call(&__this, a1) } + } +} diff --git a/tests/unit/out/unsafe/local_anon_struct_collision.rs b/tests/unit/out/unsafe/local_anon_struct_collision.rs index 4e0a72bd..2ab7395e 100644 --- a/tests/unit/out/unsafe/local_anon_struct_collision.rs +++ b/tests/unit/out/unsafe/local_anon_struct_collision.rs @@ -7,29 +7,29 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn first_0() -> i32 { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_1 { - pub x: i32, - pub y: i32, - }; let mut p: anon_1 = ::default(); p.x = 1; p.y = 2; return ((p.x) + (p.y)); } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_1 { + pub x: i32, + pub y: i32, +} pub unsafe fn second_2() -> i32 { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_3 { - pub a: i64, - pub b: i64, - }; let mut q: anon_3 = ::default(); q.a = 10_i64; q.b = 20_i64; return (((q.a) + (q.b)) as i32); } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_3 { + pub a: i64, + pub b: i64, +} pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index da3cd9de..7a9a821e 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -19,17 +19,9 @@ unsafe fn main_0() -> i32 { .offset((5) as isize) .offset_from(arr1.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { - if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*x, *y) - { + if (lambda_0 {}).call(*x, *y) { std::cmp::Ordering::Less - } else if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*y, *x) - { + } else if (lambda_0 {}).call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -38,3 +30,17 @@ unsafe fn main_0() -> i32 { }; return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32, mut y: i32) -> bool { + return ((x) < (y)); + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + let __this: lambda_0 = self.clone(); + unsafe { lambda_0::operator_call(&__this, a1, a2) } + } +} diff --git a/tests/unit/out/unsafe/union_pointer_pun_address.rs b/tests/unit/out/unsafe/union_pointer_pun_address.rs index 858e04b8..7b3e50ab 100644 --- a/tests/unit/out/unsafe/union_pointer_pun_address.rs +++ b/tests/unit/out/unsafe/union_pointer_pun_address.rs @@ -24,17 +24,6 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: node_a = node_a { n: 123 }; - #[repr(C)] - #[derive(Copy, Clone)] - pub union anon_0 { - pub to_a: *mut node_a, - pub to_b: *mut node_b, - } - impl Default for anon_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } - }; let mut ptr: anon_0 = ::default(); ptr.to_a = (&mut a as *mut node_a); let mut out: *mut node_b = ptr.to_b; @@ -45,3 +34,14 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone)] +pub union anon_0 { + pub to_a: *mut node_a, + pub to_b: *mut node_b, +} +impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} diff --git a/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs b/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs index 172ad396..7cdcc2aa 100644 --- a/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs @@ -13,20 +13,20 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i64 = (-1_i32 as i64); - #[repr(C)] - #[derive(Copy, Clone)] - pub union anon_0 { - pub as_unsigned: *mut u64, - pub as_signed: *mut i64, - } - impl Default for anon_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } - }; let mut pp: anon_0 = ::default(); pp.as_signed = (&mut x as *mut i64); (*pp.as_unsigned) = 42_u64; assert!(((((x) == (42_i64)) as i32) != 0)); return 0; } +#[repr(C)] +#[derive(Copy, Clone)] +pub union anon_0 { + pub as_unsigned: *mut u64, + pub as_signed: *mut i64, +} +impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} From eec1a00c69019791ff1a1c74e64f9a8c8c75df30 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 15:44:00 +0100 Subject: [PATCH 11/43] Add hoisted_records --- cpp2rust/converter/converter.cpp | 10 ++++++++++ cpp2rust/converter/converter.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 99d7b036..ed91bb4b 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -363,6 +363,10 @@ bool Converter::VisitTranslationUnitDecl(clang::TranslationUnitDecl *decl) { if (IsUserDefinedDecl(child) && (IsInMainFile(child) || !decl_ids_.contains(GetID(child)))) { Convert(child); + if (!hoisted_records_.empty()) { + StrCat(hoisted_records_); + hoisted_records_.clear(); + } } } return false; @@ -1257,6 +1261,12 @@ bool Converter::VisitCompoundStmt(clang::CompoundStmt *stmt) { bool Converter::VisitDeclStmt(clang::DeclStmt *stmt) { for (auto *decl : stmt->decls()) { + if (clang::isa(decl)) { + Buffer buf(*this); + Convert(decl); + hoisted_records_ += std::move(buf).str(); + continue; + } Convert(decl); StrCat(token::kSemiColon); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 6a4996cf..61e28044 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -880,6 +880,8 @@ class Converter : public clang::RecursiveASTVisitor { // translation units. static std::map methods_on_ptr_; + std::string hoisted_records_; + enum class ExprKind : uint8_t { Callee, LValue, From 4b5bab8ad093a04852b75356e795569d2a5ee548 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 15:44:18 +0100 Subject: [PATCH 12/43] Update tests --- tests/unit/local_record_template.cpp | 17 +++ tests/unit/out/refcount/anonymous-struct.rs | 60 +++++----- tests/unit/out/refcount/anonymous-struct_c.rs | 56 ++++----- tests/unit/out/refcount/anonymous_enum.rs | 6 +- tests/unit/out/refcount/anonymous_enum_c.rs | 6 +- .../refcount/local_anon_struct_collision.rs | 108 +++++++++--------- .../out/refcount/local_record_template.rs | 48 ++++++++ .../out/refcount/union_pointer_pun_address.rs | 76 ++++++------ .../union_pointer_pun_writethrough.rs | 72 ++++++------ tests/unit/out/unsafe/anonymous-struct.rs | 12 +- tests/unit/out/unsafe/anonymous-struct_c.rs | 12 +- tests/unit/out/unsafe/anonymous_enum.rs | 6 +- tests/unit/out/unsafe/anonymous_enum_c.rs | 6 +- .../out/unsafe/local_anon_struct_collision.rs | 24 ++-- .../unit/out/unsafe/local_record_template.rs | 26 +++++ .../out/unsafe/union_pointer_pun_address.rs | 22 ++-- .../unsafe/union_pointer_pun_writethrough.rs | 22 ++-- 17 files changed, 335 insertions(+), 244 deletions(-) create mode 100644 tests/unit/local_record_template.cpp create mode 100644 tests/unit/out/refcount/local_record_template.rs create mode 100644 tests/unit/out/unsafe/local_record_template.rs diff --git a/tests/unit/local_record_template.cpp b/tests/unit/local_record_template.cpp new file mode 100644 index 00000000..0fa6ea4c --- /dev/null +++ b/tests/unit/local_record_template.cpp @@ -0,0 +1,17 @@ +#include + +template int get(T t) { return t.x; } + +namespace ns { +template int twice(T t) { return t.x * 2; } +} + +int main() { + struct Local { + int x; + }; + Local l{7}; + assert(get(l) == 7); + assert(ns::twice(l) == 14); + return 0; +} diff --git a/tests/unit/out/refcount/anonymous-struct.rs b/tests/unit/out/refcount/anonymous-struct.rs index 64d82f14..3ef5f74c 100644 --- a/tests/unit/out/refcount/anonymous-struct.rs +++ b/tests/unit/out/refcount/anonymous-struct.rs @@ -321,36 +321,6 @@ fn main_0() -> i32 { .borrow()) == 11) ); - #[derive(Default)] - pub struct anon_6 { - pub x: Value, - pub z: Value, - } - impl Clone for anon_6 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x: Rc::new(RefCell::new((*self.x.borrow()))), - z: Rc::new(RefCell::new((*self.z.borrow()))), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } - } - impl ByteRepr for anon_6 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.z.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let s: Value = Rc::new(RefCell::new(::default())); (*(*s.borrow()).x.borrow_mut()) = 1; (*(*s.borrow()).z.borrow_mut()) = 2; @@ -368,3 +338,33 @@ fn main_0() -> i32 { ); return 0; } +#[derive(Default)] +pub struct anon_6 { + pub x: Value, + pub z: Value, +} +impl Clone for anon_6 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + z: Rc::new(RefCell::new((*self.z.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.z.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} diff --git a/tests/unit/out/refcount/anonymous-struct_c.rs b/tests/unit/out/refcount/anonymous-struct_c.rs index 065fd2cc..5473ea07 100644 --- a/tests/unit/out/refcount/anonymous-struct_c.rs +++ b/tests/unit/out/refcount/anonymous-struct_c.rs @@ -290,34 +290,6 @@ fn main_0() -> i32 { == 11) as i32) != 0) ); - #[derive(Default)] - pub struct anon_6 { - pub x: Value, - pub z: Value, - } - impl Clone for anon_6 { - fn clone(&self) -> Self { - Self { - x: Rc::new(RefCell::new((*self.x.borrow()).clone())), - z: Rc::new(RefCell::new((*self.z.borrow()).clone())), - } - } - } - impl ByteRepr for anon_6 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.z.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let s: Value = >::default(); (*(*s.borrow()).x.borrow_mut()) = 1; (*(*s.borrow()).z.borrow_mut()) = 2; @@ -335,3 +307,31 @@ fn main_0() -> i32 { ); return 0; } +#[derive(Default)] +pub struct anon_6 { + pub x: Value, + pub z: Value, +} +impl Clone for anon_6 { + fn clone(&self) -> Self { + Self { + x: Rc::new(RefCell::new((*self.x.borrow()).clone())), + z: Rc::new(RefCell::new((*self.z.borrow()).clone())), + } + } +} +impl ByteRepr for anon_6 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.z.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + z: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index 2e954d73..f630eea9 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -78,9 +78,6 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32))); assert!(((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32))); assert!(((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32))); @@ -95,3 +92,6 @@ fn main_0() -> i32 { assert!((((*(*w.borrow()).field.borrow()) as i32) == (anon_2_FIELD_B as i32))); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 82240be2..dd356a26 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -74,9 +74,6 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)) as i32) != 0)); @@ -97,3 +94,6 @@ fn main_0() -> i32 { ); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/refcount/local_anon_struct_collision.rs b/tests/unit/out/refcount/local_anon_struct_collision.rs index d717fab0..f9deb5f2 100644 --- a/tests/unit/out/refcount/local_anon_struct_collision.rs +++ b/tests/unit/out/refcount/local_anon_struct_collision.rs @@ -7,73 +7,73 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn first_0() -> i32 { - #[derive(Default)] - pub struct anon_1 { - pub x: Value, - pub y: Value, - } - impl Clone for anon_1 { - fn clone(&self) -> Self { - Self { - x: Rc::new(RefCell::new((*self.x.borrow()).clone())), - y: Rc::new(RefCell::new((*self.y.borrow()).clone())), - } - } - } - impl ByteRepr for anon_1 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.x.borrow()).to_bytes(&mut buf[0..4]); - (*self.y.borrow()).to_bytes(&mut buf[4..8]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), - y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), - } - } - }; let p: Value = >::default(); (*(*p.borrow()).x.borrow_mut()) = 1; (*(*p.borrow()).y.borrow_mut()) = 2; return ((*(*p.borrow()).x.borrow()) + (*(*p.borrow()).y.borrow())); } -pub fn second_2() -> i32 { - #[derive(Default)] - pub struct anon_3 { - pub a: Value, - pub b: Value, - } - impl Clone for anon_3 { - fn clone(&self) -> Self { - Self { - a: Rc::new(RefCell::new((*self.a.borrow()).clone())), - b: Rc::new(RefCell::new((*self.b.borrow()).clone())), - } +#[derive(Default)] +pub struct anon_1 { + pub x: Value, + pub y: Value, +} +impl Clone for anon_1 { + fn clone(&self) -> Self { + Self { + x: Rc::new(RefCell::new((*self.x.borrow()).clone())), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), } } - impl ByteRepr for anon_3 { - fn byte_size() -> usize { - 16 - } - fn to_bytes(&self, buf: &mut [u8]) { - (*self.a.borrow()).to_bytes(&mut buf[0..8]); - (*self.b.borrow()).to_bytes(&mut buf[8..16]); - } - fn from_bytes(buf: &[u8]) -> Self { - Self { - a: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), - b: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), - } +} +impl ByteRepr for anon_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), } - }; + } +} +pub fn second_2() -> i32 { let q: Value = >::default(); (*(*q.borrow()).a.borrow_mut()) = 10_i64; (*(*q.borrow()).b.borrow_mut()) = 20_i64; return (((*(*q.borrow()).a.borrow()) + (*(*q.borrow()).b.borrow())) as i32); } +#[derive(Default)] +pub struct anon_3 { + pub a: Value, + pub b: Value, +} +impl Clone for anon_3 { + fn clone(&self) -> Self { + Self { + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + } + } +} +impl ByteRepr for anon_3 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..8]); + (*self.b.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/local_record_template.rs b/tests/unit/out/refcount/local_record_template.rs new file mode 100644 index 00000000..ded9eb62 --- /dev/null +++ b/tests/unit/out/refcount/local_record_template.rs @@ -0,0 +1,48 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn get_0(t: Local) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); + return (*(*t.borrow()).x.borrow()); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let l: Value = Rc::new(RefCell::new(Local { + x: Rc::new(RefCell::new(7)), + })); + assert!((({ get_0((*l.borrow()).clone(),) }) == 7)); + return 0; +} +#[derive(Default)] +pub struct Local { + pub x: Value, +} +impl Clone for Local { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Local { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} diff --git a/tests/unit/out/refcount/union_pointer_pun_address.rs b/tests/unit/out/refcount/union_pointer_pun_address.rs index 4a0cb1bb..464f78bd 100644 --- a/tests/unit/out/refcount/union_pointer_pun_address.rs +++ b/tests/unit/out/refcount/union_pointer_pun_address.rs @@ -65,44 +65,6 @@ fn main_0() -> i32 { let a: Value = Rc::new(RefCell::new(node_a { n: Rc::new(RefCell::new(123)), })); - pub struct anon_0 { - __bytes: Value>, - } - impl anon_0 { - pub fn to_a(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - pub fn to_b(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - } - impl Clone for anon_0 { - fn clone(&self) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), - } - } - } - impl Default for anon_0 { - fn default() -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), - } - } - } - impl ByteRepr for anon_0 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - buf.copy_from_slice(&self.__bytes.borrow()); - } - fn from_bytes(buf: &[u8]) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from(buf))), - } - } - }; let ptr: Value = >::default(); (*ptr.borrow_mut()).to_a().write((a.as_pointer())); let out: Value> = Rc::new(RefCell::new(((*ptr.borrow()).to_b().read()).clone())); @@ -115,3 +77,41 @@ fn main_0() -> i32 { ); return 0; } +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn to_a(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } + pub fn to_b(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() + } +} +impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), + } + } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), + } + } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), + } + } +} diff --git a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs index dd2f9369..3d470727 100644 --- a/tests/unit/out/refcount/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/refcount/union_pointer_pun_writethrough.rs @@ -11,47 +11,47 @@ pub fn main() { } fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new((-1_i32 as i64))); - pub struct anon_0 { - __bytes: Value>, + let pp: Value = >::default(); + (*pp.borrow_mut()).as_signed().write((x.as_pointer())); + ((*pp.borrow()).as_unsigned().read()).write(42_u64); + assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); + return 0; +} +pub struct anon_0 { + __bytes: Value>, +} +impl anon_0 { + pub fn as_unsigned(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - impl anon_0 { - pub fn as_unsigned(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } - pub fn as_signed(&self) -> Ptr> { - (self.__bytes.as_pointer() as Ptr).reinterpret_cast() - } + pub fn as_signed(&self) -> Ptr> { + (self.__bytes.as_pointer() as Ptr).reinterpret_cast() } - impl Clone for anon_0 { - fn clone(&self) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), - } +} +impl Clone for anon_0 { + fn clone(&self) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(self.__bytes.borrow().clone())), } } - impl Default for anon_0 { - fn default() -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), - } +} +impl Default for anon_0 { + fn default() -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from([0u8; 8]))), } } - impl ByteRepr for anon_0 { - fn byte_size() -> usize { - 8 - } - fn to_bytes(&self, buf: &mut [u8]) { - buf.copy_from_slice(&self.__bytes.borrow()); - } - fn from_bytes(buf: &[u8]) -> Self { - anon_0 { - __bytes: Rc::new(RefCell::new(Box::from(buf))), - } +} +impl ByteRepr for anon_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + buf.copy_from_slice(&self.__bytes.borrow()); + } + fn from_bytes(buf: &[u8]) -> Self { + anon_0 { + __bytes: Rc::new(RefCell::new(Box::from(buf))), } - }; - let pp: Value = >::default(); - (*pp.borrow_mut()).as_signed().write((x.as_pointer())); - ((*pp.borrow()).as_unsigned().read()).write(42_u64); - assert!(((((*x.borrow()) == 42_i64) as i32) != 0)); - return 0; + } } diff --git a/tests/unit/out/unsafe/anonymous-struct.rs b/tests/unit/out/unsafe/anonymous-struct.rs index 59c69a7f..705075f8 100644 --- a/tests/unit/out/unsafe/anonymous-struct.rs +++ b/tests/unit/out/unsafe/anonymous-struct.rs @@ -95,12 +95,6 @@ unsafe fn main_0() -> i32 { assert!(((o.anon_3.i) == (9))); assert!(((o.anon_3.inner_named.j) == (10))); assert!(((o.anon_3.anon_5.k) == (11))); - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_6 { - pub x: i32, - pub z: i32, - }; let mut s: anon_6 = ::default(); s.x = 1; s.z = 2; @@ -118,3 +112,9 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_6 { + pub x: i32, + pub z: i32, +} diff --git a/tests/unit/out/unsafe/anonymous-struct_c.rs b/tests/unit/out/unsafe/anonymous-struct_c.rs index 1c9915d9..5de7e6b6 100644 --- a/tests/unit/out/unsafe/anonymous-struct_c.rs +++ b/tests/unit/out/unsafe/anonymous-struct_c.rs @@ -91,12 +91,6 @@ unsafe fn main_0() -> i32 { assert!(((((o.anon_3.i) == (9)) as i32) != 0)); assert!(((((o.anon_3.inner_named.j) == (10)) as i32) != 0)); assert!(((((o.anon_3.anon_5.k) == (11)) as i32) != 0)); - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_6 { - pub x: i32, - pub z: i32, - }; let mut s: anon_6 = ::default(); s.x = 1; s.z = 2; @@ -114,3 +108,9 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_6 { + pub x: i32, + pub z: i32, +} diff --git a/tests/unit/out/unsafe/anonymous_enum.rs b/tests/unit/out/unsafe/anonymous_enum.rs index 02028c3c..e5e75562 100644 --- a/tests/unit/out/unsafe/anonymous_enum.rs +++ b/tests/unit/out/unsafe/anonymous_enum.rs @@ -35,9 +35,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32))); assert!(((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32))); assert!(((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32))); @@ -52,3 +49,6 @@ unsafe fn main_0() -> i32 { assert!(((w.field as i32) == (anon_2_FIELD_B as i32))); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/unsafe/anonymous_enum_c.rs b/tests/unit/out/unsafe/anonymous_enum_c.rs index 9b405228..3913926e 100644 --- a/tests/unit/out/unsafe/anonymous_enum_c.rs +++ b/tests/unit/out/unsafe/anonymous_enum_c.rs @@ -35,9 +35,6 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - pub type anon_3 = u32; - pub const anon_3_THIRD_A: anon_3 = 0; - pub const anon_3_THIRD_B: anon_3 = 1;; assert!(((((anon_0_FIRST_A as i32) != (anon_0_FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1_SECOND_A as i32) != (anon_1_SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3_THIRD_A as i32) != (anon_3_THIRD_B as i32)) as i32) != 0)); @@ -52,3 +49,6 @@ unsafe fn main_0() -> i32 { assert!(((((w.field as u32) == ((anon_2_FIELD_B as i32) as u32)) as i32) != 0)); return 0; } +pub type anon_3 = u32; +pub const anon_3_THIRD_A: anon_3 = 0; +pub const anon_3_THIRD_B: anon_3 = 1; diff --git a/tests/unit/out/unsafe/local_anon_struct_collision.rs b/tests/unit/out/unsafe/local_anon_struct_collision.rs index 4e0a72bd..2ab7395e 100644 --- a/tests/unit/out/unsafe/local_anon_struct_collision.rs +++ b/tests/unit/out/unsafe/local_anon_struct_collision.rs @@ -7,29 +7,29 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub unsafe fn first_0() -> i32 { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_1 { - pub x: i32, - pub y: i32, - }; let mut p: anon_1 = ::default(); p.x = 1; p.y = 2; return ((p.x) + (p.y)); } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_1 { + pub x: i32, + pub y: i32, +} pub unsafe fn second_2() -> i32 { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct anon_3 { - pub a: i64, - pub b: i64, - }; let mut q: anon_3 = ::default(); q.a = 10_i64; q.b = 20_i64; return (((q.a) + (q.b)) as i32); } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct anon_3 { + pub a: i64, + pub b: i64, +} pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/local_record_template.rs b/tests/unit/out/unsafe/local_record_template.rs new file mode 100644 index 00000000..3a64619f --- /dev/null +++ b/tests/unit/out/unsafe/local_record_template.rs @@ -0,0 +1,26 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn get_0(mut t: Local) -> i32 { + return t.x; +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut l: Local = Local { x: 7 }; + assert!(((unsafe { get_0(l,) }) == (7))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Local { + pub x: i32, +} diff --git a/tests/unit/out/unsafe/union_pointer_pun_address.rs b/tests/unit/out/unsafe/union_pointer_pun_address.rs index 858e04b8..7b3e50ab 100644 --- a/tests/unit/out/unsafe/union_pointer_pun_address.rs +++ b/tests/unit/out/unsafe/union_pointer_pun_address.rs @@ -24,17 +24,6 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: node_a = node_a { n: 123 }; - #[repr(C)] - #[derive(Copy, Clone)] - pub union anon_0 { - pub to_a: *mut node_a, - pub to_b: *mut node_b, - } - impl Default for anon_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } - }; let mut ptr: anon_0 = ::default(); ptr.to_a = (&mut a as *mut node_a); let mut out: *mut node_b = ptr.to_b; @@ -45,3 +34,14 @@ unsafe fn main_0() -> i32 { ); return 0; } +#[repr(C)] +#[derive(Copy, Clone)] +pub union anon_0 { + pub to_a: *mut node_a, + pub to_b: *mut node_b, +} +impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} diff --git a/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs b/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs index 172ad396..7cdcc2aa 100644 --- a/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs +++ b/tests/unit/out/unsafe/union_pointer_pun_writethrough.rs @@ -13,20 +13,20 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i64 = (-1_i32 as i64); - #[repr(C)] - #[derive(Copy, Clone)] - pub union anon_0 { - pub as_unsigned: *mut u64, - pub as_signed: *mut i64, - } - impl Default for anon_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } - }; let mut pp: anon_0 = ::default(); pp.as_signed = (&mut x as *mut i64); (*pp.as_unsigned) = 42_u64; assert!(((((x) == (42_i64)) as i32) != 0)); return 0; } +#[repr(C)] +#[derive(Copy, Clone)] +pub union anon_0 { + pub as_unsigned: *mut u64, + pub as_signed: *mut i64, +} +impl Default for anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} From dab0234cc1b64b0ce58a9cdf4ad092bb76c6ddb9 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 15:44:57 +0100 Subject: [PATCH 13/43] Update tests --- tests/unit/out/refcount/local_record_template.rs | 5 +++++ tests/unit/out/unsafe/local_record_template.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/tests/unit/out/refcount/local_record_template.rs b/tests/unit/out/refcount/local_record_template.rs index ded9eb62..d415f487 100644 --- a/tests/unit/out/refcount/local_record_template.rs +++ b/tests/unit/out/refcount/local_record_template.rs @@ -10,6 +10,10 @@ pub fn get_0(t: Local) -> i32 { let t: Value = Rc::new(RefCell::new(t)); return (*(*t.borrow()).x.borrow()); } +pub fn twice_1(t: Local) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); + return ((*(*t.borrow()).x.borrow()) * 2); +} pub fn main() { std::process::exit(main_0()); } @@ -18,6 +22,7 @@ fn main_0() -> i32 { x: Rc::new(RefCell::new(7)), })); assert!((({ get_0((*l.borrow()).clone(),) }) == 7)); + assert!((({ twice_1((*l.borrow()).clone(),) }) == 14)); return 0; } #[derive(Default)] diff --git a/tests/unit/out/unsafe/local_record_template.rs b/tests/unit/out/unsafe/local_record_template.rs index 3a64619f..62644ec8 100644 --- a/tests/unit/out/unsafe/local_record_template.rs +++ b/tests/unit/out/unsafe/local_record_template.rs @@ -9,6 +9,9 @@ use std::rc::Rc; pub unsafe fn get_0(mut t: Local) -> i32 { return t.x; } +pub unsafe fn twice_1(mut t: Local) -> i32 { + return ((t.x) * (2)); +} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -17,6 +20,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut l: Local = Local { x: 7 }; assert!(((unsafe { get_0(l,) }) == (7))); + assert!(((unsafe { twice_1(l,) }) == (14))); return 0; } #[repr(C)] From 989890e623b84cb4d0ae774b5fcb0dfb16f49f20 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 15:56:10 +0100 Subject: [PATCH 14/43] Fix naming clash between functoins and specializations --- cpp2rust/converter/converter_lib.cpp | 19 ++- cpp2rust/converter/mapper.cpp | 6 + tests/unit/local_record_template.cpp | 20 +++ .../out/refcount/local_record_template.rs | 142 ++++++++++++++++-- .../unit/out/unsafe/local_record_template.rs | 52 ++++++- 5 files changed, 219 insertions(+), 20 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 7a031734..dc9f75c8 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -535,13 +535,24 @@ static std::string GetParamSignature(const clang::Decl *decl) { } static std::string GetLexicalSpecializationID(const clang::Decl *decl) { + std::string id; if (const auto *spec = clang::dyn_cast( decl->getLexicalDeclContext()); spec && decl->getLexicalDeclContext() != decl->getDeclContext()) { - return Mapper::ToString(Mapper::GetTypeForDecl(spec)); + id += Mapper::ToString(Mapper::GetTypeForDecl(spec)); } - return {}; + for (const auto *dc = decl->getDeclContext(); dc; dc = dc->getParent()) { + if (const auto *spec = + clang::dyn_cast(dc)) { + id += Mapper::ToString(Mapper::GetTypeForDecl(spec)); + } + if (const auto *fn = clang::dyn_cast(dc); + fn && fn->getTemplateSpecializationArgs()) { + id += clang::ASTNameGenerator(fn->getASTContext()).getName(fn); + } + } + return id; } std::string GetID(const clang::Decl *decl) { @@ -623,6 +634,10 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { var && (var->isFileVarDecl() || var->isStaticLocal())) { id = GetDeclId(var->getCanonicalDecl(), var->getFormalLinkage() != clang::Linkage::External); + } else if (auto *tag = clang::dyn_cast(decl); + tag && tag->getDeclContext()->isFunctionOrMethod()) { + id = + type_mapping.try_emplace(GetID(tag), type_mapping.size()).first->second; } if (id) { name += '_'; diff --git a/cpp2rust/converter/mapper.cpp b/cpp2rust/converter/mapper.cpp index 4def2784..a5699070 100644 --- a/cpp2rust/converter/mapper.cpp +++ b/cpp2rust/converter/mapper.cpp @@ -882,6 +882,12 @@ std::string ToString(clang::QualType qual_type, ScalarSugar sugar) { return ToString(clang::cast(tag)); } + if (auto *tag = qual_type->getAsTagDecl(); + tag && tag->getIdentifier() && + tag->getDeclContext()->isFunctionOrMethod()) { + return GetNamedDeclAsString(tag); + } + if (auto renamed = DisambiguateAnonymousTag(qual_type->getAsTagDecl()); !renamed.empty()) { return renamed; diff --git a/tests/unit/local_record_template.cpp b/tests/unit/local_record_template.cpp index 0fa6ea4c..f96c0ff6 100644 --- a/tests/unit/local_record_template.cpp +++ b/tests/unit/local_record_template.cpp @@ -6,6 +6,23 @@ namespace ns { template int twice(T t) { return t.x * 2; } } +template int wrap(T v) { + struct Local { + T x; + }; + Local l{v}; + return get(l); +} + +int other() { + struct Local { + long x; + long y; + }; + Local l{3, 4}; + return get(l) + (int)l.y; +} + int main() { struct Local { int x; @@ -13,5 +30,8 @@ int main() { Local l{7}; assert(get(l) == 7); assert(ns::twice(l) == 14); + assert(other() == 7); + assert(wrap(5) == 5); + assert(wrap(6L) == 6); return 0; } diff --git a/tests/unit/out/refcount/local_record_template.rs b/tests/unit/out/refcount/local_record_template.rs index d415f487..b7170eaf 100644 --- a/tests/unit/out/refcount/local_record_template.rs +++ b/tests/unit/out/refcount/local_record_template.rs @@ -6,39 +6,157 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -pub fn get_0(t: Local) -> i32 { - let t: Value = Rc::new(RefCell::new(t)); +pub fn get_0(t: Local_1) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); + return ((*(*t.borrow()).x.borrow()) as i32); +} +pub fn get_2(t: Local_3) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); + return (*(*t.borrow()).x.borrow()); +} +pub fn get_4(t: Local_5) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); return (*(*t.borrow()).x.borrow()); } -pub fn twice_1(t: Local) -> i32 { - let t: Value = Rc::new(RefCell::new(t)); +pub fn get_6(t: Local_7) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); + return ((*(*t.borrow()).x.borrow()) as i32); +} +pub fn twice_8(t: Local_3) -> i32 { + let t: Value = Rc::new(RefCell::new(t)); return ((*(*t.borrow()).x.borrow()) * 2); } +pub fn wrap_9(v: i32) -> i32 { + let v: Value = Rc::new(RefCell::new(v)); + let l: Value = Rc::new(RefCell::new(Local_5 { + x: Rc::new(RefCell::new((*v.borrow()))), + })); + return ({ get_4((*l.borrow()).clone()) }); +} +pub fn wrap_10(v: i64) -> i32 { + let v: Value = Rc::new(RefCell::new(v)); + let l: Value = Rc::new(RefCell::new(Local_7 { + x: Rc::new(RefCell::new((*v.borrow()))), + })); + return ({ get_6((*l.borrow()).clone()) }); +} +#[derive(Default)] +pub struct Local_5 { + pub x: Value, +} +impl Clone for Local_5 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Local_5 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct Local_7 { + pub x: Value, +} +impl Clone for Local_7 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Local_7 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + } + } +} +pub fn other_11() -> i32 { + let l: Value = Rc::new(RefCell::new(Local_1 { + x: Rc::new(RefCell::new(3_i64)), + y: Rc::new(RefCell::new(4_i64)), + })); + return (({ get_0((*l.borrow()).clone()) }) + ((*(*l.borrow()).y.borrow()) as i32)); +} +#[derive(Default)] +pub struct Local_1 { + pub x: Value, + pub y: Value, +} +impl Clone for Local_1 { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Local_1 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..8]); + (*self.y.borrow()).to_bytes(&mut buf[8..16]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + } + } +} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let l: Value = Rc::new(RefCell::new(Local { + let l: Value = Rc::new(RefCell::new(Local_3 { x: Rc::new(RefCell::new(7)), })); - assert!((({ get_0((*l.borrow()).clone(),) }) == 7)); - assert!((({ twice_1((*l.borrow()).clone(),) }) == 14)); + assert!((({ get_2((*l.borrow()).clone(),) }) == 7)); + assert!((({ twice_8((*l.borrow()).clone(),) }) == 14)); + assert!((({ other_11() }) == 7)); + assert!((({ wrap_9(5,) }) == 5)); + assert!((({ wrap_10(6_i64,) }) == 6)); return 0; } #[derive(Default)] -pub struct Local { +pub struct Local_3 { pub x: Value, } -impl Clone for Local { +impl Clone for Local_3 { fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { + let __this: Value = Rc::new(RefCell::new(Self { x: Rc::new(RefCell::new((*self.x.borrow()))), })); - let this: Ptr = __this.as_pointer(); + let this: Ptr = __this.as_pointer(); Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl ByteRepr for Local { +impl ByteRepr for Local_3 { fn byte_size() -> usize { 4 } diff --git a/tests/unit/out/unsafe/local_record_template.rs b/tests/unit/out/unsafe/local_record_template.rs index 62644ec8..dbc6b2bf 100644 --- a/tests/unit/out/unsafe/local_record_template.rs +++ b/tests/unit/out/unsafe/local_record_template.rs @@ -6,25 +6,65 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub unsafe fn get_0(mut t: Local) -> i32 { +pub unsafe fn get_0(mut t: Local_1) -> i32 { + return (t.x as i32); +} +pub unsafe fn get_2(mut t: Local_3) -> i32 { + return t.x; +} +pub unsafe fn get_4(mut t: Local_5) -> i32 { return t.x; } -pub unsafe fn twice_1(mut t: Local) -> i32 { +pub unsafe fn get_6(mut t: Local_7) -> i32 { + return (t.x as i32); +} +pub unsafe fn twice_8(mut t: Local_3) -> i32 { return ((t.x) * (2)); } +pub unsafe fn wrap_9(mut v: i32) -> i32 { + let mut l: Local_5 = Local_5 { x: v }; + return (unsafe { get_4(l) }); +} +pub unsafe fn wrap_10(mut v: i64) -> i32 { + let mut l: Local_7 = Local_7 { x: v }; + return (unsafe { get_6(l) }); +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Local_5 { + pub x: i32, +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Local_7 { + pub x: i64, +} +pub unsafe fn other_11() -> i32 { + let mut l: Local_1 = Local_1 { x: 3_i64, y: 4_i64 }; + return ((unsafe { get_0(l) }) + (l.y as i32)); +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Local_1 { + pub x: i64, + pub y: i64, +} pub fn main() { unsafe { std::process::exit(main_0() as i32); } } unsafe fn main_0() -> i32 { - let mut l: Local = Local { x: 7 }; - assert!(((unsafe { get_0(l,) }) == (7))); - assert!(((unsafe { twice_1(l,) }) == (14))); + let mut l: Local_3 = Local_3 { x: 7 }; + assert!(((unsafe { get_2(l,) }) == (7))); + assert!(((unsafe { twice_8(l,) }) == (14))); + assert!(((unsafe { other_11() }) == (7))); + assert!(((unsafe { wrap_9(5,) }) == (5))); + assert!(((unsafe { wrap_10(6_i64,) }) == (6))); return 0; } #[repr(C)] #[derive(Copy, Clone, Default)] -pub struct Local { +pub struct Local_3 { pub x: i32, } From 2ddf78f06e0ed8794a095cca75cea919735fdf97 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 16:10:01 +0100 Subject: [PATCH 15/43] clang-format --- tests/unit/local_record_template.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/local_record_template.cpp b/tests/unit/local_record_template.cpp index f96c0ff6..53a79e62 100644 --- a/tests/unit/local_record_template.cpp +++ b/tests/unit/local_record_template.cpp @@ -4,7 +4,7 @@ template int get(T t) { return t.x; } namespace ns { template int twice(T t) { return t.x * 2; } -} +} // namespace ns template int wrap(T v) { struct Local { From 2382727f23cfc3356026d1026362f8c1ecc86907 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 18:38:05 +0100 Subject: [PATCH 16/43] Rename to AddCallableTrait --- cpp2rust/converter/converter.cpp | 4 ++-- cpp2rust/converter/converter.h | 2 +- cpp2rust/converter/models/converter_refcount.cpp | 4 ++-- cpp2rust/converter/models/converter_refcount.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 3fd03729..4ac450d3 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -957,7 +957,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { EmitRustStructOrUnion(decl); if (decl->isLambda()) { - ConvertLambdaCallable(decl); + AddCallableTrait(decl); } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { @@ -3616,7 +3616,7 @@ std::string Converter::LambdaCallParams(const clang::CXXMethodDecl *op, static constexpr unsigned kMaxCallableArity = 3; -void Converter::ConvertLambdaCallable(clang::CXXRecordDecl *decl) { +void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { auto *op = decl->getLambdaCallOperator(); if (!op->isConst() || op->getNumParams() > kMaxCallableArity) { return; diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 9b237c72..cdd6735e 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -418,7 +418,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); virtual void ConvertLambdaClass(clang::CXXRecordDecl *decl); - virtual void ConvertLambdaCallable(clang::CXXRecordDecl *decl); + virtual void AddCallableTrait(clang::CXXRecordDecl *decl); virtual void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr); virtual std::string LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 1c1e1c04..fc5f7211 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2876,9 +2876,9 @@ bool ConverterRefCount::VisitLambdaExpr(clang::LambdaExpr *expr) { return Converter::VisitLambdaExpr(expr); } -void ConverterRefCount::ConvertLambdaCallable(clang::CXXRecordDecl *decl) { +void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { PushConversionKind push(*this, ConversionKind::Unboxed); - Converter::ConvertLambdaCallable(decl); + Converter::AddCallableTrait(decl); } void ConverterRefCount::ConvertLambdaClass(clang::CXXRecordDecl *decl) { diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 8a65b674..7b2bde07 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -89,7 +89,7 @@ class ConverterRefCount final : public Converter { bool VisitLambdaExpr(clang::LambdaExpr *expr) override; void ConvertLambdaClass(clang::CXXRecordDecl *decl) override; - void ConvertLambdaCallable(clang::CXXRecordDecl *decl) override; + void AddCallableTrait(clang::CXXRecordDecl *decl) override; void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) override; std::string LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, From e04cad3514305023abfa1cdc78b1c975318fe70c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 18:38:24 +0100 Subject: [PATCH 17/43] Check lambda in AddCloneTrait --- cpp2rust/converter/models/converter_refcount.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index fc5f7211..f22c37cb 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -481,7 +481,10 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { } auto *cxx = clang::dyn_cast(decl); - if (!cxx) { + if (cxx && cxx->isLambda() && !HasCallableCopyConstructor(cxx)) { + return; + } + if (!cxx || cxx->isLambda()) { StrCat(keyword::kImpl, "Clone for", record_name); PushBrace impl_brace(*this); StrCat("fn clone(&self) -> Self"); From 88be99f1e0cc4a6b03356923cdeec80d78164eb0 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 18:52:21 +0100 Subject: [PATCH 18/43] Fix clone for lambdas --- cpp2rust/converter/converter_lib.cpp | 9 ++++++++ cpp2rust/converter/converter_lib.h | 1 + .../converter/models/converter_refcount.cpp | 11 ++++++++++ tests/ub/out/refcount/ctor_ref_member.rs | 11 +--------- tests/ub/out/refcount/ub6.rs | 12 +---------- tests/unit/out/refcount/complex_function.rs | 11 +--------- tests/unit/out/refcount/destructor.rs | 9 +------- tests/unit/out/refcount/fn_ptr_default_arg.rs | 9 +------- .../unit/out/refcount/function_overloading.rs | 9 +------- .../unit/out/refcount/lambda_capture_pass.rs | 19 ++++------------- tests/unit/out/refcount/lambda_nested.rs | 21 +++++-------------- tests/unit/out/refcount/nested_structs.rs | 9 +------- .../operator_member_pointer_member.rs | 9 +------- .../out/refcount/operator_other_member.rs | 9 +------- tests/unit/out/refcount/polymorphism.rs | 18 ++-------------- tests/unit/out/refcount/random.rs | 9 +------- tests/unit/out/refcount/stable_sort.rs | 9 +------- .../unit/out/refcount/static_var_in_class.rs | 18 ++-------------- .../out/refcount/vector_with_allocator.rs | 18 ++-------------- 19 files changed, 47 insertions(+), 174 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index f9417874..22e5f9e5 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -330,6 +330,15 @@ bool HasDefaultedCopyConstructor(const clang::RecordDecl *decl) { return !cxx->defaultedCopyConstructorIsDeleted(); } +bool RecordHasOnlyReferenceFields(const clang::RecordDecl *decl) { + for (auto *field : decl->fields()) { + if (!field->getType()->isReferenceType()) { + return false; + } + } + return true; +} + bool HasCallableCopyConstructor(const clang::RecordDecl *decl) { auto *cxx = clang::dyn_cast(decl); if (!cxx) { diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 7ebbd795..bb6ec0f6 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -79,6 +79,7 @@ bool IsDefaultedMoveConstructor(const clang::CXXConstructorDecl *ctor); clang::CXXConstructorDecl * GetUserDefinedCopyConstructor(const clang::RecordDecl *decl); +bool RecordHasOnlyReferenceFields(const clang::RecordDecl *decl); bool HasCallableCopyConstructor(const clang::RecordDecl *decl); bool HasDefaultedCopyConstructor(const clang::RecordDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index f22c37cb..ed2733fb 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -480,6 +480,9 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { return; } + if (HasDefaultedCopyConstructor(decl) && RecordHasOnlyReferenceFields(decl)) { + return; + } auto *cxx = clang::dyn_cast(decl); if (cxx && cxx->isLambda() && !HasCallableCopyConstructor(cxx)) { return; @@ -493,6 +496,10 @@ void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) { PushBrace init_brace(*this); for (auto *field : decl->fields()) { auto name = GetNamedDeclAsString(field); + if (field->getType()->isReferenceType()) { + StrCat(std::format("{0}: self.{0}.clone(),", name)); + continue; + } StrCat(std::format( "{0}: Rc::new(RefCell::new((*self.{0}.borrow()).clone())),", name)); } @@ -2079,6 +2086,10 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { return attrs; } + if (HasDefaultedCopyConstructor(decl) && RecordHasOnlyReferenceFields(decl)) { + attrs.emplace_back("Clone"); + } + if (RecordDerivesDefault(decl)) { attrs.emplace_back("Default"); } diff --git a/tests/ub/out/refcount/ctor_ref_member.rs b/tests/ub/out/refcount/ctor_ref_member.rs index f99be5a9..e1bb73f0 100644 --- a/tests/ub/out/refcount/ctor_ref_member.rs +++ b/tests/ub/out/refcount/ctor_ref_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct S { pub r: Ptr, } @@ -17,15 +17,6 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - r: (self.r).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S {} pub fn main() { std::process::exit(main_0()); diff --git a/tests/ub/out/refcount/ub6.rs b/tests/ub/out/refcount/ub6.rs index e7628b27..c5d6b85b 100644 --- a/tests/ub/out/refcount/ub6.rs +++ b/tests/ub/out/refcount/ub6.rs @@ -6,21 +6,11 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Pair { pub x1: Ptr, pub x2: Ptr, } -impl Clone for Pair { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x1: (self.x1).clone(), - x2: (self.x2).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Pair {} pub fn mkPair_0(x1: Ptr, x2: Ptr) -> Pair { return Pair { diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index c2c67a7c..33374295 100644 --- a/tests/unit/out/refcount/complex_function.rs +++ b/tests/unit/out/refcount/complex_function.rs @@ -43,19 +43,10 @@ impl ByteRepr for X1 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X2 { pub v: Ptr, } -impl Clone for X2 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - v: (self.v).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X2 {} #[derive(Default)] pub struct X3 { diff --git a/tests/unit/out/refcount/destructor.rs b/tests/unit/out/refcount/destructor.rs index 4e10438d..81cdf09f 100644 --- a/tests/unit/out/refcount/destructor.rs +++ b/tests/unit/out/refcount/destructor.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static global_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index fdb3093a..8ca3b6e8 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -33,15 +33,8 @@ fn main_0() -> i32 { assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct lambda_2 {} -impl Clone for lambda_2 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for lambda_2 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/function_overloading.rs b/tests/unit/out/refcount/function_overloading.rs index 55cdb27a..feda1928 100644 --- a/tests/unit/out/refcount/function_overloading.rs +++ b/tests/unit/out/refcount/function_overloading.rs @@ -36,15 +36,8 @@ pub fn foo_3(x: Ptr, y: Ptr, z: Ptr) -> i32 { pub fn bar_4(x: Ptr) -> i32 { return (x.read()); } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Foo {} -impl Clone for Foo { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Foo { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_capture_pass.rs index da55c3a6..430479d6 100644 --- a/tests/unit/out/refcount/lambda_capture_pass.rs +++ b/tests/unit/out/refcount/lambda_capture_pass.rs @@ -38,19 +38,10 @@ fn main_0() -> i32 { assert!((({ apply_2((*scale.borrow()).clone(), 4,) }) == 12)); return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct lambda_1 { base: Ptr, } -impl Clone for lambda_1 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - base: (self.base).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for lambda_1 {} impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { @@ -64,11 +55,9 @@ pub struct lambda_3 { } impl Clone for lambda_3 { fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - factor: Rc::new(RefCell::new((*self.factor.borrow()))), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() + Self { + factor: Rc::new(RefCell::new((*self.factor.borrow()).clone())), + } } } impl ByteRepr for lambda_3 { diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index 765219f6..62d22448 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -24,12 +24,10 @@ pub struct lambda_1 { } impl Clone for lambda_1 { fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x: (self.x).clone(), - y: Rc::new(RefCell::new((*self.y.borrow()))), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() + Self { + x: self.x.clone(), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } } } impl ByteRepr for lambda_1 {} @@ -39,19 +37,10 @@ impl Callable1 for lambda_1 { lambda_1Impl::operator_call(&__this.as_pointer(), a1) } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct lambda_0 { x: Ptr, } -impl Clone for lambda_0 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x: (self.x).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for lambda_0 {} impl Callable1 for lambda_0 { fn call(&self, a1: i32) -> i32 { diff --git a/tests/unit/out/refcount/nested_structs.rs b/tests/unit/out/refcount/nested_structs.rs index 58bade83..6636b8d6 100644 --- a/tests/unit/out/refcount/nested_structs.rs +++ b/tests/unit/out/refcount/nested_structs.rs @@ -144,15 +144,8 @@ impl ByteRepr for Level0_Level1_2 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Level0 {} -impl Clone for Level0 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Level0 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_member_pointer_member.rs b/tests/unit/out/refcount/operator_member_pointer_member.rs index 8d852312..9a549bcd 100644 --- a/tests/unit/out/refcount/operator_member_pointer_member.rs +++ b/tests/unit/out/refcount/operator_member_pointer_member.rs @@ -33,7 +33,7 @@ impl ByteRepr for Inner { } } thread_local!(); -#[derive(Default)] +#[derive(Clone, Default)] pub struct Table {} impl Table { pub fn operator_index(i: i32) -> Ptr { @@ -41,13 +41,6 @@ impl Table { return (table_0.with(Value::clone).as_pointer() as Ptr).offset((*i.borrow())); } } -impl Clone for Table { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr
= __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Table { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_other_member.rs b/tests/unit/out/refcount/operator_other_member.rs index 0395abaf..90b68956 100644 --- a/tests/unit/out/refcount/operator_other_member.rs +++ b/tests/unit/out/refcount/operator_other_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Static {} impl Static { pub fn operator_call(a: i32, b: i32) -> i32 { @@ -15,13 +15,6 @@ impl Static { return ((*a.borrow()) * (*b.borrow())); } } -impl Clone for Static { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Static { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/polymorphism.rs b/tests/unit/out/refcount/polymorphism.rs index 6e2b6cf9..d48d3f85 100644 --- a/tests/unit/out/refcount/polymorphism.rs +++ b/tests/unit/out/refcount/polymorphism.rs @@ -9,20 +9,13 @@ use std::rc::{Rc, Weak}; pub trait Animal { fn bark(&self) -> bool; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Dog {} impl Animal for Dog { fn bark(&self) -> bool { return true; } } -impl Clone for Dog { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Dog { fn byte_size() -> usize { 8 @@ -32,20 +25,13 @@ impl ByteRepr for Dog { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Cat {} impl Animal for Cat { fn bark(&self) -> bool { return false; } } -impl Clone for Cat { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Cat { fn byte_size() -> usize { 8 diff --git a/tests/unit/out/refcount/random.rs b/tests/unit/out/refcount/random.rs index 3e857cbc..ffd77689 100644 --- a/tests/unit/out/refcount/random.rs +++ b/tests/unit/out/refcount/random.rs @@ -54,15 +54,8 @@ impl ByteRepr for Pair {} pub fn zero_0() -> i32 { return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X1 {} -impl Clone for X1 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X1 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index f5d7e452..730c20fc 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -23,15 +23,8 @@ fn main_0() -> i32 { }; return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct lambda_0 {} -impl Clone for lambda_0 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for lambda_0 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/static_var_in_class.rs b/tests/unit/out/refcount/static_var_in_class.rs index 5b163fa7..be46149c 100644 --- a/tests/unit/out/refcount/static_var_in_class.rs +++ b/tests/unit/out/refcount/static_var_in_class.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( static inner_const_0: Value = Rc::new(RefCell::new(1)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct C {} -impl Clone for C { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for C { fn byte_size() -> usize { 1 @@ -30,15 +23,8 @@ impl ByteRepr for C { thread_local!( pub static inner_const_1: Value = Rc::new(RefCell::new(2)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/vector_with_allocator.rs b/tests/unit/out/refcount/vector_with_allocator.rs index f217e8ba..0a65a770 100644 --- a/tests/unit/out/refcount/vector_with_allocator.rs +++ b/tests/unit/out/refcount/vector_with_allocator.rs @@ -6,15 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_int_ {} -impl Clone for TestAllocator_int_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_int_ { fn byte_size() -> usize { 1 @@ -24,15 +17,8 @@ impl ByteRepr for TestAllocator_int_ { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_double_ {} -impl Clone for TestAllocator_double_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_double_ { fn byte_size() -> usize { 1 From b7324a5bc435f269f1b8815e2412d65dd2c7a6db Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 19:12:52 +0100 Subject: [PATCH 19/43] Captureless lambdas don't have receiver --- cpp2rust/converter/converter.cpp | 18 +++++++------- cpp2rust/converter/converter_lib.cpp | 11 ++++++++- cpp2rust/converter/converter_lib.h | 1 + .../converter/models/converter_refcount.cpp | 12 ++++++---- tests/unit/out/refcount/fn_ptr_default_arg.rs | 24 +++++++------------ tests/unit/out/refcount/stable_sort.rs | 20 +++++++--------- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 10 +++----- tests/unit/out/unsafe/stable_sort.rs | 5 ++-- 8 files changed, 50 insertions(+), 51 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 4ac450d3..d88445d5 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1020,7 +1020,7 @@ bool Converter::ConvertCXXMethodDecl(clang::CXXMethodDecl *decl) { } if (method_target_ == MethodTarget::ValueImpl && - (decl->isStatic() || + (IsStaticMethod(decl) || (!decl->isVirtual() && !decl->getParent()->isAbstract()))) { ConvertFunctionQualifiers(decl); } @@ -1028,7 +1028,7 @@ bool Converter::ConvertCXXMethodDecl(clang::CXXMethodDecl *decl) { { PushParen paren(*this); - if (!decl->isStatic()) { + if (!IsStaticMethod(decl)) { StrCat(GetSelfMaybeWithMut(decl), token::kComma); } ConvertFunctionParameters(decl); @@ -2041,7 +2041,7 @@ void Converter::ConvertUserOperatorCall(clang::CXXOperatorCallExpr *expr) { auto info = CollectCallInfo(expr); EmitHoistedArgs(info); if (auto *method = clang::dyn_cast(callee)) { - if (method->isInstance()) { + if (!IsStaticMethod(method)) { SetUFCSReceiver(expr->getArg(0), false, method); } StrCat(GetUFCSName(method), token::kDoubleColon, GetMethodName(method)); @@ -2850,7 +2850,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { if (auto *function = decl->getAsFunction()) { if (auto method = clang::dyn_cast(function)) { - if (method->isStatic()) { + if (IsStaticMethod(method)) { return std::format("{}::{}", GetRecordName(method->getParent()), GetNamedDeclAsString(method)); } @@ -3640,6 +3640,10 @@ std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, std::string_view args) { auto *op = decl->getLambdaCallOperator(); + if (IsStaticMethod(op)) { + return std::format("unsafe {{ {0}::{1}({2}) }}", GetUFCSName(op), + GetMethodName(op), args); + } return std::format( "let __this: {0} = {1}; unsafe {{ {2}::{3}(&__this, {4}) }}", GetRecordName(decl), value, GetUFCSName(op), GetMethodName(op), args); @@ -3648,10 +3652,8 @@ std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, void Converter::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { auto *decl = expr->getLambdaClass(); ConvertLambdaClass(decl); - std::string args; - auto params = LambdaCallParams(decl->getLambdaCallOperator(), args); - StrCat("Some(|", params, "| {", - LambdaCallBody(decl, GetRecordName(decl) + " {}", args), "})"); + auto *op = decl->getLambdaCallOperator(); + StrCat("Some(", GetUFCSName(op), token::kDoubleColon, GetMethodName(op), ")"); computed_expr_type_ = ComputedExprType::FreshValue; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 22e5f9e5..b99f7a12 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -991,8 +991,17 @@ bool IsEmittableMethod(clang::CXXMethodDecl *method) { clang::isa(method); } +bool IsStaticMethod(const clang::CXXMethodDecl *method) { + if (method->isStatic()) { + return true; + } + auto *parent = method->getParent(); + return parent->isLambda() && parent->getLambdaCallOperator() == method && + parent->captures().empty(); +} + bool IsMethodOnPtr(const clang::CXXMethodDecl *method) { - if (method->isDeleted() || method->isStatic() || method->isVirtual() || + if (method->isDeleted() || IsStaticMethod(method) || method->isVirtual() || clang::isa(method)) { return false; } diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index bb6ec0f6..778d7c32 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -95,6 +95,7 @@ bool IsConvertibleCXXMethodDecl(const clang::CXXMethodDecl *decl); bool IsComparisonOperator(const clang::FunctionDecl *fn); bool IsEmittableMethod(clang::CXXMethodDecl *method); +bool IsStaticMethod(const clang::CXXMethodDecl *method); bool IsMethodOnPtr(const clang::CXXMethodDecl *method); bool IsConvertibleFunctionDecl(const clang::FunctionDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index ed2733fb..0bb37910 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2905,11 +2905,9 @@ void ConverterRefCount::ConvertLambdaClass(clang::CXXRecordDecl *decl) { void ConverterRefCount::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { auto *decl = expr->getLambdaClass(); ConvertLambdaClass(decl); - PushConversionKind push(*this, ConversionKind::Unboxed); - std::string args; - auto params = LambdaCallParams(decl->getLambdaCallOperator(), args); - StrCat("FnPtr::new(|", params, "| {", - LambdaCallBody(decl, GetRecordName(decl) + " {}", args), "})"); + auto *op = decl->getLambdaCallOperator(); + StrCat("FnPtr::new(", GetUFCSName(op), token::kDoubleColon, GetMethodName(op), + ")"); computed_expr_type_ = ComputedExprType::FreshValue; } @@ -2917,6 +2915,10 @@ std::string ConverterRefCount::LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, std::string_view args) { auto *op = decl->getLambdaCallOperator(); + if (IsStaticMethod(op)) { + return std::format("{0}::{1}({2})", GetUFCSName(op), GetMethodName(op), + args); + } return std::format("let __this: Value<{0}> = Rc::new(RefCell::new({1})); " "{2}::{3}(&__this.as_pointer(), {4})", GetRecordName(decl), value, GetUFCSName(op), diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 8ca3b6e8..6cdd6a77 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,15 +26,19 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new(|a1: i32| { - let __this: Value = Rc::new(RefCell::new(lambda_2 {})); - lambda_2Impl::operator_call(&__this.as_pointer(), a1) - }))); + let negate: Value i32>> = + Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } #[derive(Clone, Default)] pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} impl ByteRepr for lambda_2 { fn byte_size() -> usize { 1 @@ -46,16 +50,6 @@ impl ByteRepr for lambda_2 { } impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_2Impl::operator_call(&__this.as_pointer(), a1) - } -} -pub trait lambda_2Impl { - fn operator_call(&self, x: i32) -> i32; -} -impl lambda_2Impl for Ptr { - fn operator_call(&self, x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); + lambda_2::operator_call(a1) } } diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 730c20fc..a859d8da 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -25,6 +25,13 @@ fn main_0() -> i32 { } #[derive(Clone, Default)] pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call(x: i32, y: i32) -> bool { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + return ((*x.borrow()) < (*y.borrow())); + } +} impl ByteRepr for lambda_0 { fn byte_size() -> usize { 1 @@ -36,17 +43,6 @@ impl ByteRepr for lambda_0 { } impl Callable2 for lambda_0 { fn call(&self, a1: i32, a2: i32) -> bool { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_0Impl::operator_call(&__this.as_pointer(), a1, a2) - } -} -pub trait lambda_0Impl { - fn operator_call(&self, x: i32, y: i32) -> bool; -} -impl lambda_0Impl for Ptr { - fn operator_call(&self, x: i32, y: i32) -> bool { - let x: Value = Rc::new(RefCell::new(x)); - let y: Value = Rc::new(RefCell::new(y)); - return ((*x.borrow()) < (*y.borrow())); + lambda_0::operator_call(a1, a2) } } diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index ad4e1298..beac75e6 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -25,10 +25,7 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(|a1: i32| { - let __this: lambda_2 = lambda_2 {}; - unsafe { lambda_2::operator_call(&__this, a1) } - }); + let mut negate: Option i32> = Some(lambda_2::operator_call); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } @@ -36,13 +33,12 @@ unsafe fn main_0() -> i32 { #[derive(Copy, Clone, Default)] pub struct lambda_2 {} impl lambda_2 { - pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + pub unsafe fn operator_call(mut x: i32) -> i32 { return -x; } } impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - let __this: lambda_2 = self.clone(); - unsafe { lambda_2::operator_call(&__this, a1) } + unsafe { lambda_2::operator_call(a1) } } } diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index 7a9a821e..c62c17ce 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -34,13 +34,12 @@ unsafe fn main_0() -> i32 { #[derive(Copy, Clone, Default)] pub struct lambda_0 {} impl lambda_0 { - pub unsafe fn operator_call(&self, mut x: i32, mut y: i32) -> bool { + pub unsafe fn operator_call(mut x: i32, mut y: i32) -> bool { return ((x) < (y)); } } impl Callable2 for lambda_0 { fn call(&self, a1: i32, a2: i32) -> bool { - let __this: lambda_0 = self.clone(); - unsafe { lambda_0::operator_call(&__this, a1, a2) } + unsafe { lambda_0::operator_call(a1, a2) } } } From 70eff8357160965839f3cb1c9c3814b00041d221 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 20:18:40 +0100 Subject: [PATCH 20/43] Declare lambda to function cast inline --- cpp2rust/converter/converter.cpp | 42 +++++++---- cpp2rust/converter/converter.h | 3 +- .../converter/models/converter_refcount.cpp | 17 +---- .../converter/models/converter_refcount.h | 2 +- tests/unit/lambda_to_fn_ptr.cpp | 20 +++++ tests/unit/out/refcount/fn_ptr_default_arg.rs | 49 ++++++------ tests/unit/out/refcount/lambda_to_fn_ptr.rs | 74 +++++++++++++++++++ tests/unit/out/refcount/simple_index.rs | 4 +- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 30 ++++---- tests/unit/out/unsafe/lambda_to_fn_ptr.rs | 55 ++++++++++++++ tests/unit/out/unsafe/simple_index.rs | 2 +- 11 files changed, 226 insertions(+), 72 deletions(-) create mode 100644 tests/unit/lambda_to_fn_ptr.cpp create mode 100644 tests/unit/out/refcount/lambda_to_fn_ptr.rs create mode 100644 tests/unit/out/unsafe/lambda_to_fn_ptr.rs diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index d88445d5..991929c6 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2383,6 +2383,16 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } break; } + case clang::CastKind::CK_UserDefinedConversion: { + auto *call = clang::dyn_cast(sub_expr); + if (call && clang::isa(call->getMethodDecl()) && + call->getRecordDecl()->isLambda()) { + ConvertLambdaToFnPtr(call); + break; + } + Convert(sub_expr); + break; + } case clang::CastKind::CK_ConstructorConversion: case clang::CastKind::CK_DerivedToBase: Convert(sub_expr); @@ -3577,7 +3587,11 @@ bool Converter::VisitConstantExpr(clang::ConstantExpr *expr) { bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { auto *record = expr->getLambdaClass(); - ConvertLambdaClass(record); + { + Buffer buf(*this); + ConvertLambdaClass(record); + hoisted_records_ += std::move(buf).str(); + } PushParen paren(*this); StrCat(GetRecordName(record)); { @@ -3594,12 +3608,10 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { } void Converter::ConvertLambdaClass(clang::CXXRecordDecl *decl) { - Buffer buf(*this); std::vector saved_expr_kinds; saved_expr_kinds.swap(curr_expr_kind_); VisitCXXRecordDecl(decl); curr_expr_kind_.swap(saved_expr_kinds); - hoisted_records_ += std::move(buf).str(); } std::string Converter::LambdaCallParams(const clang::CXXMethodDecl *op, @@ -3649,11 +3661,20 @@ std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, GetRecordName(decl), value, GetUFCSName(op), GetMethodName(op), args); } -void Converter::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { - auto *decl = expr->getLambdaClass(); - ConvertLambdaClass(decl); +std::string Converter::LambdaFnPtr(const clang::CXXMethodDecl *op) { + return std::format("Some({}::{})", GetUFCSName(op), GetMethodName(op)); +} + +void Converter::ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call) { + auto *decl = call->getRecordDecl(); auto *op = decl->getLambdaCallOperator(); - StrCat("Some(", GetUFCSName(op), token::kDoubleColon, GetMethodName(op), ")"); + auto *object = call->getImplicitObjectArgument()->IgnoreParenImpCasts(); + bool fresh = clang::isa(object); + PushBrace brace(*this, fresh); + if (fresh) { + ConvertLambdaClass(decl); + } + StrCat(LambdaFnPtr(op)); computed_expr_type_ = ComputedExprType::FreshValue; } @@ -4092,13 +4113,6 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) { StrCat(keyword_mut_); } } - if (qual_type->isFunctionPointerType()) { - if (auto *lambda = clang::dyn_cast( - expr->IgnoreUnlessSpelledInSource())) { - ConvertLambdaAsFnPtr(lambda); - return; - } - } auto *ignore_casts = expr->IgnoreCasts(); // FIXME: this looks very complicated if (auto *ctor = clang::dyn_cast(ignore_casts); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index cdd6735e..7fa83e49 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -419,7 +419,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); virtual void ConvertLambdaClass(clang::CXXRecordDecl *decl); virtual void AddCallableTrait(clang::CXXRecordDecl *decl); - virtual void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr); + void ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call); + virtual std::string LambdaFnPtr(const clang::CXXMethodDecl *op); virtual std::string LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, std::string_view args); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 0bb37910..dd27f2a6 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2098,14 +2098,6 @@ ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::string ConverterRefCount::ConvertVarInitValue(clang::QualType qual_type, clang::Expr *expr) { - if (auto lambda = clang::dyn_cast( - expr->IgnoreUnlessSpelledInSource()); - lambda && qual_type->isFunctionPointerType()) { - Buffer buf(*this); - ConvertLambdaAsFnPtr(lambda); - return std::move(buf).str(); - } - PushInitType init_type(*this, qual_type); if (qual_type->isReferenceType() || qual_type->isFunctionPointerType()) { if (llvm::isa(expr->IgnoreImpCasts())) { @@ -2902,13 +2894,8 @@ void ConverterRefCount::ConvertLambdaClass(clang::CXXRecordDecl *decl) { conversion_kind_.swap(saved_conversion_kinds); } -void ConverterRefCount::ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) { - auto *decl = expr->getLambdaClass(); - ConvertLambdaClass(decl); - auto *op = decl->getLambdaCallOperator(); - StrCat("FnPtr::new(", GetUFCSName(op), token::kDoubleColon, GetMethodName(op), - ")"); - computed_expr_type_ = ComputedExprType::FreshValue; +std::string ConverterRefCount::LambdaFnPtr(const clang::CXXMethodDecl *op) { + return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); } std::string ConverterRefCount::LambdaCallBody(const clang::CXXRecordDecl *decl, diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 7b2bde07..33102303 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -90,7 +90,7 @@ class ConverterRefCount final : public Converter { bool VisitLambdaExpr(clang::LambdaExpr *expr) override; void ConvertLambdaClass(clang::CXXRecordDecl *decl) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; - void ConvertLambdaAsFnPtr(clang::LambdaExpr *expr) override; + std::string LambdaFnPtr(const clang::CXXMethodDecl *op) override; std::string LambdaCallBody(const clang::CXXRecordDecl *decl, std::string_view value, std::string_view args) override; diff --git a/tests/unit/lambda_to_fn_ptr.cpp b/tests/unit/lambda_to_fn_ptr.cpp new file mode 100644 index 00000000..47a0f596 --- /dev/null +++ b/tests/unit/lambda_to_fn_ptr.cpp @@ -0,0 +1,20 @@ +#include + +typedef int (*transform_t)(int); + +int apply(int x, transform_t fn) { return fn(x); } + +int main() { + transform_t fresh = [](int x) { return -x; }; + assert(fresh(5) == -5); + + auto twice = [](int x) { return x * 2; }; + transform_t named = twice; + assert(named(5) == 10); + assert(apply(5, twice) == 10); + + named = fresh; + assert(named(3) == -3); + + return 0; +} diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 6cdd6a77..6b030286 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,30 +26,31 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = - Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); + let negate: Value i32>> = Rc::new(RefCell::new({ + #[derive(Clone, Default)] + pub struct lambda_2 {} + impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } + } + impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } + } + impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + lambda_2::operator_call(a1) + } + } + FnPtr::new(lambda_2::operator_call) + })); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } -#[derive(Clone, Default)] -pub struct lambda_2 {} -impl lambda_2 { - pub fn operator_call(x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - } -} -impl ByteRepr for lambda_2 { - fn byte_size() -> usize { - 1 - } - fn to_bytes(&self, buf: &mut [u8]) {} - fn from_bytes(buf: &[u8]) -> Self { - Self {} - } -} -impl Callable1 for lambda_2 { - fn call(&self, a1: i32) -> i32 { - lambda_2::operator_call(a1) - } -} diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs new file mode 100644 index 00000000..acc18068 --- /dev/null +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -0,0 +1,74 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn apply_0(x: i32, fn_: FnPtr i32>) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let fn_: Value i32>> = Rc::new(RefCell::new(fn_)); + return ({ (*(*fn_.borrow()))((*x.borrow())) }); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let fresh: Value i32>> = Rc::new(RefCell::new({ + #[derive(Clone, Default)] + pub struct lambda_1 {} + impl lambda_1 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } + } + impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } + } + impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + lambda_1::operator_call(a1) + } + } + FnPtr::new(lambda_1::operator_call) + })); + assert!((({ (*(*fresh.borrow()))(5,) }) == -5_i32)); + let twice: Value = Rc::new(RefCell::new((lambda_2 {}))); + let named: Value i32>> = + Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); + assert!((({ (*(*named.borrow()))(5,) }) == 10)); + assert!((({ apply_0(5, FnPtr::new(lambda_2::operator_call),) }) == 10)); + (*named.borrow_mut()) = (*fresh.borrow()).clone(); + assert!((({ (*(*named.borrow()))(3,) }) == -3_i32)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * 2); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + lambda_2::operator_call(a1) + } +} diff --git a/tests/unit/out/refcount/simple_index.rs b/tests/unit/out/refcount/simple_index.rs index c8a2e507..2537300c 100644 --- a/tests/unit/out/refcount/simple_index.rs +++ b/tests/unit/out/refcount/simple_index.rs @@ -12,10 +12,10 @@ pub fn main() { fn main_0() -> i32 { let v: Value> = Rc::new(RefCell::new(vec![true])); assert!( - ((*(v.as_pointer() as Ptr) + (*(v.as_pointer() as Ptr) .offset(0_usize) .upgrade() - .deref()) as bool) + .deref()) ); return 0; } diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index beac75e6..58adb6e9 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -25,20 +25,22 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(lambda_2::operator_call); + let mut negate: Option i32> = { + #[repr(C)] + #[derive(Copy, Clone, Default)] + pub struct lambda_2 {} + impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } + } + impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } + } + Some(lambda_2::operator_call) + }; assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } -#[repr(C)] -#[derive(Copy, Clone, Default)] -pub struct lambda_2 {} -impl lambda_2 { - pub unsafe fn operator_call(mut x: i32) -> i32 { - return -x; - } -} -impl Callable1 for lambda_2 { - fn call(&self, a1: i32) -> i32 { - unsafe { lambda_2::operator_call(a1) } - } -} diff --git a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs new file mode 100644 index 00000000..5819a4a7 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs @@ -0,0 +1,55 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn apply_0(mut x: i32, mut fn_: Option i32>) -> i32 { + return (unsafe { (fn_).unwrap()(x) }); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut fresh: Option i32> = { + #[repr(C)] + #[derive(Copy, Clone, Default)] + pub struct lambda_1 {} + impl lambda_1 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } + } + impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(a1) } + } + } + Some(lambda_1::operator_call) + }; + assert!(((unsafe { (fresh).unwrap()(5,) }) == (-5_i32))); + let mut twice: lambda_2 = (lambda_2 {}); + let mut named: Option i32> = Some(lambda_2::operator_call); + assert!(((unsafe { (named).unwrap()(5,) }) == (10))); + assert!(((unsafe { apply_0(5, Some(lambda_2::operator_call),) }) == (10))); + named = fresh; + assert!(((unsafe { (named).unwrap()(3,) }) == (-3_i32))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return ((x) * (2)); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } +} diff --git a/tests/unit/out/unsafe/simple_index.rs b/tests/unit/out/unsafe/simple_index.rs index 98f29d04..1f45f495 100644 --- a/tests/unit/out/unsafe/simple_index.rs +++ b/tests/unit/out/unsafe/simple_index.rs @@ -13,6 +13,6 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut v: Vec = vec![true]; - assert!((v[(0_usize)] as bool)); + assert!(v[(0_usize)]); return 0; } From 03f4c99a9a50e1007075a9e8778eae9d17e64edb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 20:28:02 +0100 Subject: [PATCH 21/43] Always hoist lambdas --- cpp2rust/converter/converter.cpp | 34 ++++++------- cpp2rust/converter/converter.h | 2 +- .../converter/models/converter_refcount.cpp | 10 ++-- .../converter/models/converter_refcount.h | 1 - tests/unit/out/refcount/fn_ptr_default_arg.rs | 49 +++++++++---------- tests/unit/out/refcount/lambda_to_fn_ptr.rs | 49 +++++++++---------- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 30 ++++++------ tests/unit/out/unsafe/lambda_to_fn_ptr.rs | 30 ++++++------ 8 files changed, 96 insertions(+), 109 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 991929c6..61b67e71 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -908,10 +908,17 @@ void Converter::EmitRustUnion(clang::RecordDecl *decl) { bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { decl->dump(log()); + std::vector saved_expr_kinds; + saved_expr_kinds.swap(curr_expr_kind_); + ConvertCXXRecordDecl(decl); + curr_expr_kind_.swap(saved_expr_kinds); + return false; +} +void Converter::ConvertCXXRecordDecl(clang::CXXRecordDecl *decl) { Mapper::AddRuleForUserDefinedType(decl); if (!IsConvertibleCXXRecordDecl(decl)) { - return false; + return; } if (decl->isStruct() || decl->isClass()) { @@ -928,12 +935,12 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (clang::isa(decl)) { ConvertLateInstantiatedMethods(decl); } - return false; + return; } if (decl->isAbstract()) { ConvertAbstractClass(decl); - return false; + return; } sema_->ForceDeclarationOfImplicitMembers(decl); @@ -961,15 +968,13 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { - return false; + return; } EmitRustStructOrUnion(decl); } else { // FIXME: improve error handling assert(0 && "unsupported record kind"); } - - return false; } bool Converter::VisitCXXMethodDecl(clang::CXXMethodDecl *decl) { @@ -3589,7 +3594,7 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { auto *record = expr->getLambdaClass(); { Buffer buf(*this); - ConvertLambdaClass(record); + VisitCXXRecordDecl(record); hoisted_records_ += std::move(buf).str(); } PushParen paren(*this); @@ -3607,13 +3612,6 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { return false; } -void Converter::ConvertLambdaClass(clang::CXXRecordDecl *decl) { - std::vector saved_expr_kinds; - saved_expr_kinds.swap(curr_expr_kind_); - VisitCXXRecordDecl(decl); - curr_expr_kind_.swap(saved_expr_kinds); -} - std::string Converter::LambdaCallParams(const clang::CXXMethodDecl *op, std::string &args) { std::string params; @@ -3669,10 +3667,10 @@ void Converter::ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call) { auto *decl = call->getRecordDecl(); auto *op = decl->getLambdaCallOperator(); auto *object = call->getImplicitObjectArgument()->IgnoreParenImpCasts(); - bool fresh = clang::isa(object); - PushBrace brace(*this, fresh); - if (fresh) { - ConvertLambdaClass(decl); + if (clang::isa(object)) { + Buffer buf(*this); + VisitCXXRecordDecl(decl); + hoisted_records_ += std::move(buf).str(); } StrCat(LambdaFnPtr(op)); computed_expr_type_ = ComputedExprType::FreshValue; diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 7fa83e49..dda6d0f3 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -111,6 +111,7 @@ class Converter : public clang::RecursiveASTVisitor { bool VisitRecordDecl(clang::RecordDecl *decl); virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl); + void ConvertCXXRecordDecl(clang::CXXRecordDecl *decl); virtual void EmitRustStructOrUnion(clang::RecordDecl *decl); @@ -417,7 +418,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitConstantExpr(clang::ConstantExpr *expr); virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); - virtual void ConvertLambdaClass(clang::CXXRecordDecl *decl); virtual void AddCallableTrait(clang::CXXRecordDecl *decl); void ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call); virtual std::string LambdaFnPtr(const clang::CXXMethodDecl *op); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index dd27f2a6..1667aeb7 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -431,7 +431,10 @@ bool ConverterRefCount::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (decl_ids_.count(GetID(decl))) { return false; } + std::vector saved_conversion_kinds({ConversionKind::Unboxed}); + saved_conversion_kinds.swap(conversion_kind_); Converter::VisitCXXRecordDecl(decl); + conversion_kind_.swap(saved_conversion_kinds); return false; } @@ -2887,13 +2890,6 @@ void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { Converter::AddCallableTrait(decl); } -void ConverterRefCount::ConvertLambdaClass(clang::CXXRecordDecl *decl) { - std::vector saved_conversion_kinds({ConversionKind::Unboxed}); - saved_conversion_kinds.swap(conversion_kind_); - Converter::ConvertLambdaClass(decl); - conversion_kind_.swap(saved_conversion_kinds); -} - std::string ConverterRefCount::LambdaFnPtr(const clang::CXXMethodDecl *op) { return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); } diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 33102303..4323e52d 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -88,7 +88,6 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; bool VisitLambdaExpr(clang::LambdaExpr *expr) override; - void ConvertLambdaClass(clang::CXXRecordDecl *decl) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; std::string LambdaFnPtr(const clang::CXXMethodDecl *op) override; std::string LambdaCallBody(const clang::CXXRecordDecl *decl, diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 6b030286..6cdd6a77 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -26,31 +26,30 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new({ - #[derive(Clone, Default)] - pub struct lambda_2 {} - impl lambda_2 { - pub fn operator_call(x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - } - } - impl ByteRepr for lambda_2 { - fn byte_size() -> usize { - 1 - } - fn to_bytes(&self, buf: &mut [u8]) {} - fn from_bytes(buf: &[u8]) -> Self { - Self {} - } - } - impl Callable1 for lambda_2 { - fn call(&self, a1: i32) -> i32 { - lambda_2::operator_call(a1) - } - } - FnPtr::new(lambda_2::operator_call) - })); + let negate: Value i32>> = + Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + lambda_2::operator_call(a1) + } +} diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs index acc18068..6473f22f 100644 --- a/tests/unit/out/refcount/lambda_to_fn_ptr.rs +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -15,31 +15,8 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let fresh: Value i32>> = Rc::new(RefCell::new({ - #[derive(Clone, Default)] - pub struct lambda_1 {} - impl lambda_1 { - pub fn operator_call(x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - } - } - impl ByteRepr for lambda_1 { - fn byte_size() -> usize { - 1 - } - fn to_bytes(&self, buf: &mut [u8]) {} - fn from_bytes(buf: &[u8]) -> Self { - Self {} - } - } - impl Callable1 for lambda_1 { - fn call(&self, a1: i32) -> i32 { - lambda_1::operator_call(a1) - } - } - FnPtr::new(lambda_1::operator_call) - })); + let fresh: Value i32>> = + Rc::new(RefCell::new(FnPtr::new(lambda_1::operator_call))); assert!((({ (*(*fresh.borrow()))(5,) }) == -5_i32)); let twice: Value = Rc::new(RefCell::new((lambda_2 {}))); let named: Value i32>> = @@ -51,6 +28,28 @@ fn main_0() -> i32 { return 0; } #[derive(Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + lambda_1::operator_call(a1) + } +} +#[derive(Clone, Default)] pub struct lambda_2 {} impl lambda_2 { pub fn operator_call(x: i32) -> i32 { diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index 58adb6e9..beac75e6 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -25,22 +25,20 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct lambda_2 {} - impl lambda_2 { - pub unsafe fn operator_call(mut x: i32) -> i32 { - return -x; - } - } - impl Callable1 for lambda_2 { - fn call(&self, a1: i32) -> i32 { - unsafe { lambda_2::operator_call(a1) } - } - } - Some(lambda_2::operator_call) - }; + let mut negate: Option i32> = Some(lambda_2::operator_call); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } +} diff --git a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs index 5819a4a7..3108e6d9 100644 --- a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs +++ b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs @@ -15,22 +15,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut fresh: Option i32> = { - #[repr(C)] - #[derive(Copy, Clone, Default)] - pub struct lambda_1 {} - impl lambda_1 { - pub unsafe fn operator_call(mut x: i32) -> i32 { - return -x; - } - } - impl Callable1 for lambda_1 { - fn call(&self, a1: i32) -> i32 { - unsafe { lambda_1::operator_call(a1) } - } - } - Some(lambda_1::operator_call) - }; + let mut fresh: Option i32> = Some(lambda_1::operator_call); assert!(((unsafe { (fresh).unwrap()(5,) }) == (-5_i32))); let mut twice: lambda_2 = (lambda_2 {}); let mut named: Option i32> = Some(lambda_2::operator_call); @@ -42,6 +27,19 @@ unsafe fn main_0() -> i32 { } #[repr(C)] #[derive(Copy, Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] pub struct lambda_2 {} impl lambda_2 { pub unsafe fn operator_call(mut x: i32) -> i32 { From 73f0fa9e83c38c424aeb7e3677e8393c064c4ef9 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 20:43:36 +0100 Subject: [PATCH 22/43] Synthesize an init list expr in VisitLambdaExpr --- cpp2rust/converter/converter.cpp | 17 ++++++----------- .../converter/models/converter_refcount.cpp | 5 ----- cpp2rust/converter/models/converter_refcount.h | 1 - 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 61b67e71..0153cdb5 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3597,18 +3597,13 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { VisitCXXRecordDecl(record); hoisted_records_ += std::move(buf).str(); } + auto *init_list = new (ctx_) clang::InitListExpr( + ctx_, {}, + llvm::ArrayRef(expr->capture_init_begin(), expr->capture_size()), {}, + false); + init_list->setType(expr->getType()); PushParen paren(*this); - StrCat(GetRecordName(record)); - { - PushBrace brace(*this); - auto init = expr->capture_init_begin(); - for (auto *field : record->fields()) { - StrCat(GetNamedDeclAsString(field), token::kColon); - ConvertVarInit(field->getType(), *init++); - StrCat(token::kComma); - } - } - computed_expr_type_ = ComputedExprType::FreshValue; + Convert(init_list); return false; } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 1667aeb7..59b07330 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2880,11 +2880,6 @@ bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { return false; } -bool ConverterRefCount::VisitLambdaExpr(clang::LambdaExpr *expr) { - PushConversionKind push(*this, ConversionKind::FullRefCount); - return Converter::VisitLambdaExpr(expr); -} - void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { PushConversionKind push(*this, ConversionKind::Unboxed); Converter::AddCallableTrait(decl); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 4323e52d..fa01ac2d 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -87,7 +87,6 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; - bool VisitLambdaExpr(clang::LambdaExpr *expr) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; std::string LambdaFnPtr(const clang::CXXMethodDecl *op) override; std::string LambdaCallBody(const clang::CXXRecordDecl *decl, From d9bb6d210476aea9faebbd4f5feb9b07f2c8391b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 20:44:03 +0100 Subject: [PATCH 23/43] Use RAII --- cpp2rust/converter/converter.cpp | 19 ++++++++++++++----- cpp2rust/converter/converter.h | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 0153cdb5..7569bde9 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3630,13 +3630,22 @@ void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { auto params = LambdaCallParams(op, args); auto ret = op->getReturnType()->isVoidType() ? std::string("()") : ToString(op->getReturnType()); - StrCat(keyword::kImpl, std::format("Callable{}<", op->getNumParams())); - for (auto *p : op->parameters()) { - StrCat(ToString(p->getType()), token::kComma); + StrCat(keyword::kImpl, std::format("Callable{}", op->getNumParams())); + { + PushAngle angle(*this); + for (auto *p : op->parameters()) { + StrCat(ToString(p->getType()), token::kComma); + } + StrCat(ret); } - StrCat(ret, "> for", GetRecordName(decl)); + StrCat("for", GetRecordName(decl)); PushBrace impl_brace(*this); - StrCat(keyword::kFn, "call(&self,", params, ")", token::kArrow, ret); + StrCat(keyword::kFn, "call"); + { + PushParen paren(*this); + StrCat("&self,", params); + } + StrCat(token::kArrow, ret); PushBrace fn_brace(*this); StrCat(LambdaCallBody(decl, "self.clone()", args)); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index dda6d0f3..bd3e094a 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -498,6 +498,7 @@ class Converter : public clang::RecursiveASTVisitor { PushDelim; using PushParen = PushDelim; using PushBracket = PushDelim; + using PushAngle = PushDelim; template inline std::string From 6d1e2f43879ecb0b4aaa748b496d24a37616238c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:06:47 +0100 Subject: [PATCH 24/43] Assert on maxcallablearity --- cpp2rust/converter/converter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 7569bde9..771e68e0 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3623,7 +3623,8 @@ static constexpr unsigned kMaxCallableArity = 3; void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { auto *op = decl->getLambdaCallOperator(); - if (!op->isConst() || op->getNumParams() > kMaxCallableArity) { + assert(op->getNumParams() <= kMaxCallableArity); + if (!op->isConst()) { return; } std::string args; From 0f563576362191c993c7c6ba38eeaa0d5a30a106 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:07:54 +0100 Subject: [PATCH 25/43] Captured variables are declrefexpr pointing to vardecl --- cpp2rust/converter/converter.cpp | 25 ++++++++----------- cpp2rust/converter/converter.h | 2 +- .../converter/models/converter_refcount.cpp | 7 ++---- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 771e68e0..1a96d7af 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2849,6 +2849,9 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { } std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { + if (auto capture = LambdaCaptureName(expr->getDecl()); !capture.empty()) { + return capture; + } if (isAddrOf()) { clang::Expr *addrof_op = ToAddrOf(ctx_, expr); if (auto str = GetMappedAsString(addrof_op); !str.empty()) { @@ -2889,10 +2892,6 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { } bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { - if (auto *capture = LambdaCaptureAccess(expr->getDecl())) { - Convert(capture); - return false; - } auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); @@ -3169,7 +3168,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { if (IsCapturedThis(expr)) { - Convert(LambdaCaptureAccess(nullptr)); + StrCat(LambdaCaptureName(nullptr)); + computed_expr_type_ = ComputedExprType::Pointer; return false; } if (clang::isa(curr_function_)) { @@ -3681,20 +3681,16 @@ void Converter::ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call) { computed_expr_type_ = ComputedExprType::FreshValue; } -clang::MemberExpr *Converter::LambdaCaptureAccess(const clang::ValueDecl *var) { +std::string Converter::LambdaCaptureName(const clang::ValueDecl *var) const { auto *lambda = GetLambdaOf(curr_function_); if (!lambda) { - return nullptr; + return {}; } auto *field = GetLambdaCaptureField(lambda, var); if (!field) { - return nullptr; + return {}; } - auto *this_expr = clang::CXXThisExpr::Create( - ctx_, {}, lambda->getLambdaCallOperator()->getThisType(), true); - return clang::MemberExpr::CreateImplicit( - ctx_, this_expr, true, field, field->getType().getNonReferenceType(), - clang::VK_LValue, clang::OK_Ordinary); + return std::format("{}.{}", keyword::kSelfValue, GetNamedDeclAsString(field)); } bool Converter::IsCapturedThis(const clang::Expr *expr) const { @@ -3704,8 +3700,7 @@ bool Converter::IsCapturedThis(const clang::Expr *expr) const { return false; } auto *lambda = GetLambdaOf(curr_function_); - return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda && - GetLambdaCaptureField(lambda, nullptr); + return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda; } bool Converter::VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index bd3e094a..a776c61e 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -426,7 +426,7 @@ class Converter : public clang::RecursiveASTVisitor { std::string_view args); std::string LambdaCallParams(const clang::CXXMethodDecl *op, std::string &args); - clang::MemberExpr *LambdaCaptureAccess(const clang::ValueDecl *var); + std::string LambdaCaptureName(const clang::ValueDecl *var) const; bool IsCapturedThis(const clang::Expr *expr) const; virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 59b07330..94ec8283 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -816,10 +816,6 @@ bool ConverterRefCount::VisitConditionalOperator( } bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { - if (auto *capture = LambdaCaptureAccess(expr->getDecl())) { - Convert(capture); - return false; - } if (isAddrOf()) { clang::Expr *addrof_op = ToAddrOf(ctx_, expr); if (auto str = GetMappedAsString(addrof_op); !str.empty()) { @@ -2866,7 +2862,8 @@ void ConverterRefCount::ConvertCXXConstructorBody( bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { if (IsCapturedThis(expr)) { - Convert(LambdaCaptureAccess(nullptr)); + StrCat(LambdaCaptureName(nullptr)); + computed_expr_type_ = ComputedExprType::Pointer; return false; } bool in_ctor = From 0e0ef1031645b1d0437a512e3a8f8779b432dde4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:12:45 +0100 Subject: [PATCH 26/43] Implement operator_call on Self instead of Ptr --- cpp2rust/converter/converter.cpp | 36 +++++++-------- cpp2rust/converter/converter.h | 6 +-- cpp2rust/converter/converter_lib.cpp | 4 ++ .../converter/models/converter_refcount.cpp | 16 +------ .../converter/models/converter_refcount.h | 3 -- tests/unit/out/refcount/fn_ptr_default_arg.rs | 2 +- .../unit/out/refcount/lambda_capture_pass.rs | 40 +++++++---------- tests/unit/out/refcount/lambda_nested.rs | 44 +++++++------------ tests/unit/out/refcount/lambda_to_fn_ptr.rs | 4 +- tests/unit/out/refcount/stable_sort.rs | 2 +- tests/unit/out/unsafe/lambda_capture_pass.rs | 6 +-- tests/unit/out/unsafe/lambda_nested.rs | 6 +-- 12 files changed, 67 insertions(+), 102 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 1a96d7af..e3e81d0e 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2894,10 +2894,12 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); + auto *field = LambdaCaptureField(decl); + auto decl_t = field ? field->getType() : decl->getType(); - if (decl->getType()->getAs() && !isAddrOf() && + if (decl_t->getAs() && !isAddrOf() && !map_iter_decls_.contains(clang::dyn_cast(decl))) { - EmitDeref(std::move(str), decl->getType().getNonReferenceType()); + EmitDeref(std::move(str), decl_t.getNonReferenceType()); SetValueFreshness(expr->getType()); return false; } @@ -2912,9 +2914,8 @@ bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - if (!decl->getType()->getAs() && isAddrOf()) { - StrCat(token::kRef, decl->getType().isConstQualified() ? "" : keyword_mut_, - str); + if (!decl_t->getAs() && isAddrOf()) { + StrCat(token::kRef, decl_t.isConstQualified() ? "" : keyword_mut_, str); computed_expr_type_ = ComputedExprType::FreshPointer; return false; } @@ -3648,20 +3649,15 @@ void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { } StrCat(token::kArrow, ret); PushBrace fn_brace(*this); - StrCat(LambdaCallBody(decl, "self.clone()", args)); + StrCat(LambdaCallBody(decl, args)); } std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view value, std::string_view args) { auto *op = decl->getLambdaCallOperator(); - if (IsStaticMethod(op)) { - return std::format("unsafe {{ {0}::{1}({2}) }}", GetUFCSName(op), - GetMethodName(op), args); - } - return std::format( - "let __this: {0} = {1}; unsafe {{ {2}::{3}(&__this, {4}) }}", - GetRecordName(decl), value, GetUFCSName(op), GetMethodName(op), args); + auto receiver = IsStaticMethod(op) ? "" : "self,"; + return std::format("{} {{ {}::{}({}{}) }}", keyword_unsafe_, GetUFCSName(op), + GetMethodName(op), receiver, args); } std::string Converter::LambdaFnPtr(const clang::CXXMethodDecl *op) { @@ -3681,12 +3677,14 @@ void Converter::ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call) { computed_expr_type_ = ComputedExprType::FreshValue; } -std::string Converter::LambdaCaptureName(const clang::ValueDecl *var) const { +clang::FieldDecl * +Converter::LambdaCaptureField(const clang::ValueDecl *var) const { auto *lambda = GetLambdaOf(curr_function_); - if (!lambda) { - return {}; - } - auto *field = GetLambdaCaptureField(lambda, var); + return lambda ? GetLambdaCaptureField(lambda, var) : nullptr; +} + +std::string Converter::LambdaCaptureName(const clang::ValueDecl *var) const { + auto *field = LambdaCaptureField(var); if (!field) { return {}; } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index a776c61e..5712fbe0 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -421,11 +421,11 @@ class Converter : public clang::RecursiveASTVisitor { virtual void AddCallableTrait(clang::CXXRecordDecl *decl); void ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call); virtual std::string LambdaFnPtr(const clang::CXXMethodDecl *op); - virtual std::string LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view value, - std::string_view args); + std::string LambdaCallBody(const clang::CXXRecordDecl *decl, + std::string_view args); std::string LambdaCallParams(const clang::CXXMethodDecl *op, std::string &args); + clang::FieldDecl *LambdaCaptureField(const clang::ValueDecl *var) const; std::string LambdaCaptureName(const clang::ValueDecl *var) const; bool IsCapturedThis(const clang::Expr *expr) const; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index b99f7a12..bf44f416 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1001,6 +1001,10 @@ bool IsStaticMethod(const clang::CXXMethodDecl *method) { } bool IsMethodOnPtr(const clang::CXXMethodDecl *method) { + if (GetLambdaOf(method) && + method->getParent()->getLambdaCallOperator() == method) { + return false; + } if (method->isDeleted() || IsStaticMethod(method) || method->isVirtual() || clang::isa(method)) { return false; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 94ec8283..e4975ea9 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -852,7 +852,8 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - const auto decl_t = decl->getType(); + auto *field = LambdaCaptureField(decl); + const auto decl_t = field ? field->getType() : decl->getType(); if (IsGlobalVar(expr)) { auto tp = decl_t->isReferenceType() ? "Ptr" : "Value"; str = std::format("{}.with({}::clone)", str, std::move(tp)); @@ -2886,17 +2887,4 @@ std::string ConverterRefCount::LambdaFnPtr(const clang::CXXMethodDecl *op) { return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); } -std::string ConverterRefCount::LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view value, - std::string_view args) { - auto *op = decl->getLambdaCallOperator(); - if (IsStaticMethod(op)) { - return std::format("{0}::{1}({2})", GetUFCSName(op), GetMethodName(op), - args); - } - return std::format("let __this: Value<{0}> = Rc::new(RefCell::new({1})); " - "{2}::{3}(&__this.as_pointer(), {4})", - GetRecordName(decl), value, GetUFCSName(op), - GetMethodName(op), args); -} } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index fa01ac2d..ce8385e7 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -89,9 +89,6 @@ class ConverterRefCount final : public Converter { void AddCallableTrait(clang::CXXRecordDecl *decl) override; std::string LambdaFnPtr(const clang::CXXMethodDecl *op) override; - std::string LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view value, - std::string_view args) override; bool VisitDeclRefExpr(clang::DeclRefExpr *expr) override; diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 6cdd6a77..a7b3cb5c 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -50,6 +50,6 @@ impl ByteRepr for lambda_2 { } impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - lambda_2::operator_call(a1) + { lambda_2::operator_call(a1) } } } diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_capture_pass.rs index 430479d6..4e4b2360 100644 --- a/tests/unit/out/refcount/lambda_capture_pass.rs +++ b/tests/unit/out/refcount/lambda_capture_pass.rs @@ -9,12 +9,12 @@ use std::rc::{Rc, Weak}; pub fn apply_0(fn_: lambda_1, x: i32) -> i32 { let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return ({ lambda_1Impl::operator_call(&fn_.as_pointer(), (*x.borrow())) }); + return ({ lambda_1::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); } pub fn apply_2(fn_: lambda_3, x: i32) -> i32 { let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return ({ lambda_3Impl::operator_call(&fn_.as_pointer(), (*x.borrow())) }); + return ({ lambda_3::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); } pub fn main() { std::process::exit(main_0()); @@ -42,17 +42,28 @@ fn main_0() -> i32 { pub struct lambda_1 { base: Ptr, } +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} impl ByteRepr for lambda_1 {} impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_1Impl::operator_call(&__this.as_pointer(), a1) + { lambda_1::operator_call(self, a1) } } } #[derive(Default)] pub struct lambda_3 { factor: Value, } +impl lambda_3 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*self.factor.borrow())); + } +} impl Clone for lambda_3 { fn clone(&self) -> Self { Self { @@ -75,25 +86,6 @@ impl ByteRepr for lambda_3 { } impl Callable1 for lambda_3 { fn call(&self, a1: i32) -> i32 { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_3Impl::operator_call(&__this.as_pointer(), a1) - } -} -pub trait lambda_1Impl { - fn operator_call(&self, x: i32) -> i32; -} -impl lambda_1Impl for Ptr { - fn operator_call(&self, x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return ((*x.borrow()) + ((*(*self).upgrade().deref()).base.read())); - } -} -pub trait lambda_3Impl { - fn operator_call(&self, x: i32) -> i32; -} -impl lambda_3Impl for Ptr { - fn operator_call(&self, x: i32) -> i32 { - let x: Value = Rc::new(RefCell::new(x)); - return ((*x.borrow()) * (*(*(*self).upgrade().deref()).factor.borrow())); + { lambda_3::operator_call(self, a1) } } } diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index 62d22448..4fb9192d 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -12,9 +12,9 @@ pub fn main() { fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(10)); let outer: Value = Rc::new(RefCell::new((lambda_0 { x: x.as_pointer() }))); - assert!((({ lambda_0Impl::operator_call(&outer.as_pointer(), 20,) }) == 31)); + assert!((({ lambda_0::operator_call(&(*outer.borrow_mut()), 20,) }) == 31)); (*x.borrow_mut()) = 100; - assert!((({ lambda_0Impl::operator_call(&outer.as_pointer(), 20,) }) == 121)); + assert!((({ lambda_0::operator_call(&(*outer.borrow_mut()), 20,) }) == 121)); return 0; } #[derive(Default)] @@ -22,6 +22,12 @@ pub struct lambda_1 { x: Ptr, y: Value, } +impl lambda_1 { + pub fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((self.x.read()) + (*self.y.borrow())) + (*z.borrow())); + } +} impl Clone for lambda_1 { fn clone(&self) -> Self { Self { @@ -33,44 +39,28 @@ impl Clone for lambda_1 { impl ByteRepr for lambda_1 {} impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_1Impl::operator_call(&__this.as_pointer(), a1) + { lambda_1::operator_call(self, a1) } } } #[derive(Clone, Default)] pub struct lambda_0 { x: Ptr, } -impl ByteRepr for lambda_0 {} -impl Callable1 for lambda_0 { - fn call(&self, a1: i32) -> i32 { - let __this: Value = Rc::new(RefCell::new(self.clone())); - lambda_0Impl::operator_call(&__this.as_pointer(), a1) - } -} -pub trait lambda_0Impl { - fn operator_call(&self, y: i32) -> i32; -} -impl lambda_0Impl for Ptr { - fn operator_call(&self, y: i32) -> i32 { +impl lambda_0 { + pub fn operator_call(&self, y: i32) -> i32 { let y: Value = Rc::new(RefCell::new(y)); let inner: Value = Rc::new(RefCell::new( (lambda_1 { - x: ((*(*self).upgrade().deref()).x).clone(), + x: (self.x).clone(), y: Rc::new(RefCell::new((*y.borrow()))), }), )); - return ({ lambda_1Impl::operator_call(&inner.as_pointer(), 1) }); + return ({ lambda_1::operator_call(&(*inner.borrow_mut()), 1) }); } } -pub trait lambda_1Impl { - fn operator_call(&self, z: i32) -> i32; -} -impl lambda_1Impl for Ptr { - fn operator_call(&self, z: i32) -> i32 { - let z: Value = Rc::new(RefCell::new(z)); - return ((((*(*self).upgrade().deref()).x.read()) - + (*(*(*self).upgrade().deref()).y.borrow())) - + (*z.borrow())); +impl ByteRepr for lambda_0 {} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } } } diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs index 6473f22f..0a5bb7fa 100644 --- a/tests/unit/out/refcount/lambda_to_fn_ptr.rs +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -46,7 +46,7 @@ impl ByteRepr for lambda_1 { } impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { - lambda_1::operator_call(a1) + { lambda_1::operator_call(a1) } } } #[derive(Clone, Default)] @@ -68,6 +68,6 @@ impl ByteRepr for lambda_2 { } impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - lambda_2::operator_call(a1) + { lambda_2::operator_call(a1) } } } diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index a859d8da..e0a23e47 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -43,6 +43,6 @@ impl ByteRepr for lambda_0 { } impl Callable2 for lambda_0 { fn call(&self, a1: i32, a2: i32) -> bool { - lambda_0::operator_call(a1, a2) + { lambda_0::operator_call(a1, a2) } } } diff --git a/tests/unit/out/unsafe/lambda_capture_pass.rs b/tests/unit/out/unsafe/lambda_capture_pass.rs index 99366db7..82033c01 100644 --- a/tests/unit/out/unsafe/lambda_capture_pass.rs +++ b/tests/unit/out/unsafe/lambda_capture_pass.rs @@ -40,8 +40,7 @@ impl lambda_1 { } impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { - let __this: lambda_1 = self.clone(); - unsafe { lambda_1::operator_call(&__this, a1) } + unsafe { lambda_1::operator_call(self, a1) } } } #[repr(C)] @@ -56,7 +55,6 @@ impl lambda_3 { } impl Callable1 for lambda_3 { fn call(&self, a1: i32) -> i32 { - let __this: lambda_3 = self.clone(); - unsafe { lambda_3::operator_call(&__this, a1) } + unsafe { lambda_3::operator_call(self, a1) } } } diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index 6381f56c..65af1acd 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -32,8 +32,7 @@ impl lambda_1 { } impl Callable1 for lambda_1 { fn call(&self, a1: i32) -> i32 { - let __this: lambda_1 = self.clone(); - unsafe { lambda_1::operator_call(&__this, a1) } + unsafe { lambda_1::operator_call(self, a1) } } } #[repr(C)] @@ -52,7 +51,6 @@ impl lambda_0 { } impl Callable1 for lambda_0 { fn call(&self, a1: i32) -> i32 { - let __this: lambda_0 = self.clone(); - unsafe { lambda_0::operator_call(&__this, a1) } + unsafe { lambda_0::operator_call(self, a1) } } } From d6a2d09c989360a4001c89e34f2d3c02dc830af1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:17:09 +0100 Subject: [PATCH 27/43] Inline functions --- cpp2rust/converter/converter.cpp | 61 ++++++++++++-------------------- cpp2rust/converter/converter.h | 5 --- 2 files changed, 23 insertions(+), 43 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e3e81d0e..4105d87a 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2392,7 +2392,15 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { auto *call = clang::dyn_cast(sub_expr); if (call && clang::isa(call->getMethodDecl()) && call->getRecordDecl()->isLambda()) { - ConvertLambdaToFnPtr(call); + auto *decl = call->getRecordDecl(); + if (clang::isa( + call->getImplicitObjectArgument()->IgnoreParenImpCasts())) { + Buffer buf(*this); + VisitCXXRecordDecl(decl); + hoisted_records_ += std::move(buf).str(); + } + StrCat(LambdaFnPtr(decl->getLambdaCallOperator())); + computed_expr_type_ = ComputedExprType::FreshValue; break; } Convert(sub_expr); @@ -3608,18 +3616,6 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) { return false; } -std::string Converter::LambdaCallParams(const clang::CXXMethodDecl *op, - std::string &args) { - std::string params; - unsigned i = 0; - for (auto *p : op->parameters()) { - auto name = std::format("a{}", ++i); - params += std::format("{}: {},", name, ToString(p->getType())); - args += name + ','; - } - return params; -} - static constexpr unsigned kMaxCallableArity = 3; void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { @@ -3628,8 +3624,6 @@ void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { if (!op->isConst()) { return; } - std::string args; - auto params = LambdaCallParams(op, args); auto ret = op->getReturnType()->isVoidType() ? std::string("()") : ToString(op->getReturnType()); StrCat(keyword::kImpl, std::format("Callable{}", op->getNumParams())); @@ -3645,38 +3639,29 @@ void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { StrCat(keyword::kFn, "call"); { PushParen paren(*this); - StrCat("&self,", params); + StrCat("&self,"); + for (unsigned i = 0; auto *p : op->parameters()) { + StrCat(std::format("a{}:", ++i), ToString(p->getType()), token::kComma); + } } StrCat(token::kArrow, ret); PushBrace fn_brace(*this); - StrCat(LambdaCallBody(decl, args)); -} - -std::string Converter::LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view args) { - auto *op = decl->getLambdaCallOperator(); - auto receiver = IsStaticMethod(op) ? "" : "self,"; - return std::format("{} {{ {}::{}({}{}) }}", keyword_unsafe_, GetUFCSName(op), - GetMethodName(op), receiver, args); + StrCat(keyword_unsafe_); + PushBrace unsafe_brace(*this); + StrCat(GetUFCSName(op), token::kDoubleColon, GetMethodName(op)); + PushParen call_paren(*this); + if (!IsStaticMethod(op)) { + StrCat("self,"); + } + for (unsigned i = 0; i < op->getNumParams(); ++i) { + StrCat(std::format("a{},", i + 1)); + } } std::string Converter::LambdaFnPtr(const clang::CXXMethodDecl *op) { return std::format("Some({}::{})", GetUFCSName(op), GetMethodName(op)); } -void Converter::ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call) { - auto *decl = call->getRecordDecl(); - auto *op = decl->getLambdaCallOperator(); - auto *object = call->getImplicitObjectArgument()->IgnoreParenImpCasts(); - if (clang::isa(object)) { - Buffer buf(*this); - VisitCXXRecordDecl(decl); - hoisted_records_ += std::move(buf).str(); - } - StrCat(LambdaFnPtr(op)); - computed_expr_type_ = ComputedExprType::FreshValue; -} - clang::FieldDecl * Converter::LambdaCaptureField(const clang::ValueDecl *var) const { auto *lambda = GetLambdaOf(curr_function_); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 5712fbe0..1d066b15 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -419,12 +419,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); virtual void AddCallableTrait(clang::CXXRecordDecl *decl); - void ConvertLambdaToFnPtr(clang::CXXMemberCallExpr *call); virtual std::string LambdaFnPtr(const clang::CXXMethodDecl *op); - std::string LambdaCallBody(const clang::CXXRecordDecl *decl, - std::string_view args); - std::string LambdaCallParams(const clang::CXXMethodDecl *op, - std::string &args); clang::FieldDecl *LambdaCaptureField(const clang::ValueDecl *var) const; std::string LambdaCaptureName(const clang::ValueDecl *var) const; bool IsCapturedThis(const clang::Expr *expr) const; From 8777d622f4161aad5716e8e145df35442824204c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:18:45 +0100 Subject: [PATCH 28/43] Rename --- cpp2rust/converter/converter.cpp | 5 +++-- cpp2rust/converter/converter.h | 8 +++++++- cpp2rust/converter/models/converter_refcount.cpp | 3 ++- cpp2rust/converter/models/converter_refcount.h | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 4105d87a..5ee30db1 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2399,7 +2399,7 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { VisitCXXRecordDecl(decl); hoisted_records_ += std::move(buf).str(); } - StrCat(LambdaFnPtr(decl->getLambdaCallOperator())); + StrCat(ConvertLambdaToFunctionPointer(decl->getLambdaCallOperator())); computed_expr_type_ = ComputedExprType::FreshValue; break; } @@ -3658,7 +3658,8 @@ void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { } } -std::string Converter::LambdaFnPtr(const clang::CXXMethodDecl *op) { +std::string +Converter::ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) { return std::format("Some({}::{})", GetUFCSName(op), GetMethodName(op)); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 1d066b15..4bb66f7b 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -418,10 +418,16 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool VisitConstantExpr(clang::ConstantExpr *expr); virtual bool VisitLambdaExpr(clang::LambdaExpr *expr); + virtual void AddCallableTrait(clang::CXXRecordDecl *decl); - virtual std::string LambdaFnPtr(const clang::CXXMethodDecl *op); + + virtual std::string + ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op); + clang::FieldDecl *LambdaCaptureField(const clang::ValueDecl *var) const; + std::string LambdaCaptureName(const clang::ValueDecl *var) const; + bool IsCapturedThis(const clang::Expr *expr) const; virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e4975ea9..6ee138cc 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2883,7 +2883,8 @@ void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { Converter::AddCallableTrait(decl); } -std::string ConverterRefCount::LambdaFnPtr(const clang::CXXMethodDecl *op) { +std::string ConverterRefCount::ConvertLambdaToFunctionPointer( + const clang::CXXMethodDecl *op) { return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); } diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index ce8385e7..5b988473 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -88,7 +88,8 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; - std::string LambdaFnPtr(const clang::CXXMethodDecl *op) override; + std::string + ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) override; bool VisitDeclRefExpr(clang::DeclRefExpr *expr) override; From e66082e7e4215f395e8fe1a238a816621ead4b73 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 16 Sep 2026 21:32:37 +0100 Subject: [PATCH 29/43] Add to_free_function operator --- cpp2rust/converter/converter.cpp | 37 +++++++++---------- cpp2rust/converter/converter.h | 2 + cpp2rust/converter/converter_lib.cpp | 3 ++ .../converter/models/converter_refcount.cpp | 6 +++ .../converter/models/converter_refcount.h | 1 + tests/unit/out/refcount/fn_ptr_default_arg.rs | 7 +++- tests/unit/out/refcount/lambda_to_fn_ptr.rs | 16 ++++++-- tests/unit/out/refcount/simple_index.rs | 4 +- tests/unit/out/refcount/stable_sort.rs | 5 +++ tests/unit/out/unsafe/fn_ptr_default_arg.rs | 7 +++- tests/unit/out/unsafe/lambda_to_fn_ptr.rs | 16 ++++++-- tests/unit/out/unsafe/simple_index.rs | 2 +- tests/unit/out/unsafe/stable_sort.rs | 5 +++ 13 files changed, 81 insertions(+), 30 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 5ee30db1..16fad05e 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -965,6 +965,7 @@ void Converter::ConvertCXXRecordDecl(clang::CXXRecordDecl *decl) { EmitRustStructOrUnion(decl); if (decl->isLambda()) { AddCallableTrait(decl); + AddFunctionPointerConversion(decl); } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { @@ -2388,24 +2389,6 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } break; } - case clang::CastKind::CK_UserDefinedConversion: { - auto *call = clang::dyn_cast(sub_expr); - if (call && clang::isa(call->getMethodDecl()) && - call->getRecordDecl()->isLambda()) { - auto *decl = call->getRecordDecl(); - if (clang::isa( - call->getImplicitObjectArgument()->IgnoreParenImpCasts())) { - Buffer buf(*this); - VisitCXXRecordDecl(decl); - hoisted_records_ += std::move(buf).str(); - } - StrCat(ConvertLambdaToFunctionPointer(decl->getLambdaCallOperator())); - computed_expr_type_ = ComputedExprType::FreshValue; - break; - } - Convert(sub_expr); - break; - } case clang::CastKind::CK_ConstructorConversion: case clang::CastKind::CK_DerivedToBase: Convert(sub_expr); @@ -3169,7 +3152,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { StrCat(GetOverloadedFunctionName(method)); } else if (!name_override.empty()) { StrCat(token::kDot, name_override); - } else if (member->getDeclName().isIdentifier()) { + } else if (member->getDeclName().isIdentifier() || + clang::isa(member)) { StrCat(token::kDot); StrCat(GetNamedDeclAsString(member)); } @@ -3663,6 +3647,21 @@ Converter::ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) { return std::format("Some({}::{})", GetUFCSName(op), GetMethodName(op)); } +void Converter::AddFunctionPointerConversion(clang::CXXRecordDecl *decl) { + for (auto *method : decl->methods()) { + auto *conv = clang::dyn_cast(method); + if (!conv) { + continue; + } + StrCat(keyword::kImpl, GetRecordName(decl)); + PushBrace impl_brace(*this); + StrCat("pub fn", GetMethodName(conv), "(&self)", token::kArrow, + ToString(conv->getConversionType())); + PushBrace fn_brace(*this); + StrCat(ConvertLambdaToFunctionPointer(decl->getLambdaCallOperator())); + } +} + clang::FieldDecl * Converter::LambdaCaptureField(const clang::ValueDecl *var) const { auto *lambda = GetLambdaOf(curr_function_); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 4bb66f7b..0f6e2aee 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -421,6 +421,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void AddCallableTrait(clang::CXXRecordDecl *decl); + virtual void AddFunctionPointerConversion(clang::CXXRecordDecl *decl); + virtual std::string ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index bf44f416..0224a612 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -900,6 +900,9 @@ bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) { std::string GetFunctionBaseName(const clang::FunctionDecl *decl) { if (auto *conversion = clang::dyn_cast(decl)) { + if (conversion->getParent()->isLambda()) { + return "to_free_function"; + } auto name = "operator_" + conversion->getConversionType().getAsString(); std::replace_if( name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_'); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 6ee138cc..e43f4db0 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2883,6 +2883,12 @@ void ConverterRefCount::AddCallableTrait(clang::CXXRecordDecl *decl) { Converter::AddCallableTrait(decl); } +void ConverterRefCount::AddFunctionPointerConversion( + clang::CXXRecordDecl *decl) { + PushConversionKind push(*this, ConversionKind::Unboxed); + Converter::AddFunctionPointerConversion(decl); +} + std::string ConverterRefCount::ConvertLambdaToFunctionPointer( const clang::CXXMethodDecl *op) { return std::format("FnPtr::new({}::{})", GetUFCSName(op), GetMethodName(op)); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 5b988473..276f5950 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -88,6 +88,7 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; + void AddFunctionPointerConversion(clang::CXXRecordDecl *decl) override; std::string ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) override; diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index a7b3cb5c..a436551f 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -27,7 +27,7 @@ fn main_0() -> i32 { assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); let negate: Value i32>> = - Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); + Rc::new(RefCell::new(({ (lambda_2 {}).to_free_function() }))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } @@ -53,3 +53,8 @@ impl Callable1 for lambda_2 { { lambda_2::operator_call(a1) } } } +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs index 0a5bb7fa..78e109e9 100644 --- a/tests/unit/out/refcount/lambda_to_fn_ptr.rs +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -16,13 +16,13 @@ pub fn main() { } fn main_0() -> i32 { let fresh: Value i32>> = - Rc::new(RefCell::new(FnPtr::new(lambda_1::operator_call))); + Rc::new(RefCell::new(({ (lambda_1 {}).to_free_function() }))); assert!((({ (*(*fresh.borrow()))(5,) }) == -5_i32)); let twice: Value = Rc::new(RefCell::new((lambda_2 {}))); let named: Value i32>> = - Rc::new(RefCell::new(FnPtr::new(lambda_2::operator_call))); + Rc::new(RefCell::new(({ (*twice.borrow()).to_free_function() }))); assert!((({ (*(*named.borrow()))(5,) }) == 10)); - assert!((({ apply_0(5, FnPtr::new(lambda_2::operator_call),) }) == 10)); + assert!((({ apply_0(5, ({ (*twice.borrow()).to_free_function() }),) }) == 10)); (*named.borrow_mut()) = (*fresh.borrow()).clone(); assert!((({ (*(*named.borrow()))(3,) }) == -3_i32)); return 0; @@ -49,6 +49,11 @@ impl Callable1 for lambda_1 { { lambda_1::operator_call(a1) } } } +impl lambda_1 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_1::operator_call) + } +} #[derive(Clone, Default)] pub struct lambda_2 {} impl lambda_2 { @@ -71,3 +76,8 @@ impl Callable1 for lambda_2 { { lambda_2::operator_call(a1) } } } +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} diff --git a/tests/unit/out/refcount/simple_index.rs b/tests/unit/out/refcount/simple_index.rs index 2537300c..c8a2e507 100644 --- a/tests/unit/out/refcount/simple_index.rs +++ b/tests/unit/out/refcount/simple_index.rs @@ -12,10 +12,10 @@ pub fn main() { fn main_0() -> i32 { let v: Value> = Rc::new(RefCell::new(vec![true])); assert!( - (*(v.as_pointer() as Ptr) + ((*(v.as_pointer() as Ptr) .offset(0_usize) .upgrade() - .deref()) + .deref()) as bool) ); return 0; } diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index e0a23e47..0ddcb62c 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -46,3 +46,8 @@ impl Callable2 for lambda_0 { { lambda_0::operator_call(a1, a2) } } } +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr bool> { + FnPtr::new(lambda_0::operator_call) + } +} diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index beac75e6..af59e156 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -25,7 +25,7 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(lambda_2::operator_call); + let mut negate: Option i32> = (unsafe { (lambda_2 {}).to_free_function() }); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } @@ -42,3 +42,8 @@ impl Callable1 for lambda_2 { unsafe { lambda_2::operator_call(a1) } } } +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} diff --git a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs index 3108e6d9..26d137d3 100644 --- a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs +++ b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs @@ -15,12 +15,12 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut fresh: Option i32> = Some(lambda_1::operator_call); + let mut fresh: Option i32> = (unsafe { (lambda_1 {}).to_free_function() }); assert!(((unsafe { (fresh).unwrap()(5,) }) == (-5_i32))); let mut twice: lambda_2 = (lambda_2 {}); - let mut named: Option i32> = Some(lambda_2::operator_call); + let mut named: Option i32> = (unsafe { twice.to_free_function() }); assert!(((unsafe { (named).unwrap()(5,) }) == (10))); - assert!(((unsafe { apply_0(5, Some(lambda_2::operator_call),) }) == (10))); + assert!(((unsafe { apply_0(5, (unsafe { twice.to_free_function() }),) }) == (10))); named = fresh; assert!(((unsafe { (named).unwrap()(3,) }) == (-3_i32))); return 0; @@ -38,6 +38,11 @@ impl Callable1 for lambda_1 { unsafe { lambda_1::operator_call(a1) } } } +impl lambda_1 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_1::operator_call) + } +} #[repr(C)] #[derive(Copy, Clone, Default)] pub struct lambda_2 {} @@ -51,3 +56,8 @@ impl Callable1 for lambda_2 { unsafe { lambda_2::operator_call(a1) } } } +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} diff --git a/tests/unit/out/unsafe/simple_index.rs b/tests/unit/out/unsafe/simple_index.rs index 1f45f495..98f29d04 100644 --- a/tests/unit/out/unsafe/simple_index.rs +++ b/tests/unit/out/unsafe/simple_index.rs @@ -13,6 +13,6 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut v: Vec = vec![true]; - assert!(v[(0_usize)]); + assert!((v[(0_usize)] as bool)); return 0; } diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index c62c17ce..57c12753 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -43,3 +43,8 @@ impl Callable2 for lambda_0 { unsafe { lambda_0::operator_call(a1, a2) } } } +impl lambda_0 { + pub fn to_free_function(&self) -> Option bool> { + Some(lambda_0::operator_call) + } +} From 813cc6fa7a0c04253851113850b924df272281fa Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 09:36:13 +0100 Subject: [PATCH 30/43] Move lambda functions in _lib --- cpp2rust/converter/converter.cpp | 37 ++++--------------- cpp2rust/converter/converter.h | 6 --- cpp2rust/converter/converter_lib.cpp | 34 +++++++++++++++++ cpp2rust/converter/converter_lib.h | 8 ++++ .../converter/models/converter_refcount.cpp | 8 ++-- 5 files changed, 53 insertions(+), 40 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 16fad05e..7333ecd4 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2840,7 +2840,8 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { } std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { - if (auto capture = LambdaCaptureName(expr->getDecl()); !capture.empty()) { + if (auto capture = GetLambdaCaptureName(curr_function_, expr->getDecl()); + !capture.empty()) { return capture; } if (isAddrOf()) { @@ -2885,7 +2886,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); - auto *field = LambdaCaptureField(decl); + auto *field = GetLambdaCapturedField(curr_function_, decl); auto decl_t = field ? field->getType() : decl->getType(); if (decl_t->getAs() && !isAddrOf() && @@ -3059,7 +3060,7 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, const clang::CXXMethodDecl *method) { if (clang::isa(base->IgnoreParenImpCasts()) && - !IsCapturedThis(base)) { + !IsCapturedThis(curr_function_, base)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); ufcs_receiver_ = in_ctor ? "&mut this" : keyword::kSelfValue; @@ -3134,7 +3135,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()) && - !ThisIsRustPtr() && !IsCapturedThis(base); + !ThisIsRustPtr() && !IsCapturedThis(curr_function_, base); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); if (base_is_this) { StrCat(clang::isa(curr_function_) @@ -3160,8 +3161,8 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { - if (IsCapturedThis(expr)) { - StrCat(LambdaCaptureName(nullptr)); + if (IsCapturedThis(curr_function_, expr)) { + StrCat(GetLambdaCaptureName(curr_function_, nullptr)); computed_expr_type_ = ComputedExprType::Pointer; return false; } @@ -3662,30 +3663,6 @@ void Converter::AddFunctionPointerConversion(clang::CXXRecordDecl *decl) { } } -clang::FieldDecl * -Converter::LambdaCaptureField(const clang::ValueDecl *var) const { - auto *lambda = GetLambdaOf(curr_function_); - return lambda ? GetLambdaCaptureField(lambda, var) : nullptr; -} - -std::string Converter::LambdaCaptureName(const clang::ValueDecl *var) const { - auto *field = LambdaCaptureField(var); - if (!field) { - return {}; - } - return std::format("{}.{}", keyword::kSelfValue, GetNamedDeclAsString(field)); -} - -bool Converter::IsCapturedThis(const clang::Expr *expr) const { - auto *this_expr = - clang::dyn_cast(expr->IgnoreParenImpCasts()); - if (!this_expr) { - return false; - } - auto *lambda = GetLambdaOf(curr_function_); - return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda; -} - bool Converter::VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr) { if (auto arr_ty = clang::dyn_cast( expr->getType()->getCanonicalTypeInternal().getTypePtr())) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 0f6e2aee..45b24693 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -426,12 +426,6 @@ class Converter : public clang::RecursiveASTVisitor { virtual std::string ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op); - clang::FieldDecl *LambdaCaptureField(const clang::ValueDecl *var) const; - - std::string LambdaCaptureName(const clang::ValueDecl *var) const; - - bool IsCapturedThis(const clang::Expr *expr) const; - virtual bool VisitImplicitValueInitExpr(clang::ImplicitValueInitExpr *expr); virtual bool VisitCXXScalarValueInitExpr(clang::CXXScalarValueInitExpr *expr); diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 0224a612..d838d272 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -653,6 +653,40 @@ const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn) { return method->getParent(); } +clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, + const clang::ValueDecl *var) { + if (!fn) { + return nullptr; + } + auto *lambda = GetLambdaOf(fn); + return lambda ? GetLambdaCaptureField(lambda, var) : nullptr; +} + +std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, + const clang::ValueDecl *var) { + if (!fn) { + return {}; + } + auto *field = GetLambdaCapturedField(fn, var); + if (!field) { + return {}; + } + return std::format("{}.{}", keyword::kSelfValue, GetNamedDeclAsString(field)); +} + +bool IsCapturedThis(const clang::FunctionDecl *fn, const clang::Expr *expr) { + if (!fn) { + return false; + } + auto *this_expr = + clang::dyn_cast(expr->IgnoreParenImpCasts()); + if (!this_expr) { + return false; + } + auto *lambda = GetLambdaOf(fn); + return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda; +} + std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 778d7c32..f65aabb9 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -174,6 +174,14 @@ clang::FieldDecl *GetLambdaCaptureField(const clang::CXXRecordDecl *lambda, const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); +clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, + const clang::ValueDecl *var); + +std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, + const clang::ValueDecl *var); + +bool IsCapturedThis(const clang::FunctionDecl *fn, const clang::Expr *expr); + std::vector GetNestedStructs(const clang::CXXRecordDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index e43f4db0..eb1cd317 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -852,7 +852,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - auto *field = LambdaCaptureField(decl); + auto *field = GetLambdaCapturedField(curr_function_, decl); const auto decl_t = field ? field->getType() : decl->getType(); if (IsGlobalVar(expr)) { auto tp = decl_t->isReferenceType() ? "Ptr" : "Value"; @@ -2685,7 +2685,7 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow, bool base_is_pointer = is_arrow && !clang::isa( base->IgnoreParenImpCasts()); if (clang::isa(base->IgnoreParenImpCasts()) && - !IsCapturedThis(base)) { + !IsCapturedThis(curr_function_, base)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2862,8 +2862,8 @@ void ConverterRefCount::ConvertCXXConstructorBody( } bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { - if (IsCapturedThis(expr)) { - StrCat(LambdaCaptureName(nullptr)); + if (IsCapturedThis(curr_function_, expr)) { + StrCat(GetLambdaCaptureName(curr_function_, nullptr)); computed_expr_type_ = ComputedExprType::Pointer; return false; } From 7ec42f577e221350dcf931ca81a4e0944ab0c374 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 09:44:05 +0100 Subject: [PATCH 31/43] Remvove duplicated function --- cpp2rust/converter/converter_lib.cpp | 25 ++++++++++--------------- cpp2rust/converter/converter_lib.h | 3 --- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index d838d272..0200ee00 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -633,18 +633,6 @@ const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field) { return nullptr; } -clang::FieldDecl *GetLambdaCaptureField(const clang::CXXRecordDecl *lambda, - const clang::ValueDecl *var) { - llvm::DenseMap captures; - clang::FieldDecl *this_capture = nullptr; - lambda->getCaptureFields(captures, this_capture); - if (!var) { - return this_capture; - } - auto it = captures.find(var); - return it == captures.end() ? nullptr : it->second; -} - const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn) { auto *method = clang::dyn_cast_or_null(fn); if (!method || !method->getParent()->isLambda()) { @@ -655,11 +643,18 @@ const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn) { clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, const clang::ValueDecl *var) { - if (!fn) { + auto *lambda = GetLambdaOf(fn); + if (!lambda) { return nullptr; } - auto *lambda = GetLambdaOf(fn); - return lambda ? GetLambdaCaptureField(lambda, var) : nullptr; + llvm::DenseMap captures; + clang::FieldDecl *this_capture = nullptr; + lambda->getCaptureFields(captures, this_capture); + if (!var) { + return this_capture; + } + auto it = captures.find(var); + return it == captures.end() ? nullptr : it->second; } std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index f65aabb9..42f035b4 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -169,9 +169,6 @@ clang::Expr *ToAddrOf(clang::ASTContext &ctx, clang::Expr *expr); const clang::LambdaCapture *GetLambdaCapture(const clang::FieldDecl *field); -clang::FieldDecl *GetLambdaCaptureField(const clang::CXXRecordDecl *lambda, - const clang::ValueDecl *var); - const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, From 1d53d95fddb061fac673f216cb8da8a1ce7c46f7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 09:56:45 +0100 Subject: [PATCH 32/43] Inline conversion of captured this --- cpp2rust/converter/converter.cpp | 2 +- cpp2rust/converter/converter_lib.cpp | 8 +------- cpp2rust/converter/lex.h | 1 + cpp2rust/converter/models/converter_refcount.cpp | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 7333ecd4..160dfbb6 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3162,7 +3162,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { if (IsCapturedThis(curr_function_, expr)) { - StrCat(GetLambdaCaptureName(curr_function_, nullptr)); + StrCat(keyword::kSelfValue, token::kDot, token::kLambdaThisCapture); computed_expr_type_ = ComputedExprType::Pointer; return false; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 0200ee00..99dc2ba0 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -650,18 +650,12 @@ clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, llvm::DenseMap captures; clang::FieldDecl *this_capture = nullptr; lambda->getCaptureFields(captures, this_capture); - if (!var) { - return this_capture; - } auto it = captures.find(var); return it == captures.end() ? nullptr : it->second; } std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, const clang::ValueDecl *var) { - if (!fn) { - return {}; - } auto *field = GetLambdaCapturedField(fn, var); if (!field) { return {}; @@ -698,7 +692,7 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { if (auto *field = clang::dyn_cast(decl)) { if (auto *capture = GetLambdaCapture(field)) { if (capture->capturesThis()) { - return "this_"; + return token::kLambdaThisCapture; } return GetNamedDeclAsString(capture->getCapturedVar()); } diff --git a/cpp2rust/converter/lex.h b/cpp2rust/converter/lex.h index 207e7077..a52c5438 100644 --- a/cpp2rust/converter/lex.h +++ b/cpp2rust/converter/lex.h @@ -63,5 +63,6 @@ inline constexpr const char kMut[] = "mut"; namespace token { inline constexpr const char kDefault[] = "Default::default()"; inline constexpr const char kIgnoreRule[] = "libcc2rs::IgnoreRule"; +inline constexpr const char kLambdaThisCapture[] = "this_"; } // namespace token } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index eb1cd317..c69c2374 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2863,7 +2863,7 @@ void ConverterRefCount::ConvertCXXConstructorBody( bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { if (IsCapturedThis(curr_function_, expr)) { - StrCat(GetLambdaCaptureName(curr_function_, nullptr)); + StrCat(keyword::kSelfValue, token::kDot, token::kLambdaThisCapture); computed_expr_type_ = ComputedExprType::Pointer; return false; } From c443023341ac576e40d7b4d833f05be4d5c9508c Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 10:04:29 +0100 Subject: [PATCH 33/43] Fix captured this --- .../converter/models/converter_refcount.cpp | 3 +- tests/unit/lambda_capture_this.cpp | 17 ++++ .../unit/out/refcount/lambda_capture_this.rs | 93 +++++++++++++++++++ tests/unit/out/unsafe/lambda_capture_this.rs | 48 ++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/unit/lambda_capture_this.cpp create mode 100644 tests/unit/out/refcount/lambda_capture_this.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_this.rs diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index c69c2374..f123b4e2 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2863,7 +2863,8 @@ void ConverterRefCount::ConvertCXXConstructorBody( bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { if (IsCapturedThis(curr_function_, expr)) { - StrCat(keyword::kSelfValue, token::kDot, token::kLambdaThisCapture); + StrCat("(*", keyword::kSelfValue, token::kDot, token::kLambdaThisCapture, + ".borrow())"); computed_expr_type_ = ComputedExprType::Pointer; return false; } diff --git a/tests/unit/lambda_capture_this.cpp b/tests/unit/lambda_capture_this.cpp new file mode 100644 index 00000000..9cd469fb --- /dev/null +++ b/tests/unit/lambda_capture_this.cpp @@ -0,0 +1,17 @@ +#include + +struct Counter { + int n = 0; + void bump(int by) { + auto inc = [this](int k) { n += k; }; + inc(by); + inc(by); + } +}; + +int main() { + Counter c; + c.bump(3); + assert(c.n == 6); + return 0; +} diff --git a/tests/unit/out/refcount/lambda_capture_this.rs b/tests/unit/out/refcount/lambda_capture_this.rs new file mode 100644 index 00000000..56d9a4e2 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_this.rs @@ -0,0 +1,93 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct Counter { + pub n: Value, +} +impl Clone for Counter { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + n: Rc::new(RefCell::new((*self.n.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for Counter { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.n.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + n: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_0 { + this_: Value>, +} +impl lambda_0 { + fn operator_call(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + (*(*(*self.this_.borrow()).upgrade().deref()).n.borrow_mut()) += (*k.borrow()); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> () { + { lambda_0::operator_call(self, a1) } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let c: Value = Rc::new(RefCell::new(::default())); + ({ CounterImpl::bump(&c.as_pointer(), 3) }); + assert!(((*(*c.borrow()).n.borrow()) == 6)); + return 0; +} +pub trait CounterImpl { + fn bump(&self, by: i32); +} +impl CounterImpl for Ptr { + fn bump(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + let inc: Value = Rc::new(RefCell::new( + (lambda_0 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_this.rs b/tests/unit/out/unsafe/lambda_capture_this.rs new file mode 100644 index 00000000..d2d5f137 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_this.rs @@ -0,0 +1,48 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct Counter { + pub n: i32, +} +impl Counter { + pub unsafe fn bump(&mut self, mut by: i32) { + let mut inc: lambda_0 = (lambda_0 { + this_: (self as *mut Counter), + }); + (unsafe { lambda_0::operator_call(&inc, by) }); + (unsafe { lambda_0::operator_call(&inc, by) }); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + this_: *mut Counter, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut k: i32) { + (*self.this_).n += k; + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_0::operator_call(self, a1) } + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut c: Counter = ::default(); + (unsafe { Counter::bump(&mut c, 3) }); + assert!(((c.n) == (6))); + return 0; +} From 64c87b10609577f2ba9d5a0522d9aa64bee0d5bb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 10:08:57 +0100 Subject: [PATCH 34/43] Inline function --- cpp2rust/converter/converter.cpp | 12 +++++----- cpp2rust/converter/converter_lib.cpp | 22 ------------------- cpp2rust/converter/converter_lib.h | 5 ----- .../converter/models/converter_refcount.cpp | 4 ++-- 4 files changed, 8 insertions(+), 35 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 160dfbb6..1c4f553b 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2840,9 +2840,9 @@ bool Converter::VisitConditionalOperator(clang::ConditionalOperator *expr) { } std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { - if (auto capture = GetLambdaCaptureName(curr_function_, expr->getDecl()); - !capture.empty()) { - return capture; + if (auto *field = GetLambdaCapturedField(curr_function_, expr->getDecl())) { + return std::format("{}.{}", keyword::kSelfValue, + GetNamedDeclAsString(field)); } if (isAddrOf()) { clang::Expr *addrof_op = ToAddrOf(ctx_, expr); @@ -3060,7 +3060,7 @@ bool Converter::VisitMemberExpr(clang::MemberExpr *expr) { void Converter::SetUFCSReceiver(clang::Expr *base, bool is_arrow, const clang::CXXMethodDecl *method) { if (clang::isa(base->IgnoreParenImpCasts()) && - !IsCapturedThis(curr_function_, base)) { + !GetLambdaOf(curr_function_)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); ufcs_receiver_ = in_ctor ? "&mut this" : keyword::kSelfValue; @@ -3135,7 +3135,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { auto *base = expr->getBase(); bool base_is_this = clang::isa(base->IgnoreCasts()) && - !ThisIsRustPtr() && !IsCapturedThis(curr_function_, base); + !ThisIsRustPtr() && !GetLambdaOf(curr_function_); PushExprKind push(*this, isLValue() ? ExprKind::LValue : ExprKind::RValue); if (base_is_this) { StrCat(clang::isa(curr_function_) @@ -3161,7 +3161,7 @@ void Converter::ConvertMemberExpr(clang::MemberExpr *expr) { } bool Converter::VisitCXXThisExpr(clang::CXXThisExpr *expr) { - if (IsCapturedThis(curr_function_, expr)) { + if (GetLambdaOf(curr_function_)) { StrCat(keyword::kSelfValue, token::kDot, token::kLambdaThisCapture); computed_expr_type_ = ComputedExprType::Pointer; return false; diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 99dc2ba0..dbe3b3e1 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -654,28 +654,6 @@ clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, return it == captures.end() ? nullptr : it->second; } -std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, - const clang::ValueDecl *var) { - auto *field = GetLambdaCapturedField(fn, var); - if (!field) { - return {}; - } - return std::format("{}.{}", keyword::kSelfValue, GetNamedDeclAsString(field)); -} - -bool IsCapturedThis(const clang::FunctionDecl *fn, const clang::Expr *expr) { - if (!fn) { - return false; - } - auto *this_expr = - clang::dyn_cast(expr->IgnoreParenImpCasts()); - if (!this_expr) { - return false; - } - auto *lambda = GetLambdaOf(fn); - return lambda && this_expr->getType()->getPointeeCXXRecordDecl() != lambda; -} - std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 42f035b4..82599805 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -174,11 +174,6 @@ const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, const clang::ValueDecl *var); -std::string GetLambdaCaptureName(const clang::FunctionDecl *fn, - const clang::ValueDecl *var); - -bool IsCapturedThis(const clang::FunctionDecl *fn, const clang::Expr *expr); - std::vector GetNestedStructs(const clang::CXXRecordDecl *decl); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index f123b4e2..8aba23cb 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2685,7 +2685,7 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow, bool base_is_pointer = is_arrow && !clang::isa( base->IgnoreParenImpCasts()); if (clang::isa(base->IgnoreParenImpCasts()) && - !IsCapturedThis(curr_function_, base)) { + !GetLambdaOf(curr_function_)) { bool in_ctor = curr_function_ && clang::isa(curr_function_); if (in_ctor) { @@ -2862,7 +2862,7 @@ void ConverterRefCount::ConvertCXXConstructorBody( } bool ConverterRefCount::VisitCXXThisExpr(clang::CXXThisExpr *expr) { - if (IsCapturedThis(curr_function_, expr)) { + if (GetLambdaOf(curr_function_)) { StrCat("(*", keyword::kSelfValue, token::kDot, token::kLambdaThisCapture, ".borrow())"); computed_expr_type_ = ComputedExprType::Pointer; From 5b226e7a18b1615190fe9f65ca66bd25af33a2e2 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 10:31:19 +0100 Subject: [PATCH 35/43] Add more lambda tests --- ...ss.cpp => lambda_as_template_argument.cpp} | 7 +- tests/unit/lambda_basic.cpp | 25 ++ tests/unit/lambda_capture_implicit.cpp | 26 +++ tests/unit/lambda_capture_ref.cpp | 28 +++ tests/unit/lambda_capture_this.cpp | 24 +- tests/unit/lambda_capture_value.cpp | 31 +++ tests/unit/lambda_mutable.cpp | 21 ++ tests/unit/lambda_nested.cpp | 14 ++ tests/unit/out/refcount/destructor.rs | 9 +- ...pass.rs => lambda_as_template_argument.rs} | 42 ++++ tests/unit/out/refcount/lambda_basic.rs | 159 +++++++++++++ .../out/refcount/lambda_capture_implicit.rs | 138 +++++++++++ tests/unit/out/refcount/lambda_capture_ref.rs | 117 ++++++++++ .../unit/out/refcount/lambda_capture_this.rs | 134 +++++++++-- .../unit/out/refcount/lambda_capture_value.rs | 218 ++++++++++++++++++ tests/unit/out/refcount/lambda_mutable.rs | 93 ++++++++ tests/unit/out/refcount/lambda_nested.rs | 158 +++++++++++-- .../operator_member_pointer_member.rs | 9 +- tests/unit/out/refcount/random.rs | 9 +- tests/unit/out/refcount/stable_sort.rs | 38 ++- ...pass.rs => lambda_as_template_argument.rs} | 29 +++ tests/unit/out/unsafe/lambda_basic.rs | 123 ++++++++++ .../out/unsafe/lambda_capture_implicit.rs | 90 ++++++++ tests/unit/out/unsafe/lambda_capture_ref.rs | 84 +++++++ tests/unit/out/unsafe/lambda_capture_this.rs | 66 +++++- tests/unit/out/unsafe/lambda_capture_value.rs | 99 ++++++++ tests/unit/out/unsafe/lambda_mutable.rs | 48 ++++ tests/unit/out/unsafe/lambda_nested.rs | 76 ++++-- tests/unit/out/unsafe/stable_sort.rs | 30 ++- 29 files changed, 1846 insertions(+), 99 deletions(-) rename tests/unit/{lambda_capture_pass.cpp => lambda_as_template_argument.cpp} (69%) create mode 100644 tests/unit/lambda_basic.cpp create mode 100644 tests/unit/lambda_capture_implicit.cpp create mode 100644 tests/unit/lambda_capture_ref.cpp create mode 100644 tests/unit/lambda_capture_value.cpp create mode 100644 tests/unit/lambda_mutable.cpp rename tests/unit/out/refcount/{lambda_capture_pass.rs => lambda_as_template_argument.rs} (67%) create mode 100644 tests/unit/out/refcount/lambda_basic.rs create mode 100644 tests/unit/out/refcount/lambda_capture_implicit.rs create mode 100644 tests/unit/out/refcount/lambda_capture_ref.rs create mode 100644 tests/unit/out/refcount/lambda_capture_value.rs create mode 100644 tests/unit/out/refcount/lambda_mutable.rs rename tests/unit/out/unsafe/{lambda_capture_pass.rs => lambda_as_template_argument.rs} (64%) create mode 100644 tests/unit/out/unsafe/lambda_basic.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_implicit.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_ref.rs create mode 100644 tests/unit/out/unsafe/lambda_capture_value.rs create mode 100644 tests/unit/out/unsafe/lambda_mutable.rs diff --git a/tests/unit/lambda_capture_pass.cpp b/tests/unit/lambda_as_template_argument.cpp similarity index 69% rename from tests/unit/lambda_capture_pass.cpp rename to tests/unit/lambda_as_template_argument.cpp index 439b128c..8bd7d83a 100644 --- a/tests/unit/lambda_capture_pass.cpp +++ b/tests/unit/lambda_as_template_argument.cpp @@ -2,18 +2,21 @@ template int apply(F fn, int x) { return fn(x); } +template int apply_twice(F fn, int x) { return fn(fn(x)); } + int main() { int base = 10; - auto add_base = [&base](int x) { return x + base; }; assert(apply(add_base, 5) == 15); - base = 100; assert(apply(add_base, 5) == 105); int factor = 3; auto scale = [factor](int x) { return x * factor; }; assert(apply(scale, 4) == 12); + assert(apply_twice(scale, 4) == 36); + + assert(apply([](int x) { return -x; }, 9) == -9); return 0; } diff --git a/tests/unit/lambda_basic.cpp b/tests/unit/lambda_basic.cpp new file mode 100644 index 00000000..8996ab76 --- /dev/null +++ b/tests/unit/lambda_basic.cpp @@ -0,0 +1,25 @@ +#include + +int main() { + auto zero = []() { return 42; }; + assert(zero() == 42); + + auto one = [](int x) { return x + 1; }; + assert(one(1) == 2); + + auto three = [](int x, int y, int z) { return x * 100 + y * 10 + z; }; + assert(three(1, 2, 3) == 123); + + int hits = 0; + auto no_return = [&hits](int by) { hits += by; }; + no_return(3); + no_return(4); + assert(hits == 7); + + int a = 2; + int b = 3; + int product = [&]() { return a * b; }(); + assert(product == 6); + + return 0; +} diff --git a/tests/unit/lambda_capture_implicit.cpp b/tests/unit/lambda_capture_implicit.cpp new file mode 100644 index 00000000..293eb907 --- /dev/null +++ b/tests/unit/lambda_capture_implicit.cpp @@ -0,0 +1,26 @@ +#include + +int main() { + int a = 1; + int b = 2; + int c = 3; + + auto by_value = [=](int x) { return a + b + c + x; }; + assert(by_value(10) == 16); + a = 100; + assert(by_value(10) == 16); + + auto by_ref = [&](int x) { return a + b + c + x; }; + assert(by_ref(10) == 115); + b = 200; + assert(by_ref(10) == 313); + + auto mixed = [=, &c](int x) { + c += x; + return a + b + c; + }; + assert(mixed(1) == 100 + 200 + 4); + assert(c == 4); + + return 0; +} diff --git a/tests/unit/lambda_capture_ref.cpp b/tests/unit/lambda_capture_ref.cpp new file mode 100644 index 00000000..065030af --- /dev/null +++ b/tests/unit/lambda_capture_ref.cpp @@ -0,0 +1,28 @@ +#include + +struct S { + int x; + int y; +}; + +int main() { + int base = 10; + auto add_base = [&base](int x) { return x + base; }; + assert(add_base(5) == 15); + base = 100; + assert(add_base(5) == 105); + + S s = {1, 2}; + auto sum = [&s]() { return s.x + s.y; }; + assert(sum() == 3); + s.x = 50; + assert(sum() == 52); + + int counter = 0; + auto bump = [&counter]() { counter++; }; + bump(); + bump(); + assert(counter == 2); + + return 0; +} diff --git a/tests/unit/lambda_capture_this.cpp b/tests/unit/lambda_capture_this.cpp index 9cd469fb..d34cf8c7 100644 --- a/tests/unit/lambda_capture_this.cpp +++ b/tests/unit/lambda_capture_this.cpp @@ -1,17 +1,31 @@ #include -struct Counter { - int n = 0; +struct S { + int n; + int step; + void add(int k) { n += k; } + int scaled() const { return n * step; } void bump(int by) { auto inc = [this](int k) { n += k; }; inc(by); inc(by); } + void bump_via_method(int by) { + auto inc = [this](int k) { add(k); }; + inc(by); + } + int read_scaled() const { + auto get = [this]() { return scaled(); }; + return get(); + } }; int main() { - Counter c; - c.bump(3); - assert(c.n == 6); + S s = {0, 2}; + s.bump(3); + assert(s.n == 6); + s.bump_via_method(4); + assert(s.n == 10); + assert(s.read_scaled() == 20); return 0; } diff --git a/tests/unit/lambda_capture_value.cpp b/tests/unit/lambda_capture_value.cpp new file mode 100644 index 00000000..cb94939c --- /dev/null +++ b/tests/unit/lambda_capture_value.cpp @@ -0,0 +1,31 @@ +#include + +struct S { + int x; + int y; +}; + +int main() { + int factor = 3; + auto scale = [factor](int x) { return x * factor; }; + assert(scale(4) == 12); + factor = 100; + assert(scale(4) == 12); + + int slot = 7; + int *p = &slot; + auto read_ptr = [p]() { return *p; }; + slot = 8; + assert(read_ptr() == 8); + + S s = {1, 2}; + auto sum = [s]() { return s.x + s.y; }; + s.x = 50; + assert(sum() == 3); + + int base = 10; + auto shifted = [y = base + 1](int x) { return x + y; }; + assert(shifted(5) == 16); + + return 0; +} diff --git a/tests/unit/lambda_mutable.cpp b/tests/unit/lambda_mutable.cpp new file mode 100644 index 00000000..5590e46e --- /dev/null +++ b/tests/unit/lambda_mutable.cpp @@ -0,0 +1,21 @@ +#include + +int main() { + int start = 5; + auto next = [start]() mutable { return start++; }; + assert(next() == 5); + assert(next() == 6); + assert(next() == 7); + assert(start == 5); + + int total = 0; + auto accumulate = [total](int x) mutable { + total += x; + return total; + }; + assert(accumulate(1) == 1); + assert(accumulate(2) == 3); + assert(total == 0); + + return 0; +} diff --git a/tests/unit/lambda_nested.cpp b/tests/unit/lambda_nested.cpp index f7f26e93..5a026da4 100644 --- a/tests/unit/lambda_nested.cpp +++ b/tests/unit/lambda_nested.cpp @@ -1,5 +1,16 @@ #include +struct S { + int v; + int nested_this() { + auto outer = [this](int y) { + auto inner = [this, y](int z) { return v + y + z; }; + return inner(1); + }; + return outer(20); + } +}; + int main() { int x = 10; @@ -13,5 +24,8 @@ int main() { x = 100; assert(outer(20) == 121); + S s = {5}; + assert(s.nested_this() == 26); + return 0; } diff --git a/tests/unit/out/refcount/destructor.rs b/tests/unit/out/refcount/destructor.rs index 71dff440..6cdfe5d8 100644 --- a/tests/unit/out/refcount/destructor.rs +++ b/tests/unit/out/refcount/destructor.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static global_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/lambda_capture_pass.rs b/tests/unit/out/refcount/lambda_as_template_argument.rs similarity index 67% rename from tests/unit/out/refcount/lambda_capture_pass.rs rename to tests/unit/out/refcount/lambda_as_template_argument.rs index 4e4b2360..218d0ce0 100644 --- a/tests/unit/out/refcount/lambda_capture_pass.rs +++ b/tests/unit/out/refcount/lambda_as_template_argument.rs @@ -16,6 +16,19 @@ pub fn apply_2(fn_: lambda_3, x: i32) -> i32 { let x: Value = Rc::new(RefCell::new(x)); return ({ lambda_3::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); } +pub fn apply_4(fn_: lambda_5, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ lambda_5::operator_call((*x.borrow())) }); +} +pub fn apply_twice_6(fn_: lambda_3, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); + let x: Value = Rc::new(RefCell::new(x)); + return ({ + let _x: i32 = ({ lambda_3::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); + lambda_3::operator_call(&(*fn_.borrow_mut()), _x) + }); +} pub fn main() { std::process::exit(main_0()); } @@ -36,6 +49,8 @@ fn main_0() -> i32 { }), )); assert!((({ apply_2((*scale.borrow()).clone(), 4,) }) == 12)); + assert!((({ apply_twice_6((*scale.borrow()).clone(), 4,) }) == 36)); + assert!((({ apply_4((lambda_5 {}), 9,) }) == -9_i32)); return 0; } #[derive(Clone, Default)] @@ -89,3 +104,30 @@ impl Callable1 for lambda_3 { { lambda_3::operator_call(self, a1) } } } +#[derive(Clone, Default)] +pub struct lambda_5 {} +impl lambda_5 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_5 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_5 { + fn call(&self, a1: i32) -> i32 { + { lambda_5::operator_call(a1) } + } +} +impl lambda_5 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_5::operator_call) + } +} diff --git a/tests/unit/out/refcount/lambda_basic.rs b/tests/unit/out/refcount/lambda_basic.rs new file mode 100644 index 00000000..50637b60 --- /dev/null +++ b/tests/unit/out/refcount/lambda_basic.rs @@ -0,0 +1,159 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let zero: Value = Rc::new(RefCell::new((lambda_0 {}))); + assert!((({ lambda_0::operator_call() }) == 42)); + let one: Value = Rc::new(RefCell::new((lambda_1 {}))); + assert!((({ lambda_1::operator_call(1,) }) == 2)); + let three: Value = Rc::new(RefCell::new((lambda_2 {}))); + assert!((({ lambda_2::operator_call(1, 2, 3,) }) == 123)); + let hits: Value = Rc::new(RefCell::new(0)); + let no_return: Value = Rc::new(RefCell::new( + (lambda_3 { + hits: hits.as_pointer(), + }), + )); + ({ lambda_3::operator_call(&(*no_return.borrow_mut()), 3) }); + ({ lambda_3::operator_call(&(*no_return.borrow_mut()), 4) }); + assert!(((*hits.borrow()) == 7)); + let a: Value = Rc::new(RefCell::new(2)); + let b: Value = Rc::new(RefCell::new(3)); + let product: Value = Rc::new(RefCell::new( + ({ + lambda_4::operator_call( + &(lambda_4 { + a: a.as_pointer(), + b: b.as_pointer(), + }), + ) + }), + )); + assert!(((*product.borrow()) == 6)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call() -> i32 { + return 42; + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable0 for lambda_0 { + fn call(&self) -> i32 { + { lambda_0::operator_call() } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_0::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + 1); + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_1::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32, y: i32, z: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + let z: Value = Rc::new(RefCell::new(z)); + return ((((*x.borrow()) * 100) + ((*y.borrow()) * 10)) + (*z.borrow())); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable3 for lambda_2 { + fn call(&self, a1: i32, a2: i32, a3: i32) -> i32 { + { lambda_2::operator_call(a1, a2, a3) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} +#[derive(Clone, Default)] +pub struct lambda_3 { + hits: Ptr, +} +impl lambda_3 { + pub fn operator_call(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + { + let _ptr = self.hits.clone(); + _ptr.write(_ptr.read() + (*by.borrow())) + }; + } +} +impl ByteRepr for lambda_3 {} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> () { + { lambda_3::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_4 { + a: Ptr, + b: Ptr, +} +impl lambda_4 { + pub fn operator_call(&self) -> i32 { + return ((self.a.read()) * (self.b.read())); + } +} +impl ByteRepr for lambda_4 {} +impl Callable0 for lambda_4 { + fn call(&self) -> i32 { + { lambda_4::operator_call(self) } + } +} diff --git a/tests/unit/out/refcount/lambda_capture_implicit.rs b/tests/unit/out/refcount/lambda_capture_implicit.rs new file mode 100644 index 00000000..2e450912 --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_implicit.rs @@ -0,0 +1,138 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value = Rc::new(RefCell::new(1)); + let b: Value = Rc::new(RefCell::new(2)); + let c: Value = Rc::new(RefCell::new(3)); + let by_value: Value = Rc::new(RefCell::new( + (lambda_0 { + a: Rc::new(RefCell::new((*a.borrow()))), + b: Rc::new(RefCell::new((*b.borrow()))), + c: Rc::new(RefCell::new((*c.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&(*by_value.borrow_mut()), 10,) }) == 16)); + (*a.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*by_value.borrow_mut()), 10,) }) == 16)); + let by_ref: Value = Rc::new(RefCell::new( + (lambda_1 { + a: a.as_pointer(), + b: b.as_pointer(), + c: c.as_pointer(), + }), + )); + assert!((({ lambda_1::operator_call(&(*by_ref.borrow_mut()), 10,) }) == 115)); + (*b.borrow_mut()) = 200; + assert!((({ lambda_1::operator_call(&(*by_ref.borrow_mut()), 10,) }) == 313)); + let mixed: Value = Rc::new(RefCell::new( + (lambda_2 { + c: c.as_pointer(), + a: Rc::new(RefCell::new((*a.borrow()))), + b: Rc::new(RefCell::new((*b.borrow()))), + }), + )); + assert!((({ lambda_2::operator_call(&(*mixed.borrow_mut()), 1,) }) == ((100 + 200) + 4))); + assert!(((*c.borrow()) == 4)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + a: Value, + b: Value, + c: Value, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((((*self.a.borrow()) + (*self.b.borrow())) + (*self.c.borrow())) + (*x.borrow())); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + c: Rc::new(RefCell::new((*self.c.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 12 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.b.borrow()).to_bytes(&mut buf[4..8]); + (*self.c.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + c: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_1 { + a: Ptr, + b: Ptr, + c: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((((self.a.read()) + (self.b.read())) + (self.c.read())) + (*x.borrow())); + } +} +impl ByteRepr for lambda_1 {} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_2 { + c: Ptr, + a: Value, + b: Value, +} +impl lambda_2 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + { + let _ptr = self.c.clone(); + _ptr.write(_ptr.read() + (*x.borrow())) + }; + return (((*self.a.borrow()) + (*self.b.borrow())) + (self.c.read())); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + c: self.c.clone(), + a: Rc::new(RefCell::new((*self.a.borrow()).clone())), + b: Rc::new(RefCell::new((*self.b.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 {} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(self, a1) } + } +} diff --git a/tests/unit/out/refcount/lambda_capture_ref.rs b/tests/unit/out/refcount/lambda_capture_ref.rs new file mode 100644 index 00000000..1daa3f9c --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_ref.rs @@ -0,0 +1,117 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub x: Value, + pub y: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let base: Value = Rc::new(RefCell::new(10)); + let add_base: Value = Rc::new(RefCell::new( + (lambda_0 { + base: base.as_pointer(), + }), + )); + assert!((({ lambda_0::operator_call(&(*add_base.borrow_mut()), 5,) }) == 15)); + (*base.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*add_base.borrow_mut()), 5,) }) == 105)); + let s: Value = Rc::new(RefCell::new(S { + x: Rc::new(RefCell::new(1)), + y: Rc::new(RefCell::new(2)), + })); + let sum: Value = Rc::new(RefCell::new((lambda_1 { s: s.as_pointer() }))); + assert!((({ lambda_1::operator_call(&(*sum.borrow_mut()),) }) == 3)); + (*(*s.borrow()).x.borrow_mut()) = 50; + assert!((({ lambda_1::operator_call(&(*sum.borrow_mut()),) }) == 52)); + let counter: Value = Rc::new(RefCell::new(0)); + let bump: Value = Rc::new(RefCell::new( + (lambda_2 { + counter: counter.as_pointer(), + }), + )); + ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); + ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); + assert!(((*counter.borrow()) == 2)); + return 0; +} +#[derive(Clone, Default)] +pub struct lambda_0 { + base: Ptr, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} +impl ByteRepr for lambda_0 {} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_1 { + s: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self) -> i32 { + return ((*(*self.s.upgrade().deref()).x.borrow()) + + (*(*self.s.upgrade().deref()).y.borrow())); + } +} +impl ByteRepr for lambda_1 {} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + { lambda_1::operator_call(self) } + } +} +#[derive(Clone, Default)] +pub struct lambda_2 { + counter: Ptr, +} +impl lambda_2 { + pub fn operator_call(&self) { + self.counter.with_mut(|__v| __v.postfix_inc()); + } +} +impl ByteRepr for lambda_2 {} +impl Callable0<()> for lambda_2 { + fn call(&self) -> () { + { lambda_2::operator_call(self) } + } +} diff --git a/tests/unit/out/refcount/lambda_capture_this.rs b/tests/unit/out/refcount/lambda_capture_this.rs index 56d9a4e2..35843b70 100644 --- a/tests/unit/out/refcount/lambda_capture_this.rs +++ b/tests/unit/out/refcount/lambda_capture_this.rs @@ -7,34 +7,38 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; #[derive(Default)] -pub struct Counter { +pub struct S { pub n: Value, + pub step: Value, } -impl Clone for Counter { +impl Clone for S { fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { + let __this: Value = Rc::new(RefCell::new(Self { n: Rc::new(RefCell::new((*self.n.borrow()))), + step: Rc::new(RefCell::new((*self.step.borrow()))), })); - let this: Ptr = __this.as_pointer(); + let this: Ptr = __this.as_pointer(); Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl ByteRepr for Counter { +impl ByteRepr for S { fn byte_size() -> usize { - 4 + 8 } fn to_bytes(&self, buf: &mut [u8]) { (*self.n.borrow()).to_bytes(&mut buf[0..4]); + (*self.step.borrow()).to_bytes(&mut buf[4..8]); } fn from_bytes(buf: &[u8]) -> Self { Self { n: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + step: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), } } } #[derive(Default)] pub struct lambda_0 { - this_: Value>, + this_: Value>, } impl lambda_0 { fn operator_call(&self, k: i32) { @@ -58,7 +62,7 @@ impl ByteRepr for lambda_0 { } fn from_bytes(buf: &[u8]) -> Self { Self { - this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), } } } @@ -67,19 +71,106 @@ impl Callable1 for lambda_0 { { lambda_0::operator_call(self, a1) } } } +#[derive(Default)] +pub struct lambda_1 { + this_: Value>, +} +impl lambda_1 { + fn operator_call(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + ({ SImpl::add(&(*self.this_.borrow()), (*k.borrow())) }); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> () { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_2 { + this_: Value>, +} +impl lambda_2 { + fn operator_call(&self) -> i32 { + return ({ SImpl::scaled(&(*self.this_.borrow())) }); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + { lambda_2::operator_call(self) } + } +} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let c: Value = Rc::new(RefCell::new(::default())); - ({ CounterImpl::bump(&c.as_pointer(), 3) }); - assert!(((*(*c.borrow()).n.borrow()) == 6)); + let s: Value = Rc::new(RefCell::new(S { + n: Rc::new(RefCell::new(0)), + step: Rc::new(RefCell::new(2)), + })); + ({ SImpl::bump(&s.as_pointer(), 3) }); + assert!(((*(*s.borrow()).n.borrow()) == 6)); + ({ SImpl::bump_via_method(&s.as_pointer(), 4) }); + assert!(((*(*s.borrow()).n.borrow()) == 10)); + assert!((({ SImpl::read_scaled(&s.as_pointer(),) }) == 20)); return 0; } -pub trait CounterImpl { +pub trait SImpl { + fn add(&self, k: i32); + fn scaled(&self) -> i32; fn bump(&self, by: i32); + fn bump_via_method(&self, by: i32); + fn read_scaled(&self) -> i32; } -impl CounterImpl for Ptr { +impl SImpl for Ptr { + fn add(&self, k: i32) { + let k: Value = Rc::new(RefCell::new(k)); + (*(*(*self).upgrade().deref()).n.borrow_mut()) += (*k.borrow()); + } + fn scaled(&self) -> i32 { + return ((*(*(*self).upgrade().deref()).n.borrow()) + * (*(*(*self).upgrade().deref()).step.borrow())); + } fn bump(&self, by: i32) { let by: Value = Rc::new(RefCell::new(by)); let inc: Value = Rc::new(RefCell::new( @@ -90,4 +181,21 @@ impl CounterImpl for Ptr { ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); ({ lambda_0::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); } + fn bump_via_method(&self, by: i32) { + let by: Value = Rc::new(RefCell::new(by)); + let inc: Value = Rc::new(RefCell::new( + (lambda_1 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + ({ lambda_1::operator_call(&(*inc.borrow_mut()), (*by.borrow())) }); + } + fn read_scaled(&self) -> i32 { + let get: Value = Rc::new(RefCell::new( + (lambda_2 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + return ({ lambda_2::operator_call(&(*get.borrow_mut())) }); + } } diff --git a/tests/unit/out/refcount/lambda_capture_value.rs b/tests/unit/out/refcount/lambda_capture_value.rs new file mode 100644 index 00000000..210b4d0d --- /dev/null +++ b/tests/unit/out/refcount/lambda_capture_value.rs @@ -0,0 +1,218 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub x: Value, + pub y: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let factor: Value = Rc::new(RefCell::new(3)); + let scale: Value = Rc::new(RefCell::new( + (lambda_0 { + factor: Rc::new(RefCell::new((*factor.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&(*scale.borrow_mut()), 4,) }) == 12)); + (*factor.borrow_mut()) = 100; + assert!((({ lambda_0::operator_call(&(*scale.borrow_mut()), 4,) }) == 12)); + let slot: Value = Rc::new(RefCell::new(7)); + let p: Value> = Rc::new(RefCell::new((slot.as_pointer()))); + let read_ptr: Value = Rc::new(RefCell::new( + (lambda_1 { + p: Rc::new(RefCell::new((*p.borrow()).clone())), + }), + )); + (*slot.borrow_mut()) = 8; + assert!((({ lambda_1::operator_call(&(*read_ptr.borrow_mut()),) }) == 8)); + let s: Value = Rc::new(RefCell::new(S { + x: Rc::new(RefCell::new(1)), + y: Rc::new(RefCell::new(2)), + })); + let sum: Value = Rc::new(RefCell::new( + (lambda_2 { + s: Rc::new(RefCell::new((*s.borrow()).clone())), + }), + )); + (*(*s.borrow()).x.borrow_mut()) = 50; + assert!((({ lambda_2::operator_call(&(*sum.borrow_mut()),) }) == 3)); + let base: Value = Rc::new(RefCell::new(10)); + let shifted: Value = Rc::new(RefCell::new( + (lambda_3 { + y: Rc::new(RefCell::new(((*base.borrow()) + 1))), + }), + )); + assert!((({ lambda_3::operator_call(&(*shifted.borrow_mut()), 5,) }) == 16)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + factor: Value, +} +impl lambda_0 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) * (*self.factor.borrow())); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + factor: Rc::new(RefCell::new((*self.factor.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.factor.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + factor: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_1 { + p: Value>, +} +impl lambda_1 { + pub fn operator_call(&self) -> i32 { + return ((*self.p.borrow()).read()); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + p: Rc::new(RefCell::new((*self.p.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.p.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + p: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + { lambda_1::operator_call(self) } + } +} +#[derive(Default)] +pub struct lambda_2 { + s: Value, +} +impl lambda_2 { + pub fn operator_call(&self) -> i32 { + return ((*(*self.s.borrow()).x.borrow()) + (*(*self.s.borrow()).y.borrow())); + } +} +impl Clone for lambda_2 { + fn clone(&self) -> Self { + Self { + s: Rc::new(RefCell::new((*self.s.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.s.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + s: Rc::new(RefCell::new(::from_bytes(&buf[0..8]))), + } + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + { lambda_2::operator_call(self) } + } +} +#[derive(Default)] +pub struct lambda_3 { + y: Value, +} +impl lambda_3 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (*self.y.borrow())); + } +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + Self { + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_3 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.y.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + y: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + { lambda_3::operator_call(self, a1) } + } +} diff --git a/tests/unit/out/refcount/lambda_mutable.rs b/tests/unit/out/refcount/lambda_mutable.rs new file mode 100644 index 00000000..54b02d77 --- /dev/null +++ b/tests/unit/out/refcount/lambda_mutable.rs @@ -0,0 +1,93 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let start: Value = Rc::new(RefCell::new(5)); + let next: Value = Rc::new(RefCell::new( + (lambda_0 { + start: Rc::new(RefCell::new((*start.borrow()))), + }), + )); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 5)); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 6)); + assert!((({ lambda_0::operator_call(&mut (*next.borrow_mut()),) }) == 7)); + assert!(((*start.borrow()) == 5)); + let total: Value = Rc::new(RefCell::new(0)); + let accumulate: Value = Rc::new(RefCell::new( + (lambda_1 { + total: Rc::new(RefCell::new((*total.borrow()))), + }), + )); + assert!((({ lambda_1::operator_call(&mut (*accumulate.borrow_mut()), 1,) }) == 1)); + assert!((({ lambda_1::operator_call(&mut (*accumulate.borrow_mut()), 2,) }) == 3)); + assert!(((*total.borrow()) == 0)); + return 0; +} +#[derive(Default)] +pub struct lambda_0 { + start: Value, +} +impl lambda_0 { + pub fn operator_call(&self) -> i32 { + return (*self.start.borrow_mut()).postfix_inc(); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + start: Rc::new(RefCell::new((*self.start.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.start.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + start: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_1 { + total: Value, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + (*self.total.borrow_mut()) += (*x.borrow()); + return (*self.total.borrow()); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + total: Rc::new(RefCell::new((*self.total.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.total.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + total: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index 4fb9192d..ff7fc61b 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -6,29 +6,140 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub v: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_1 { + this_: Value>, + y: Value, +} +impl lambda_1 { + fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((*(*(*self.this_.borrow()).upgrade().deref()).v.borrow()) + (*self.y.borrow())) + + (*z.borrow())); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + (*self.y.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_0 { + this_: Value>, +} +impl lambda_0 { + fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_1 { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_1::operator_call(&(*inner.borrow_mut()), 1) }); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(10)); - let outer: Value = Rc::new(RefCell::new((lambda_0 { x: x.as_pointer() }))); - assert!((({ lambda_0::operator_call(&(*outer.borrow_mut()), 20,) }) == 31)); + let outer: Value = Rc::new(RefCell::new((lambda_2 { x: x.as_pointer() }))); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 31)); (*x.borrow_mut()) = 100; - assert!((({ lambda_0::operator_call(&(*outer.borrow_mut()), 20,) }) == 121)); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 121)); + let s: Value = Rc::new(RefCell::new(S { + v: Rc::new(RefCell::new(5)), + })); + assert!((({ SImpl::nested_this(&s.as_pointer(),) }) == 26)); return 0; } #[derive(Default)] -pub struct lambda_1 { +pub struct lambda_3 { x: Ptr, y: Value, } -impl lambda_1 { +impl lambda_3 { pub fn operator_call(&self, z: i32) -> i32 { let z: Value = Rc::new(RefCell::new(z)); return (((self.x.read()) + (*self.y.borrow())) + (*z.borrow())); } } -impl Clone for lambda_1 { +impl Clone for lambda_3 { fn clone(&self) -> Self { Self { x: self.x.clone(), @@ -36,31 +147,44 @@ impl Clone for lambda_1 { } } } -impl ByteRepr for lambda_1 {} -impl Callable1 for lambda_1 { +impl ByteRepr for lambda_3 {} +impl Callable1 for lambda_3 { fn call(&self, a1: i32) -> i32 { - { lambda_1::operator_call(self, a1) } + { lambda_3::operator_call(self, a1) } } } #[derive(Clone, Default)] -pub struct lambda_0 { +pub struct lambda_2 { x: Ptr, } -impl lambda_0 { +impl lambda_2 { pub fn operator_call(&self, y: i32) -> i32 { let y: Value = Rc::new(RefCell::new(y)); - let inner: Value = Rc::new(RefCell::new( - (lambda_1 { + let inner: Value = Rc::new(RefCell::new( + (lambda_3 { x: (self.x).clone(), y: Rc::new(RefCell::new((*y.borrow()))), }), )); - return ({ lambda_1::operator_call(&(*inner.borrow_mut()), 1) }); + return ({ lambda_3::operator_call(&(*inner.borrow_mut()), 1) }); } } -impl ByteRepr for lambda_0 {} -impl Callable1 for lambda_0 { +impl ByteRepr for lambda_2 {} +impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - { lambda_0::operator_call(self, a1) } + { lambda_2::operator_call(self, a1) } + } +} +pub trait SImpl { + fn nested_this(&self) -> i32; +} +impl SImpl for Ptr { + fn nested_this(&self) -> i32 { + let outer: Value = Rc::new(RefCell::new( + (lambda_0 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + return ({ lambda_0::operator_call(&(*outer.borrow_mut()), 20) }); } } diff --git a/tests/unit/out/refcount/operator_member_pointer_member.rs b/tests/unit/out/refcount/operator_member_pointer_member.rs index c736517e..f3e4bafd 100644 --- a/tests/unit/out/refcount/operator_member_pointer_member.rs +++ b/tests/unit/out/refcount/operator_member_pointer_member.rs @@ -33,7 +33,7 @@ impl ByteRepr for Inner { } } thread_local!(); -#[derive(Default)] +#[derive(Clone, Default)] pub struct Table {} impl Table { pub fn operator_index(i: i32) -> Ptr { @@ -41,13 +41,6 @@ impl Table { return (table_0.with(Value::clone).as_pointer() as Ptr).offset((*i.borrow())); } } -impl Clone for Table { - fn clone(&self) -> Self { - let __this: Value
= Rc::new(RefCell::new(Self {})); - let this: Ptr
= __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Table { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/random.rs b/tests/unit/out/refcount/random.rs index ceb93973..a4943e1b 100644 --- a/tests/unit/out/refcount/random.rs +++ b/tests/unit/out/refcount/random.rs @@ -58,15 +58,8 @@ impl ByteRepr for Pair {} pub fn zero_0() -> i32 { return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X1 {} -impl Clone for X1 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X1 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 784fbf00..0ddcb62c 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -12,14 +12,8 @@ pub fn main() { fn main_0() -> i32 { let arr1: Value> = Rc::new(RefCell::new(Box::new([5, 2, 8, 1, 3]))); { - let fun = |x: Ptr, y: Ptr| { - (|x: i32, y: i32| { - let x: Value = Rc::new(RefCell::new(x)); - let y: Value = Rc::new(RefCell::new(y)); - return ((*x.borrow()) < (*y.borrow())); - }) - .call((x.read()).clone(), (y.read()).clone()) - }; + let fun = + |x: Ptr, y: Ptr| (lambda_0 {}).call((x.read()).clone(), (y.read()).clone()); (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) .offset((5) as isize) @@ -29,3 +23,31 @@ fn main_0() -> i32 { }; return 0; } +#[derive(Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call(x: i32, y: i32) -> bool { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + return ((*x.borrow()) < (*y.borrow())); + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr bool> { + FnPtr::new(lambda_0::operator_call) + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_pass.rs b/tests/unit/out/unsafe/lambda_as_template_argument.rs similarity index 64% rename from tests/unit/out/unsafe/lambda_capture_pass.rs rename to tests/unit/out/unsafe/lambda_as_template_argument.rs index 82033c01..64723d95 100644 --- a/tests/unit/out/unsafe/lambda_capture_pass.rs +++ b/tests/unit/out/unsafe/lambda_as_template_argument.rs @@ -12,6 +12,15 @@ pub unsafe fn apply_0(mut fn_: lambda_1, mut x: i32) -> i32 { pub unsafe fn apply_2(mut fn_: lambda_3, mut x: i32) -> i32 { return (unsafe { lambda_3::operator_call(&fn_, x) }); } +pub unsafe fn apply_4(mut fn_: lambda_5, mut x: i32) -> i32 { + return (unsafe { lambda_5::operator_call(x) }); +} +pub unsafe fn apply_twice_6(mut fn_: lambda_3, mut x: i32) -> i32 { + return (unsafe { + let _x: i32 = (unsafe { lambda_3::operator_call(&fn_, x) }); + lambda_3::operator_call(&fn_, _x) + }); +} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -26,6 +35,8 @@ unsafe fn main_0() -> i32 { let mut factor: i32 = 3; let mut scale: lambda_3 = (lambda_3 { factor: factor }); assert!(((unsafe { apply_2(scale, 4,) }) == (12))); + assert!(((unsafe { apply_twice_6(scale, 4,) }) == (36))); + assert!(((unsafe { apply_4((lambda_5 {}), 9,) }) == (-9_i32))); return 0; } #[repr(C)] @@ -58,3 +69,21 @@ impl Callable1 for lambda_3 { unsafe { lambda_3::operator_call(self, a1) } } } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_5 {} +impl lambda_5 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_5 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_5::operator_call(a1) } + } +} +impl lambda_5 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_5::operator_call) + } +} diff --git a/tests/unit/out/unsafe/lambda_basic.rs b/tests/unit/out/unsafe/lambda_basic.rs new file mode 100644 index 00000000..58dcd490 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_basic.rs @@ -0,0 +1,123 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut zero: lambda_0 = (lambda_0 {}); + assert!(((unsafe { lambda_0::operator_call() }) == (42))); + let mut one: lambda_1 = (lambda_1 {}); + assert!(((unsafe { lambda_1::operator_call(1,) }) == (2))); + let mut three: lambda_2 = (lambda_2 {}); + assert!(((unsafe { lambda_2::operator_call(1, 2, 3,) }) == (123))); + let mut hits: i32 = 0; + let mut no_return: lambda_3 = (lambda_3 { hits: &mut hits }); + (unsafe { lambda_3::operator_call(&no_return, 3) }); + (unsafe { lambda_3::operator_call(&no_return, 4) }); + assert!(((hits) == (7))); + let mut a: i32 = 2; + let mut b: i32 = 3; + let mut product: i32 = (unsafe { + lambda_4::operator_call( + &(lambda_4 { + a: &mut a, + b: &mut b, + }), + ) + }); + assert!(((product) == (6))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call() -> i32 { + return 42; + } +} +impl Callable0 for lambda_0 { + fn call(&self) -> i32 { + unsafe { lambda_0::operator_call() } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_0::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 {} +impl lambda_1 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return ((x) + (1)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(a1) } + } +} +impl lambda_1 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_1::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32, mut y: i32, mut z: i32) -> i32 { + return ((((x) * (100)) + ((y) * (10))) + (z)); + } +} +impl Callable3 for lambda_2 { + fn call(&self, a1: i32, a2: i32, a3: i32) -> i32 { + unsafe { lambda_2::operator_call(a1, a2, a3) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + hits: *mut i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut by: i32) { + (*self.hits) += by; + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_3::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_4 { + a: *mut i32, + b: *mut i32, +} +impl lambda_4 { + pub unsafe fn operator_call(&self) -> i32 { + return ((*self.a) * (*self.b)); + } +} +impl Callable0 for lambda_4 { + fn call(&self) -> i32 { + unsafe { lambda_4::operator_call(self) } + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_implicit.rs b/tests/unit/out/unsafe/lambda_capture_implicit.rs new file mode 100644 index 00000000..44d507fe --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_implicit.rs @@ -0,0 +1,90 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: i32 = 1; + let mut b: i32 = 2; + let mut c: i32 = 3; + let mut by_value: lambda_0 = (lambda_0 { a: a, b: b, c: c }); + assert!(((unsafe { lambda_0::operator_call(&by_value, 10,) }) == (16))); + a = 100; + assert!(((unsafe { lambda_0::operator_call(&by_value, 10,) }) == (16))); + let mut by_ref: lambda_1 = (lambda_1 { + a: &mut a, + b: &mut b, + c: &mut c, + }); + assert!(((unsafe { lambda_1::operator_call(&by_ref, 10,) }) == (115))); + b = 200; + assert!(((unsafe { lambda_1::operator_call(&by_ref, 10,) }) == (313))); + let mut mixed: lambda_2 = (lambda_2 { + c: &mut c, + a: a, + b: b, + }); + assert!(((unsafe { lambda_2::operator_call(&mixed, 1,) }) == (((100) + (200)) + (4)))); + assert!(((c) == (4))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + a: i32, + b: i32, + c: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((((self.a) + (self.b)) + (self.c)) + (x)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + a: *mut i32, + b: *mut i32, + c: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((((*self.a) + (*self.b)) + (*self.c)) + (x)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + c: *mut i32, + a: i32, + b: i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + (*self.c) += x; + return (((self.a) + (self.b)) + (*self.c)); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(self, a1) } + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_ref.rs b/tests/unit/out/unsafe/lambda_capture_ref.rs new file mode 100644 index 00000000..b41d9573 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_ref.rs @@ -0,0 +1,84 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut base: i32 = 10; + let mut add_base: lambda_0 = (lambda_0 { base: &mut base }); + assert!(((unsafe { lambda_0::operator_call(&add_base, 5,) }) == (15))); + base = 100; + assert!(((unsafe { lambda_0::operator_call(&add_base, 5,) }) == (105))); + let mut s: S = S { x: 1, y: 2 }; + let mut sum: lambda_1 = (lambda_1 { s: &mut s }); + assert!(((unsafe { lambda_1::operator_call(&sum,) }) == (3))); + s.x = 50; + assert!(((unsafe { lambda_1::operator_call(&sum,) }) == (52))); + let mut counter: i32 = 0; + let mut bump: lambda_2 = (lambda_2 { + counter: &mut counter, + }); + (unsafe { lambda_2::operator_call(&bump) }); + (unsafe { lambda_2::operator_call(&bump) }); + assert!(((counter) == (2))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + base: *mut i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + s: *mut S, +} +impl lambda_1 { + pub unsafe fn operator_call(&self) -> i32 { + return (((*self.s).x) + ((*self.s).y)); + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + unsafe { lambda_1::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + counter: *mut i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) { + (*self.counter).postfix_inc(); + } +} +impl Callable0<()> for lambda_2 { + fn call(&self) -> () { + unsafe { lambda_2::operator_call(self) } + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_this.rs b/tests/unit/out/unsafe/lambda_capture_this.rs index d2d5f137..69d9e7a9 100644 --- a/tests/unit/out/unsafe/lambda_capture_this.rs +++ b/tests/unit/out/unsafe/lambda_capture_this.rs @@ -8,22 +8,41 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] #[derive(Copy, Clone, Default)] -pub struct Counter { +pub struct S { pub n: i32, + pub step: i32, } -impl Counter { +impl S { + pub unsafe fn add(&mut self, mut k: i32) { + self.n += k; + } + pub unsafe fn scaled(&self) -> i32 { + return ((self.n) * (self.step)); + } pub unsafe fn bump(&mut self, mut by: i32) { let mut inc: lambda_0 = (lambda_0 { - this_: (self as *mut Counter), + this_: (self as *mut S), }); (unsafe { lambda_0::operator_call(&inc, by) }); (unsafe { lambda_0::operator_call(&inc, by) }); } + pub unsafe fn bump_via_method(&mut self, mut by: i32) { + let mut inc: lambda_1 = (lambda_1 { + this_: (self as *mut S), + }); + (unsafe { lambda_1::operator_call(&inc, by) }); + } + pub unsafe fn read_scaled(&self) -> i32 { + let mut get: lambda_2 = (lambda_2 { + this_: (self as *const S), + }); + return (unsafe { lambda_2::operator_call(&get) }); + } } #[repr(C)] #[derive(Copy, Clone, Default)] pub struct lambda_0 { - this_: *mut Counter, + this_: *mut S, } impl lambda_0 { pub unsafe fn operator_call(&self, mut k: i32) { @@ -35,14 +54,47 @@ impl Callable1 for lambda_0 { unsafe { lambda_0::operator_call(self, a1) } } } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + this_: *mut S, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut k: i32) { + (unsafe { S::add(&mut (*self.this_), k) }); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> () { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + this_: *const S, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) -> i32 { + return (unsafe { S::scaled(&(*self.this_)) }); + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + unsafe { lambda_2::operator_call(self) } + } +} pub fn main() { unsafe { std::process::exit(main_0() as i32); } } unsafe fn main_0() -> i32 { - let mut c: Counter = ::default(); - (unsafe { Counter::bump(&mut c, 3) }); - assert!(((c.n) == (6))); + let mut s: S = S { n: 0, step: 2 }; + (unsafe { S::bump(&mut s, 3) }); + assert!(((s.n) == (6))); + (unsafe { S::bump_via_method(&mut s, 4) }); + assert!(((s.n) == (10))); + assert!(((unsafe { S::read_scaled(&s,) }) == (20))); return 0; } diff --git a/tests/unit/out/unsafe/lambda_capture_value.rs b/tests/unit/out/unsafe/lambda_capture_value.rs new file mode 100644 index 00000000..449c4bba --- /dev/null +++ b/tests/unit/out/unsafe/lambda_capture_value.rs @@ -0,0 +1,99 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub x: i32, + pub y: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut factor: i32 = 3; + let mut scale: lambda_0 = (lambda_0 { factor: factor }); + assert!(((unsafe { lambda_0::operator_call(&scale, 4,) }) == (12))); + factor = 100; + assert!(((unsafe { lambda_0::operator_call(&scale, 4,) }) == (12))); + let mut slot: i32 = 7; + let mut p: *mut i32 = (&mut slot as *mut i32); + let mut read_ptr: lambda_1 = (lambda_1 { p: p }); + slot = 8; + assert!(((unsafe { lambda_1::operator_call(&read_ptr,) }) == (8))); + let mut s: S = S { x: 1, y: 2 }; + let mut sum: lambda_2 = (lambda_2 { s: s }); + s.x = 50; + assert!(((unsafe { lambda_2::operator_call(&sum,) }) == (3))); + let mut base: i32 = 10; + let mut shifted: lambda_3 = (lambda_3 { y: ((base) + (1)) }); + assert!(((unsafe { lambda_3::operator_call(&shifted, 5,) }) == (16))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + factor: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) * (self.factor)); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + p: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self) -> i32 { + return (*self.p); + } +} +impl Callable0 for lambda_1 { + fn call(&self) -> i32 { + unsafe { lambda_1::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + s: S, +} +impl lambda_2 { + pub unsafe fn operator_call(&self) -> i32 { + return ((self.s.x) + (self.s.y)); + } +} +impl Callable0 for lambda_2 { + fn call(&self) -> i32 { + unsafe { lambda_2::operator_call(self) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + y: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (self.y)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_3::operator_call(self, a1) } + } +} diff --git a/tests/unit/out/unsafe/lambda_mutable.rs b/tests/unit/out/unsafe/lambda_mutable.rs new file mode 100644 index 00000000..8bd65bf9 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_mutable.rs @@ -0,0 +1,48 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut start: i32 = 5; + let mut next: lambda_0 = (lambda_0 { start: start }); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (5))); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (6))); + assert!(((unsafe { lambda_0::operator_call(&mut next,) }) == (7))); + assert!(((start) == (5))); + let mut total: i32 = 0; + let mut accumulate: lambda_1 = (lambda_1 { total: total }); + assert!(((unsafe { lambda_1::operator_call(&mut accumulate, 1,) }) == (1))); + assert!(((unsafe { lambda_1::operator_call(&mut accumulate, 2,) }) == (3))); + assert!(((total) == (0))); + return 0; +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + start: i32, +} +impl lambda_0 { + pub unsafe fn operator_call(&mut self) -> i32 { + return self.start.postfix_inc(); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + total: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&mut self, mut x: i32) -> i32 { + self.total += x; + return self.total; + } +} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index 65af1acd..a86f05eb 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -6,6 +6,54 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub v: i32, +} +impl S { + pub unsafe fn nested_this(&mut self) -> i32 { + let mut outer: lambda_0 = (lambda_0 { + this_: (self as *mut S), + }); + return (unsafe { lambda_0::operator_call(&outer, 20) }); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + this_: *mut S, + y: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return ((((*self.this_).v) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + this_: *mut S, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_1 = (lambda_1 { + this_: self.this_, + y: y, + }); + return (unsafe { lambda_1::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -13,44 +61,46 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 10; - let mut outer: lambda_0 = (lambda_0 { x: &mut x }); - assert!(((unsafe { lambda_0::operator_call(&outer, 20,) }) == (31))); + let mut outer: lambda_2 = (lambda_2 { x: &mut x }); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (31))); x = 100; - assert!(((unsafe { lambda_0::operator_call(&outer, 20,) }) == (121))); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (121))); + let mut s: S = S { v: 5 }; + assert!(((unsafe { S::nested_this(&mut s,) }) == (26))); return 0; } #[repr(C)] #[derive(Copy, Clone, Default)] -pub struct lambda_1 { +pub struct lambda_3 { x: *mut i32, y: i32, } -impl lambda_1 { +impl lambda_3 { pub unsafe fn operator_call(&self, mut z: i32) -> i32 { return (((*self.x) + (self.y)) + (z)); } } -impl Callable1 for lambda_1 { +impl Callable1 for lambda_3 { fn call(&self, a1: i32) -> i32 { - unsafe { lambda_1::operator_call(self, a1) } + unsafe { lambda_3::operator_call(self, a1) } } } #[repr(C)] #[derive(Copy, Clone, Default)] -pub struct lambda_0 { +pub struct lambda_2 { x: *mut i32, } -impl lambda_0 { +impl lambda_2 { pub unsafe fn operator_call(&self, mut y: i32) -> i32 { - let mut inner: lambda_1 = (lambda_1 { + let mut inner: lambda_3 = (lambda_3 { x: &mut (*self.x), y: y, }); - return (unsafe { lambda_1::operator_call(&inner, 1) }); + return (unsafe { lambda_3::operator_call(&inner, 1) }); } } -impl Callable1 for lambda_0 { +impl Callable1 for lambda_2 { fn call(&self, a1: i32) -> i32 { - unsafe { lambda_0::operator_call(self, a1) } + unsafe { lambda_2::operator_call(self, a1) } } } diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index da3cd9de..57c12753 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -19,17 +19,9 @@ unsafe fn main_0() -> i32 { .offset((5) as isize) .offset_from(arr1.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { - if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*x, *y) - { + if (lambda_0 {}).call(*x, *y) { std::cmp::Ordering::Less - } else if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*y, *x) - { + } else if (lambda_0 {}).call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -38,3 +30,21 @@ unsafe fn main_0() -> i32 { }; return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call(mut x: i32, mut y: i32) -> bool { + return ((x) < (y)); + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + unsafe { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> Option bool> { + Some(lambda_0::operator_call) + } +} From f2b20e287f81c5b112cdc780c349882ce0f01ba3 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 10:44:06 +0100 Subject: [PATCH 36/43] format --- cpp2rust/converter/models/converter_refcount.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index dc115ca2..04c2087e 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -88,7 +88,9 @@ class ConverterRefCount final : public Converter { void EmitHoistedInArmAssignment(clang::VarDecl *decl) override; void AddCallableTrait(clang::CXXRecordDecl *decl) override; + void AddFunctionPointerConversion(clang::CXXRecordDecl *decl) override; + std::string ConvertLambdaToFunctionPointer(const clang::CXXMethodDecl *op) override; From eb00decaa7ddd3c0f00eb03603d4db61b04982e4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 11:41:12 +0100 Subject: [PATCH 37/43] Remove ConvertCXXRecordDecl --- cpp2rust/converter/converter.cpp | 17 +++++------------ cpp2rust/converter/converter.h | 1 - 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 8f3eb326..c32887fc 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -908,17 +908,9 @@ void Converter::EmitRustUnion(clang::RecordDecl *decl) { bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { decl->dump(log()); - std::vector saved_expr_kinds; - saved_expr_kinds.swap(curr_expr_kind_); - ConvertCXXRecordDecl(decl); - curr_expr_kind_.swap(saved_expr_kinds); - return false; -} - -void Converter::ConvertCXXRecordDecl(clang::CXXRecordDecl *decl) { Mapper::AddRuleForUserDefinedType(decl); if (!IsConvertibleCXXRecordDecl(decl)) { - return; + return false; } if (decl->isStruct() || decl->isClass()) { @@ -935,12 +927,12 @@ void Converter::ConvertCXXRecordDecl(clang::CXXRecordDecl *decl) { if (!decl->isAbstract()) { ConvertLateInstantiatedMethods(decl); } - return; + return false; } if (decl->isAbstract()) { ConvertAbstractClass(decl); - return; + return false; } DefineImplicitMembers(decl); @@ -951,13 +943,14 @@ void Converter::ConvertCXXRecordDecl(clang::CXXRecordDecl *decl) { } } else if (decl->isUnion()) { if (!record_decls_.MarkDefined(GetRecordName(decl))) { - return; + return false; } EmitRustStructOrUnion(decl); } else { // FIXME: improve error handling assert(0 && "unsupported record kind"); } + return false; } void Converter::DefineImplicitMembers(clang::CXXRecordDecl *decl) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 06e2156b..f40430e7 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -111,7 +111,6 @@ class Converter : public clang::RecursiveASTVisitor { bool VisitRecordDecl(clang::RecordDecl *decl); virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl); - void ConvertCXXRecordDecl(clang::CXXRecordDecl *decl); virtual void EmitRustStructOrUnion(clang::RecordDecl *decl); From 4db576761a8124aa4a7b442a9b37735ad2c276c7 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 12:41:31 +0100 Subject: [PATCH 38/43] Push unboxed when enttering Converter::VisitCXXRecordDecl --- cpp2rust/converter/models/converter_refcount.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index affe030e..10f145bc 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -431,11 +431,8 @@ bool ConverterRefCount::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (decl_ids_.count(GetID(decl))) { return false; } - std::vector saved_conversion_kinds({ConversionKind::Unboxed}); - saved_conversion_kinds.swap(conversion_kind_); - Converter::VisitCXXRecordDecl(decl); - conversion_kind_.swap(saved_conversion_kinds); - return false; + PushConversionKind push(*this, ConversionKind::Unboxed); + return Converter::VisitCXXRecordDecl(decl); } bool ConverterRefCount::VisitOffsetOfExpr(clang::OffsetOfExpr *expr) { From 4198025c3d0932641caf8a9b1cb10187be0d10bf Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 12:47:45 +0100 Subject: [PATCH 39/43] Type of declrefexpr differs based on context --- cpp2rust/converter/converter.cpp | 5 +-- cpp2rust/converter/converter_lib.cpp | 7 ++++ cpp2rust/converter/converter_lib.h | 3 ++ .../converter/models/converter_refcount.cpp | 3 +- tests/unit/lambda_capture_ref.cpp | 12 ++++++ tests/unit/out/refcount/lambda_capture_ref.rs | 39 +++++++++++++++++++ tests/unit/out/unsafe/lambda_capture_ref.rs | 22 +++++++++++ tests/unit/out/unsafe/lambda_nested.rs | 5 +-- 8 files changed, 87 insertions(+), 9 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index c32887fc..d3749134 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2697,7 +2697,7 @@ bool Converter::IsReferenceType(const clang::Expr *expr) const { GetReturnTypeOfFunction(call)->isReferenceType(); } if (const auto *decl_ref = clang::dyn_cast(e)) { - return decl_ref->getDecl()->getType()->isReferenceType(); + return GetDeclRefType(curr_function_, decl_ref)->isReferenceType(); } if (const auto *member = clang::dyn_cast(e)) { return member->getMemberDecl()->getType()->isReferenceType(); @@ -2906,8 +2906,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) { bool Converter::VisitDeclRefExpr(clang::DeclRefExpr *expr) { auto str = ConvertDeclRefExpr(expr); auto decl = expr->getDecl(); - auto *field = GetLambdaCapturedField(curr_function_, decl); - auto decl_t = field ? field->getType() : decl->getType(); + auto decl_t = GetDeclRefType(curr_function_, expr); if (decl_t->getAs() && !isAddrOf() && !map_iter_decls_.contains(clang::dyn_cast(decl))) { diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index de06a335..cd046646 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -692,6 +692,13 @@ clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, return it == captures.end() ? nullptr : it->second; } +clang::QualType GetDeclRefType(const clang::FunctionDecl *fn, + const clang::DeclRefExpr *expr) { + auto *decl = expr->getDecl(); + auto *field = GetLambdaCapturedField(fn, decl); + return field ? field->getType() : decl->getType(); +} + std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { auto name = decl->getDeclName().isIdentifier() ? decl->getName().str() : decl->getNameAsString(); diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 8ad74f2c..b7cd80d1 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -181,6 +181,9 @@ const clang::CXXRecordDecl *GetLambdaOf(const clang::FunctionDecl *fn); clang::FieldDecl *GetLambdaCapturedField(const clang::FunctionDecl *fn, const clang::ValueDecl *var); +clang::QualType GetDeclRefType(const clang::FunctionDecl *fn, + const clang::DeclRefExpr *expr); + clang::CXXConstructExpr *MakeConstructExpr(clang::ASTContext &ctx, clang::QualType type, clang::CXXConstructorDecl *ctor, diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 10f145bc..2ddac518 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -849,8 +849,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) { return false; } - auto *field = GetLambdaCapturedField(curr_function_, decl); - const auto decl_t = field ? field->getType() : decl->getType(); + const auto decl_t = GetDeclRefType(curr_function_, expr); if (IsGlobalVar(expr)) { auto tp = decl_t->isReferenceType() ? "Ptr" : "Value"; str = std::format("{}.with({}::clone)", str, std::move(tp)); diff --git a/tests/unit/lambda_capture_ref.cpp b/tests/unit/lambda_capture_ref.cpp index 065030af..761a0521 100644 --- a/tests/unit/lambda_capture_ref.cpp +++ b/tests/unit/lambda_capture_ref.cpp @@ -1,4 +1,6 @@ #include +#include +#include struct S { int x; @@ -24,5 +26,15 @@ int main() { bump(); assert(counter == 2); + uint16_t arr[4] = {3, 1, 2, 0}; + auto swap = [&arr](size_t i, size_t j) { + uint16_t t = arr[j]; + arr[j] = arr[i]; + arr[i] = t; + }; + swap(0, 3); + assert(arr[0] == 0); + assert(arr[3] == 3); + return 0; } diff --git a/tests/unit/out/refcount/lambda_capture_ref.rs b/tests/unit/out/refcount/lambda_capture_ref.rs index 1daa3f9c..788107f3 100644 --- a/tests/unit/out/refcount/lambda_capture_ref.rs +++ b/tests/unit/out/refcount/lambda_capture_ref.rs @@ -66,6 +66,15 @@ fn main_0() -> i32 { ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); ({ lambda_2::operator_call(&(*bump.borrow_mut())) }); assert!(((*counter.borrow()) == 2)); + let arr: Value> = Rc::new(RefCell::new(Box::new([3_u16, 1_u16, 2_u16, 0_u16]))); + let swap: Value = Rc::new(RefCell::new( + (lambda_3 { + arr: (arr.as_pointer() as Ptr>), + }), + )); + ({ lambda_3::operator_call(&(*swap.borrow_mut()), 0_usize, 3_usize) }); + assert!((((*arr.borrow())[(0) as usize] as i32) == 0)); + assert!((((*arr.borrow())[(3) as usize] as i32) == 3)); return 0; } #[derive(Clone, Default)] @@ -115,3 +124,33 @@ impl Callable0<()> for lambda_2 { { lambda_2::operator_call(self) } } } +#[derive(Clone, Default)] +pub struct lambda_3 { + arr: Ptr>, +} +impl lambda_3 { + pub fn operator_call(&self, i: usize, j: usize) { + let i: Value = Rc::new(RefCell::new(i)); + let j: Value = Rc::new(RefCell::new(j)); + let t: Value = Rc::new(RefCell::new( + ((self.arr.to_strong().as_pointer() as Ptr) + .offset((*j.borrow()) as isize) + .read()), + )); + let __rhs = ((self.arr.to_strong().as_pointer() as Ptr) + .offset((*i.borrow()) as isize) + .read()); + (self.arr.to_strong().as_pointer() as Ptr) + .offset((*j.borrow()) as isize) + .write(__rhs); + (self.arr.to_strong().as_pointer() as Ptr) + .offset((*i.borrow()) as isize) + .write((*t.borrow())); + } +} +impl ByteRepr for lambda_3 {} +impl Callable2 for lambda_3 { + fn call(&self, a1: usize, a2: usize) -> () { + { lambda_3::operator_call(self, a1, a2) } + } +} diff --git a/tests/unit/out/unsafe/lambda_capture_ref.rs b/tests/unit/out/unsafe/lambda_capture_ref.rs index b41d9573..b66d9e18 100644 --- a/tests/unit/out/unsafe/lambda_capture_ref.rs +++ b/tests/unit/out/unsafe/lambda_capture_ref.rs @@ -35,6 +35,11 @@ unsafe fn main_0() -> i32 { (unsafe { lambda_2::operator_call(&bump) }); (unsafe { lambda_2::operator_call(&bump) }); assert!(((counter) == (2))); + let mut arr: [u16; 4] = [3_u16, 1_u16, 2_u16, 0_u16]; + let mut swap: lambda_3 = (lambda_3 { arr: &mut arr }); + (unsafe { lambda_3::operator_call(&swap, 0_usize, 3_usize) }); + assert!(((arr[(0) as usize] as i32) == (0))); + assert!(((arr[(3) as usize] as i32) == (3))); return 0; } #[repr(C)] @@ -82,3 +87,20 @@ impl Callable0<()> for lambda_2 { unsafe { lambda_2::operator_call(self) } } } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + arr: *mut [u16; 4], +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut i: usize, mut j: usize) { + let mut t: u16 = (*self.arr)[(j)]; + (*self.arr)[(j)] = (*self.arr)[(i)]; + (*self.arr)[(i)] = t; + } +} +impl Callable2 for lambda_3 { + fn call(&self, a1: usize, a2: usize) -> () { + unsafe { lambda_3::operator_call(self, a1, a2) } + } +} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index a86f05eb..2d332ea1 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -92,10 +92,7 @@ pub struct lambda_2 { } impl lambda_2 { pub unsafe fn operator_call(&self, mut y: i32) -> i32 { - let mut inner: lambda_3 = (lambda_3 { - x: &mut (*self.x), - y: y, - }); + let mut inner: lambda_3 = (lambda_3 { x: self.x, y: y }); return (unsafe { lambda_3::operator_call(&inner, 1) }); } } From 1204400960c8232d03d966bd71b9c102a434ac12 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 13:27:10 +0100 Subject: [PATCH 40/43] Update docs --- docs/src/SUMMARY.md | 1 + docs/src/codegen/types/fn-pointers.md | 3 +- docs/src/codegen/types/lambdas.md | 157 +++++++++++++++++--------- docs/src/codegen/types/mappings.md | 36 +++--- docs/src/rules/writing-rules.md | 22 ++-- docs/src/runtime/callable.md | 52 +++++++++ docs/src/runtime/overview.md | 2 + 7 files changed, 191 insertions(+), 82 deletions(-) create mode 100644 docs/src/runtime/callable.md diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 690d9dca..6cd722a4 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -31,6 +31,7 @@ - [Increment and Decrement](./runtime/inc-dec.md) - [Iterators](./runtime/iterators.md) - [Function Pointers](./runtime/fn-ptr.md) +- [Callable](./runtime/callable.md) - [Variadic Functions](./runtime/va-args.md) - [Control Flow Macros](./runtime/control-flow.md) - [I/O and Formatting](./runtime/io.md) diff --git a/docs/src/codegen/types/fn-pointers.md b/docs/src/codegen/types/fn-pointers.md index 5d9880fd..d8d57c0d 100644 --- a/docs/src/codegen/types/fn-pointers.md +++ b/docs/src/codegen/types/fn-pointers.md @@ -71,4 +71,5 @@ in a variable clones it, and equality compares the address of the wrapped function, so a pointer stays equal to itself after being cast. A capture-less lambda assigned to a function pointer becomes -`FnPtr::new(|...| ...)` with the closure inline (see [Lambdas](./lambdas.md)). +`lambda_N::to_free_function()`, which returns +`FnPtr::new(lambda_N::operator_call)` (see [Lambdas](./lambdas.md)). diff --git a/docs/src/codegen/types/lambdas.md b/docs/src/codegen/types/lambdas.md index 1f3743c9..bd7e4314 100644 --- a/docs/src/codegen/types/lambdas.md +++ b/docs/src/codegen/types/lambdas.md @@ -1,7 +1,9 @@ # Lambdas -A lambda becomes a Rust closure with the same parameters and a translated body. -Given +A lambda becomes a struct with one field per capture, an inherent +`operator_call` method holding the translated body, a `Callable` impl so generic +code can invoke it, and, for a capture-less lambda, a `to_free_function` +associated method that yields it as a function pointer. Given ```cpp template int apply(F fn, int x) { return fn(x); } @@ -16,76 +18,125 @@ int main() { the unsafe model produces ```rust -pub unsafe fn apply_0(mut fn_: impl Fn(i32) -> i32, mut x: i32) -> i32 { - return fn_(x); +pub unsafe fn apply_0(mut fn_: lambda_1, mut x: i32) -> i32 { + return (unsafe { lambda_1::operator_call(&fn_, x) }); } unsafe fn main_0() -> i32 { let mut base: i32 = 10; - return apply_0( - (|x: i32| { - return x + base; - }) - .clone(), - 5, - ); + let mut add_base: lambda_1 = (lambda_1 { base: &mut base }); + return (unsafe { apply_0(add_base, 5) }); +} +pub struct lambda_1 { + base: *mut i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut x: i32) -> i32 { + return ((x) + (*self.base)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } } ``` and the refcount model produces ```rust -pub fn apply_0(fn_: impl Fn(i32) -> i32, x: i32) -> i32 { - let fn_: Value<_> = Rc::new(RefCell::new(fn_)); +pub fn apply_0(fn_: lambda_1, x: i32) -> i32 { + let fn_: Value = Rc::new(RefCell::new(fn_)); let x: Value = Rc::new(RefCell::new(x)); - return (*fn_.borrow_mut())(*x.borrow()); + return ({ lambda_1::operator_call(&(*fn_.borrow_mut()), (*x.borrow())) }); } fn main_0() -> i32 { let base: Value = Rc::new(RefCell::new(10)); - let add_base: Value<_> = Rc::new(RefCell::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return *x.borrow() + *base.borrow(); + let add_base: Value = Rc::new(RefCell::new( + (lambda_1 { + base: base.as_pointer(), }), )); - return apply_0((*add_base.borrow()).clone(), 5); + return ({ apply_0((*add_base.borrow()).clone(), 5) }); +} +pub struct lambda_1 { + base: Ptr, +} +impl lambda_1 { + pub fn operator_call(&self, x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return ((*x.borrow()) + (self.base.read())); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } } ``` -## Closure and type +## Closure struct + +The closure type is named `lambda_N`, numbered in order of appearance, and is +emitted at file scope. Each capture becomes a field named after the captured +variable, typed as the capture field of clang's closure class: + +| Capture | C++ field type | Unsafe | Refcount | +| -------- | -------------- | ------------- | --------------- | +| `[x]` | `T` | `T` | `Value` | +| `[&x]` | `T&` | `*mut T` | `Ptr` | +| `[&arr]` | `T (&)[N]` | `*mut [T; N]` | `Ptr>` | +| `[this]` | `S*` | `*mut S` | `Value>` | -The closure lists the lambda's parameters with their translated types and -contains the body converted like a function body, including, in the refcount -model, the preamble that boxes each parameter. The lambda's own type is never -spelled: a variable holding one is `Value<_>` in the refcount model and the type -is inferred, and a function template parameter that receives one is -`impl Fn(A) -> R`, as `apply` shows. A call through such a parameter is a plain -call, `fn_(x)`, with the refcount model borrowing the boxed closure first. +The struct follows the same trait rules as an ordinary struct, described in +[Traits](./traits.md). + +The lambda expression itself becomes a struct literal. A by-value capture copies +the variable at that point, a by-reference capture takes its address, so C++'s +distinction between `[x]` and `[&x]` is preserved: the first never sees later +writes to `x`, the second does. ## Captures -The C++ capture list is not translated. A Rust closure captures whatever it -mentions by reference, so `[&base]` and `[base]` produce the same closure and -both see the variable's current value at call time. For a by-reference capture -this is C++'s semantics; for a by-value capture it is not, since C++ copies the -variable when the lambda is created. - -## Where the closure is emitted - -The refcount model emits a variable initialized with a lambda as a boxed closure -once and clones it out of the box at each use. - -> [!WARNING] -> -> The unsafe model does not emit a `let` for such a variable; the closure is -> emitted again at every use, which is why the example above shows it inline in -> the `apply_0` call. This was a workaround: a stored closure that captures -> locals by reference keeps them borrowed for as long as it lives, so -> `let foo = || { a += 1; a }; return foo() + a;` does not compile, while -> re-emitting the closure at each call keeps every borrow inside that call. It -> is a bug, since the lambda's creation and its uses are no longer the same -> object ([#314](https://github.com/Cpp2Rust/cpp2rust/issues/314)). - -A capture-less lambda assigned to a function pointer becomes a function pointer -value: `Some(|...| ...)` in the unsafe model and `FnPtr::new(|...| ...)` in the -refcount model (see [Function Pointers](./fn-pointers.md)). Lambdas with -captures cannot be converted to function pointers, as in C++. +Explicit, implicit and init-captures all translate the same way, because clang +materializes every capture as a closure field before the converter runs. `[=]` +and `[&]` produce one field per variable the body mentions, and `[y = x + 1]` +produces a field `y` whose value in the struct literal is the initializer +expression, evaluated where the lambda expression appears. + +A captured `this` becomes a field named `this_`. A use of `this` in the body, +explicit or implied by a member access, reads that field: `self.this_` in the +unsafe model, `(*self.this_.borrow())` in the refcount model. From there member +access and method calls proceed as through any other pointer to the enclosing +class. + +## Call operator + +The body is emitted as `operator_call` on the closure struct. Its receiver +follows the C++ call operator: + +- `&self` for an ordinary lambda, whose call operator is `const`; +- `&mut self` for a `mutable` lambda, so writes to by-value captures persist + across calls; +- no receiver for a capture-less lambda, which makes `operator_call` a plain + associated function. + +## Callable + +A lambda whose call operator is `const` also implements +[`Callable`](../../runtime/callable.md), so it can be passed to rules and +helpers that take a callable argument. + +## Conversion to function pointer + +A capture-less lambda has a conversion operator to function pointer. It becomes +a `to_free_function` method that returns the call operator as a function pointer +value: `Some(lambda_N::operator_call)` in the unsafe model and +`FnPtr::new(lambda_N::operator_call)` in the refcount model (see +[Function Pointers](./fn-pointers.md)). Assigning or passing such a lambda where +a function pointer is expected calls `to_free_function` on the closure object. + +## Where the struct is emitted + +The struct and its impls are hoisted to file scope after the enclosing top-level +declaration, so the function body keeps only the struct literal instead of +several items of boilerplate. diff --git a/docs/src/codegen/types/mappings.md b/docs/src/codegen/types/mappings.md index 02bd111b..8f2ce203 100644 --- a/docs/src/codegen/types/mappings.md +++ b/docs/src/codegen/types/mappings.md @@ -3,24 +3,24 @@ The table gives the spelling of each C++ type in both models, before any refcount boxing. `T` stands for the translated inner type. -| C++ | Unsafe model | Refcount model | -| ------------------------------ | ----------------------------------------------- | --------------------------------------------------------- | -| `bool` | `bool` | `bool` | -| `int`, `unsigned long`, ... | `i32`, `u64`, ... (host width) | same | -| `float`, `double` | `f32`, `f64` | same | -| `char` | `libc::c_char` | `u8` | -| `size_t` and other typedefs | by type rule (`usize`), else desugared | same | -| `T[N]` | `[T; N]` | `Box<[T]>` | -| `T[]` | `[T]` | `Box<[T]>` | -| `struct S`, `enum E` | `S`, `E` | same | -| `T *`, `T &` | `*mut T`, `*const T` | [`Ptr`](../../runtime/rc.md#values-and-pointers) | -| `Abstract *` | `*mut dyn Abstract` | [`PtrDyn`](../../runtime/ptr-dyn.md) | -| `void *` | `*mut ::libc::c_void` | [`AnyPtr`](../../runtime/void.md) | -| `R (*)(A)` | `Option R>` | [`FnPtr R>`](../../runtime/fn-ptr.md) | -| `va_list` | [`VaList`](../../runtime/va-args.md) | [`VaList`](../../runtime/va-args.md) | -| lambda closure | `impl Fn(A) -> R` as a parameter, `_` elsewhere | same | -| `std::unique_ptr` | by type rule (`Option>`) | by type rule (`Option>`) | -| `std::vector` and other STL | by type rule (`Vec`) | by type rule (`Vec`, `Vec>>` when nested) | +| C++ | Unsafe model | Refcount model | +| ------------------------------ | -------------------------------------- | --------------------------------------------------------- | +| `bool` | `bool` | `bool` | +| `int`, `unsigned long`, ... | `i32`, `u64`, ... (host width) | same | +| `float`, `double` | `f32`, `f64` | same | +| `char` | `libc::c_char` | `u8` | +| `size_t` and other typedefs | by type rule (`usize`), else desugared | same | +| `T[N]` | `[T; N]` | `Box<[T]>` | +| `T[]` | `[T]` | `Box<[T]>` | +| `struct S`, `enum E` | `S`, `E` | same | +| `T *`, `T &` | `*mut T`, `*const T` | [`Ptr`](../../runtime/rc.md#values-and-pointers) | +| `Abstract *` | `*mut dyn Abstract` | [`PtrDyn`](../../runtime/ptr-dyn.md) | +| `void *` | `*mut ::libc::c_void` | [`AnyPtr`](../../runtime/void.md) | +| `R (*)(A)` | `Option R>` | [`FnPtr R>`](../../runtime/fn-ptr.md) | +| `va_list` | [`VaList`](../../runtime/va-args.md) | [`VaList`](../../runtime/va-args.md) | +| lambda closure | [`lambda_N` struct](./lambdas.md) | same | +| `std::unique_ptr` | by type rule (`Option>`) | by type rule (`Option>`) | +| `std::vector` and other STL | by type rule (`Vec`) | by type rule (`Vec`, `Vec>>` when nested) | Other built-ins (`wchar_t`, `long double`, `char16_t`) are omitted. Rvalue references (`T &&`) have no mapping of their own; they reach the converter only diff --git a/docs/src/rules/writing-rules.md b/docs/src/rules/writing-rules.md index 1bd7b9ef..c2d42a16 100644 --- a/docs/src/rules/writing-rules.md +++ b/docs/src/rules/writing-rules.md @@ -133,30 +133,32 @@ accesses are rules of their own, matched by the field: `it->first` and ## Callable arguments -A rule parameter may be a callable. Function pointers are spelled directly; for -a lambda, whose type cannot be written, the rule declares a file-scope lambda -and takes `decltype(lambda)`: +A rule parameter may be a callable: a function pointer, a functor or a lambda. +The source side takes it through a helper type, and the target side binds the +corresponding generic parameter with `Callable`: ```cpp // rules/algorithm/src.cpp -auto lambda = [](const T2 &a, const T2 &b) { return false; }; -void f6(T1 first, T1 last, decltype(lambda) comp) { +void f6(T1 first, T1 last, T2 comp) { return std::stable_sort(first, last, comp); } ``` ```rust // rules/algorithm/tgt_unsafe.rs -unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: &mut T2) +unsafe fn f6(a0: *mut T1, a1: *mut T1, a2: T2) where - T2: FnMut(&T1, &T1) -> bool, -{ ... } + T2: Callable2<*const T1, *const T1, bool>, +{ ... a2.call(x, y) ... } ``` +The bound is [`Callable`](../runtime/callable.md) rather than `Fn` so that one +rule serves every kind of callable argument, including translated lambdas, which +are structs and cannot implement `Fn`. + `T1` and `T2` are not template parameters here but file-scope helper structs modelling an iterator and its value type; being named like generics, they bind -as `T1`/`T2` at the use site. The function pointer version of the comparator is -a separate rule (`f7`). +as `T1`/`T2` at the use site. ## Iterators diff --git a/docs/src/runtime/callable.md b/docs/src/runtime/callable.md new file mode 100644 index 00000000..2180eaab --- /dev/null +++ b/docs/src/runtime/callable.md @@ -0,0 +1,52 @@ +# Callable + +In C++ a function pointer, a functor (a user-defined struct with `operator()`) +and a lambda are all called the same way, `f(x)`, and a template parameter +accepts any of them. Rust has the `Fn` traits for that role, but only closures +and safe `fn` items implement them; a user struct or an `unsafe fn` cannot. +`libcc2rs` therefore provides its own call trait, one per arity: + +```rust +pub trait Callable0 { fn call(&self) -> R; } +pub trait Callable1 { fn call(&self, a1: A1) -> R; } +pub trait Callable2 { fn call(&self, a1: A1, a2: A2) -> R; } +pub trait Callable3 { fn call(&self, a1: A1, a2: A2, a3: A3) -> R; } +``` + +Three kinds of value implement it: + +- safe `fn` items, through a blanket impl for every type implementing the + matching `Fn`; +- `unsafe fn` pointers, through a second blanket impl that wraps the call in an + `unsafe` block; +- [translated lambdas](../codegen/types/lambdas.md), through a call to + `operator_call`. + +Code written against a `CallableK` bound invokes any of them through +`.call(..)`. This is how the STL algorithm rules take their comparators: + +```rust +fn f6(a0: Ptr, a1: Ptr, a2: T2) +where + T2: Callable2, Ptr, bool>, +{ + a0.sort_with_cmp(a1.get_offset(), |x, y| a2.call(x, y)) +} +``` + +## Why not `Fn` + +Implementing `Fn`, `FnMut` or `FnOnce` for a user type needs the +`unboxed_closures` and `fn_traits` features, which are +[nightly-only](https://github.com/rust-lang/rust/issues/29625). + +## Notes + +There is one trait per arity, `Callable0` to `Callable3`, rather than a single +trait over a tuple of arguments, so that a call is written `call(x, y)` and not +`call((x, y))`. + +`call` takes `&self`, so only callables with a `const` call operator can +implement the trait. A `mutable` lambda, whose `operator_call` takes +`&mut self`, gets no `Callable` impl. This is a limitation of the trait +definition, not of the lambda translation. diff --git a/docs/src/runtime/overview.md b/docs/src/runtime/overview.md index c52c9e48..aabf51a6 100644 --- a/docs/src/runtime/overview.md +++ b/docs/src/runtime/overview.md @@ -46,6 +46,8 @@ Language-feature emulation, used by both models: strings up to the null terminator. - [`fn_ptr`](./fn-ptr.md): `FnPtr`, function pointers with C-style address identity. +- [`callable`](./callable.md): `Callable0` to `Callable3`, the call trait for + translated lambdas. - [`va_args`](./va-args.md): `VaArg` and `VaList`, the representation of variadic calls. - The [`goto`, `goto_block`, and `switch`](./control-flow.md) proc macros, From dbac4cc72cb8cbcc4ba244d120584f2ac90d3c95 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 13:36:22 +0100 Subject: [PATCH 41/43] Merge artifacts --- cpp2rust/converter/converter.h | 16 ++++++++-------- .../refcount/operator_member_pointer_member.rs | 9 +-------- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 38fe0853..59d6fba4 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -456,18 +456,18 @@ class Converter : public clang::RecursiveASTVisitor { #define StrCat(...) _StrCat(__FUNCTION__, __LINE__, __VA_ARGS__) inline bool is_empty(char c) { return false; } - inline bool is_empty(const char* s) { return s == nullptr || *s == '\0'; } - template - inline bool is_empty(const char (&s)[N]) { return s[0] == '\0'; } - template - inline bool is_empty(const T &s) { return s.empty(); } + inline bool is_empty(const char *s) { return s == nullptr || *s == '\0'; } + template inline bool is_empty(const char (&s)[N]) { + return s[0] == '\0'; + } + template inline bool is_empty(const T &s) { return s.empty(); } template inline void _StrCat(const char *func, int line, const Ts &...vals) { log() << '[' << func << ':' << line << "] "; - ((log() << vals << '\n', - *rs_code_ += vals, - (is_empty(vals) ? void() : void(*rs_code_ += ' '))), ...); + ((log() << vals << '\n', *rs_code_ += vals, + (is_empty(vals) ? void() : void(*rs_code_ += ' '))), + ...); } class Buffer { diff --git a/tests/unit/out/refcount/operator_member_pointer_member.rs b/tests/unit/out/refcount/operator_member_pointer_member.rs index a0e2fa34..2ebef305 100644 --- a/tests/unit/out/refcount/operator_member_pointer_member.rs +++ b/tests/unit/out/refcount/operator_member_pointer_member.rs @@ -32,7 +32,7 @@ impl ByteRepr for Inner { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Table {} impl Table { pub fn operator_index(i: i32) -> Ptr { @@ -40,13 +40,6 @@ impl Table { return (table_0.with(Value::clone).as_pointer() as Ptr).offset((*i.borrow())); } } -impl Clone for Table { - fn clone(&self) -> Self { - let __this: Value
= Rc::new(RefCell::new(Self {})); - let this: Ptr
= __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Table { fn byte_size() -> usize { 1 From 65b66e1e04f0673b500183a01e7c42eeb86c6c82 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 13:36:37 +0100 Subject: [PATCH 42/43] Use ensure instead of assert --- cpp2rust/converter/converter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 2bb60c00..bbcd2f6f 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3633,7 +3633,7 @@ static constexpr unsigned kMaxCallableArity = 3; void Converter::AddCallableTrait(clang::CXXRecordDecl *decl) { auto *op = decl->getLambdaCallOperator(); - assert(op->getNumParams() <= kMaxCallableArity); + ENSURE(op->getNumParams() <= kMaxCallableArity); if (!op->isConst()) { return; } From dbb61ac472f59d3f6f39b88036f94b3520e61aef Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Thu, 17 Sep 2026 16:00:44 +0100 Subject: [PATCH 43/43] Update tests --- tests/ub/out/refcount/ctor_ref_member.rs | 11 +- tests/ub/out/refcount/ub6.rs | 12 +- tests/unit/out/refcount/complex_function.rs | 11 +- tests/unit/out/refcount/destructor.rs | 9 +- tests/unit/out/refcount/fn_ptr_default_arg.rs | 35 +++- .../unit/out/refcount/function_overloading.rs | 9 +- .../out/refcount/global_init_side_effect.rs | 9 +- .../out/refcount/global_non_const_init.rs | 9 +- .../refcount/lambda_as_template_argument.rs | 2 + tests/unit/out/refcount/lambda_basic.rs | 2 + .../out/refcount/lambda_capture_implicit.rs | 2 + tests/unit/out/refcount/lambda_capture_ref.rs | 2 + .../unit/out/refcount/lambda_capture_this.rs | 2 + .../unit/out/refcount/lambda_capture_value.rs | 2 + tests/unit/out/refcount/lambda_mutable.rs | 2 + tests/unit/out/refcount/lambda_nested.rs | 188 ++++++++++++++++-- tests/unit/out/refcount/lambda_to_fn_ptr.rs | 2 + tests/unit/out/refcount/nested_structs.rs | 9 +- .../operator_member_pointer_member.rs | 9 +- .../out/refcount/operator_other_member.rs | 9 +- tests/unit/out/refcount/polymorphism.rs | 18 +- tests/unit/out/refcount/random.rs | 9 +- tests/unit/out/refcount/stable_sort.rs | 38 +++- .../unit/out/refcount/static_var_in_class.rs | 18 +- .../out/refcount/vector_with_allocator.rs | 18 +- tests/unit/out/unsafe/fn_ptr_default_arg.rs | 22 +- .../out/unsafe/lambda_as_template_argument.rs | 2 + tests/unit/out/unsafe/lambda_basic.rs | 2 + .../out/unsafe/lambda_capture_implicit.rs | 2 + tests/unit/out/unsafe/lambda_capture_ref.rs | 2 + tests/unit/out/unsafe/lambda_capture_this.rs | 2 + tests/unit/out/unsafe/lambda_capture_value.rs | 2 + tests/unit/out/unsafe/lambda_mutable.rs | 2 + tests/unit/out/unsafe/lambda_nested.rs | 107 ++++++++-- tests/unit/out/unsafe/lambda_to_fn_ptr.rs | 2 + tests/unit/out/unsafe/stable_sort.rs | 30 ++- 36 files changed, 406 insertions(+), 206 deletions(-) diff --git a/tests/ub/out/refcount/ctor_ref_member.rs b/tests/ub/out/refcount/ctor_ref_member.rs index 485688a0..7cde8387 100644 --- a/tests/ub/out/refcount/ctor_ref_member.rs +++ b/tests/ub/out/refcount/ctor_ref_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct S { pub r: Ptr, } @@ -17,15 +17,6 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - r: (self.r).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S {} pub fn main() { __cpp2rust_init_globals(); diff --git a/tests/ub/out/refcount/ub6.rs b/tests/ub/out/refcount/ub6.rs index ad4b8c8f..aa822287 100644 --- a/tests/ub/out/refcount/ub6.rs +++ b/tests/ub/out/refcount/ub6.rs @@ -6,21 +6,11 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Pair { pub x1: Ptr, pub x2: Ptr, } -impl Clone for Pair { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - x1: (self.x1).clone(), - x2: (self.x2).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Pair {} pub fn mkPair_0(x1: Ptr, x2: Ptr) -> Pair { return Pair { diff --git a/tests/unit/out/refcount/complex_function.rs b/tests/unit/out/refcount/complex_function.rs index 76ba6b78..7ecac949 100644 --- a/tests/unit/out/refcount/complex_function.rs +++ b/tests/unit/out/refcount/complex_function.rs @@ -43,19 +43,10 @@ impl ByteRepr for X1 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X2 { pub v: Ptr, } -impl Clone for X2 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self { - v: (self.v).clone(), - })); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X2 {} #[derive(Default)] pub struct X3 { diff --git a/tests/unit/out/refcount/destructor.rs b/tests/unit/out/refcount/destructor.rs index 5050cd7c..92e25cee 100644 --- a/tests/unit/out/refcount/destructor.rs +++ b/tests/unit/out/refcount/destructor.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( pub static global_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/fn_ptr_default_arg.rs b/tests/unit/out/refcount/fn_ptr_default_arg.rs index 7e5a0bb3..a8a1e7eb 100644 --- a/tests/unit/out/refcount/fn_ptr_default_arg.rs +++ b/tests/unit/out/refcount/fn_ptr_default_arg.rs @@ -27,13 +27,36 @@ fn main_0() -> i32 { assert!((({ apply_1(5, None,) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::null()),) }) == 5)); assert!((({ apply_1(5, Some(FnPtr:: i32>::new(identity_0)),) }) == 5)); - let negate: Value i32>> = Rc::new(RefCell::new(FnPtr::new( - (|x: i32| { - let x: Value = Rc::new(RefCell::new(x)); - return -(*x.borrow()); - }), - ))); + let negate: Value i32>> = + Rc::new(RefCell::new(({ (lambda_2 {}).to_free_function() }))); assert!((({ apply_1(5, Some((*negate.borrow()).clone()),) }) == -5_i32)); return 0; } +#[derive(Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub fn operator_call(x: i32) -> i32 { + let x: Value = Rc::new(RefCell::new(x)); + return -(*x.borrow()); + } +} +impl ByteRepr for lambda_2 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> FnPtr i32> { + FnPtr::new(lambda_2::operator_call) + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/function_overloading.rs b/tests/unit/out/refcount/function_overloading.rs index e720b72b..95407501 100644 --- a/tests/unit/out/refcount/function_overloading.rs +++ b/tests/unit/out/refcount/function_overloading.rs @@ -36,15 +36,8 @@ pub fn foo_3(x: Ptr, y: Ptr, z: Ptr) -> i32 { pub fn bar_4(x: Ptr) -> i32 { return (x.read()); } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Foo {} -impl Clone for Foo { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Foo { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/global_init_side_effect.rs b/tests/unit/out/refcount/global_init_side_effect.rs index 847bf9cf..3cd7aac0 100644 --- a/tests/unit/out/refcount/global_init_side_effect.rs +++ b/tests/unit/out/refcount/global_init_side_effect.rs @@ -9,7 +9,7 @@ use std::rc::{Rc, Weak}; thread_local!( pub static total_0: Value = Rc::new(RefCell::new(0)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} impl S { pub fn S(x: i32) -> Self { @@ -20,13 +20,6 @@ impl S { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/global_non_const_init.rs b/tests/unit/out/refcount/global_non_const_init.rs index a60421a3..760b566e 100644 --- a/tests/unit/out/refcount/global_non_const_init.rs +++ b/tests/unit/out/refcount/global_non_const_init.rs @@ -99,15 +99,8 @@ thread_local!( thread_local!( pub static inline_member_11: Value = Rc::new(RefCell::new(Ctor::Ctor2({ 5 }))); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct Holder {} -impl Clone for Holder { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Holder { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/lambda_as_template_argument.rs b/tests/unit/out/refcount/lambda_as_template_argument.rs index 218d0ce0..c2b978e9 100644 --- a/tests/unit/out/refcount/lambda_as_template_argument.rs +++ b/tests/unit/out/refcount/lambda_as_template_argument.rs @@ -30,6 +30,7 @@ pub fn apply_twice_6(fn_: lambda_3, x: i32) -> i32 { }); } pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -131,3 +132,4 @@ impl lambda_5 { FnPtr::new(lambda_5::operator_call) } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_basic.rs b/tests/unit/out/refcount/lambda_basic.rs index 50637b60..33fa897a 100644 --- a/tests/unit/out/refcount/lambda_basic.rs +++ b/tests/unit/out/refcount/lambda_basic.rs @@ -7,6 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -157,3 +158,4 @@ impl Callable0 for lambda_4 { { lambda_4::operator_call(self) } } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_implicit.rs b/tests/unit/out/refcount/lambda_capture_implicit.rs index 2e450912..a02b687a 100644 --- a/tests/unit/out/refcount/lambda_capture_implicit.rs +++ b/tests/unit/out/refcount/lambda_capture_implicit.rs @@ -7,6 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -136,3 +137,4 @@ impl Callable1 for lambda_2 { { lambda_2::operator_call(self, a1) } } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_ref.rs b/tests/unit/out/refcount/lambda_capture_ref.rs index 788107f3..17a7e785 100644 --- a/tests/unit/out/refcount/lambda_capture_ref.rs +++ b/tests/unit/out/refcount/lambda_capture_ref.rs @@ -37,6 +37,7 @@ impl ByteRepr for S { } } pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -154,3 +155,4 @@ impl Callable2 for lambda_3 { { lambda_3::operator_call(self, a1, a2) } } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_this.rs b/tests/unit/out/refcount/lambda_capture_this.rs index 35843b70..ada3b071 100644 --- a/tests/unit/out/refcount/lambda_capture_this.rs +++ b/tests/unit/out/refcount/lambda_capture_this.rs @@ -141,6 +141,7 @@ impl Callable0 for lambda_2 { } } pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -199,3 +200,4 @@ impl SImpl for Ptr { return ({ lambda_2::operator_call(&(*get.borrow_mut())) }); } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_capture_value.rs b/tests/unit/out/refcount/lambda_capture_value.rs index 210b4d0d..a4c8fc8c 100644 --- a/tests/unit/out/refcount/lambda_capture_value.rs +++ b/tests/unit/out/refcount/lambda_capture_value.rs @@ -37,6 +37,7 @@ impl ByteRepr for S { } } pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -216,3 +217,4 @@ impl Callable1 for lambda_3 { { lambda_3::operator_call(self, a1) } } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_mutable.rs b/tests/unit/out/refcount/lambda_mutable.rs index 54b02d77..51dc3c43 100644 --- a/tests/unit/out/refcount/lambda_mutable.rs +++ b/tests/unit/out/refcount/lambda_mutable.rs @@ -7,6 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -91,3 +92,4 @@ impl ByteRepr for lambda_1 { } } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_nested.rs b/tests/unit/out/refcount/lambda_nested.rs index 29670d7b..160fc63a 100644 --- a/tests/unit/out/refcount/lambda_nested.rs +++ b/tests/unit/out/refcount/lambda_nested.rs @@ -6,27 +6,187 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +#[derive(Default)] +pub struct S { + pub v: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 4 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + } + } +} +#[derive(Default)] +pub struct lambda_1 { + this_: Value>, + y: Value, +} +impl lambda_1 { + fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((*(*(*self.this_.borrow()).upgrade().deref()).v.borrow()) + (*self.y.borrow())) + + (*z.borrow())); + } +} +impl Clone for lambda_1 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_1 { + fn byte_size() -> usize { + 16 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + (*self.y.borrow()).to_bytes(&mut buf[8..12]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[8..12]))), + } + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + { lambda_1::operator_call(self, a1) } + } +} +#[derive(Default)] +pub struct lambda_0 { + this_: Value>, +} +impl lambda_0 { + fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_1 { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_1::operator_call(&(*inner.borrow_mut()), 1) }); + } +} +impl Clone for lambda_0 { + fn clone(&self) -> Self { + Self { + this_: Rc::new(RefCell::new((*self.this_.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.this_.borrow()).to_bytes(&mut buf[0..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + this_: Rc::new(RefCell::new(>::from_bytes(&buf[0..8]))), + } + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + { lambda_0::operator_call(self, a1) } + } +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { let x: Value = Rc::new(RefCell::new(10)); - let outer: Value<_> = Rc::new(RefCell::new( - (|y: i32| { - let y: Value = Rc::new(RefCell::new(y)); - let inner: Value<_> = Rc::new(RefCell::new( - (|z: i32| { - let z: Value = Rc::new(RefCell::new(z)); - return (((*x.borrow()) + (*y.borrow())) + (*z.borrow())); - }), - )); - return ({ (*inner.borrow_mut())(1) }); - }), - )); - assert!((({ (*outer.borrow_mut())(20,) }) == 31)); + let outer: Value = Rc::new(RefCell::new((lambda_2 { x: x.as_pointer() }))); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 31)); (*x.borrow_mut()) = 100; - assert!((({ (*outer.borrow_mut())(20,) }) == 121)); + assert!((({ lambda_2::operator_call(&(*outer.borrow_mut()), 20,) }) == 121)); + let s: Value = Rc::new(RefCell::new(S { + v: Rc::new(RefCell::new(5)), + })); + assert!((({ SImpl::nested_this(&s.as_pointer(),) }) == 26)); return 0; } +#[derive(Default)] +pub struct lambda_3 { + x: Ptr, + y: Value, +} +impl lambda_3 { + pub fn operator_call(&self, z: i32) -> i32 { + let z: Value = Rc::new(RefCell::new(z)); + return (((self.x.read()) + (*self.y.borrow())) + (*z.borrow())); + } +} +impl Clone for lambda_3 { + fn clone(&self) -> Self { + Self { + x: self.x.clone(), + y: Rc::new(RefCell::new((*self.y.borrow()).clone())), + } + } +} +impl ByteRepr for lambda_3 {} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + { lambda_3::operator_call(self, a1) } + } +} +#[derive(Clone, Default)] +pub struct lambda_2 { + x: Ptr, +} +impl lambda_2 { + pub fn operator_call(&self, y: i32) -> i32 { + let y: Value = Rc::new(RefCell::new(y)); + let inner: Value = Rc::new(RefCell::new( + (lambda_3 { + x: (self.x).clone(), + y: Rc::new(RefCell::new((*y.borrow()))), + }), + )); + return ({ lambda_3::operator_call(&(*inner.borrow_mut()), 1) }); + } +} +impl ByteRepr for lambda_2 {} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + { lambda_2::operator_call(self, a1) } + } +} +pub trait SImpl { + fn nested_this(&self) -> i32; +} +impl SImpl for Ptr { + fn nested_this(&self) -> i32 { + let outer: Value = Rc::new(RefCell::new( + (lambda_0 { + this_: Rc::new(RefCell::new((*self).clone())), + }), + )); + return ({ lambda_0::operator_call(&(*outer.borrow_mut()), 20) }); + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/lambda_to_fn_ptr.rs b/tests/unit/out/refcount/lambda_to_fn_ptr.rs index 78e109e9..37f4c3a8 100644 --- a/tests/unit/out/refcount/lambda_to_fn_ptr.rs +++ b/tests/unit/out/refcount/lambda_to_fn_ptr.rs @@ -12,6 +12,7 @@ pub fn apply_0(x: i32, fn_: FnPtr i32>) -> i32 { return ({ (*(*fn_.borrow()))((*x.borrow())) }); } pub fn main() { + __cpp2rust_init_globals(); std::process::exit(main_0()); } fn main_0() -> i32 { @@ -81,3 +82,4 @@ impl lambda_2 { FnPtr::new(lambda_2::operator_call) } } +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/nested_structs.rs b/tests/unit/out/refcount/nested_structs.rs index 31ba4c3e..1bd02d72 100644 --- a/tests/unit/out/refcount/nested_structs.rs +++ b/tests/unit/out/refcount/nested_structs.rs @@ -144,15 +144,8 @@ impl ByteRepr for Level0_Level1_2 { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Level0 {} -impl Clone for Level0 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Level0 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_member_pointer_member.rs b/tests/unit/out/refcount/operator_member_pointer_member.rs index ef79b5c5..90e82e56 100644 --- a/tests/unit/out/refcount/operator_member_pointer_member.rs +++ b/tests/unit/out/refcount/operator_member_pointer_member.rs @@ -32,7 +32,7 @@ impl ByteRepr for Inner { } } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Table {} impl Table { pub fn operator_index(i: i32) -> Ptr { @@ -40,13 +40,6 @@ impl Table { return (table_0.with(|v| v.as_pointer()) as Ptr).offset((*i.borrow())); } } -impl Clone for Table { - fn clone(&self) -> Self { - let __this: Value
= Rc::new(RefCell::new(Self {})); - let this: Ptr
= __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Table { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/operator_other_member.rs b/tests/unit/out/refcount/operator_other_member.rs index fbd3e5c2..930b78f6 100644 --- a/tests/unit/out/refcount/operator_other_member.rs +++ b/tests/unit/out/refcount/operator_other_member.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct Static {} impl Static { pub fn operator_call(a: i32, b: i32) -> i32 { @@ -15,13 +15,6 @@ impl Static { return ((*a.borrow()) * (*b.borrow())); } } -impl Clone for Static { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Static { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/polymorphism.rs b/tests/unit/out/refcount/polymorphism.rs index ecceb075..8a78db66 100644 --- a/tests/unit/out/refcount/polymorphism.rs +++ b/tests/unit/out/refcount/polymorphism.rs @@ -9,20 +9,13 @@ use std::rc::{Rc, Weak}; pub trait Animal { fn bark(&self) -> bool; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Dog {} impl Animal for Dog { fn bark(&self) -> bool { return true; } } -impl Clone for Dog { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Dog { fn byte_size() -> usize { 8 @@ -32,20 +25,13 @@ impl ByteRepr for Dog { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct Cat {} impl Animal for Cat { fn bark(&self) -> bool { return false; } } -impl Clone for Cat { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for Cat { fn byte_size() -> usize { 8 diff --git a/tests/unit/out/refcount/random.rs b/tests/unit/out/refcount/random.rs index e81f828c..ba8f0cdf 100644 --- a/tests/unit/out/refcount/random.rs +++ b/tests/unit/out/refcount/random.rs @@ -58,15 +58,8 @@ impl ByteRepr for Pair {} pub fn zero_0() -> i32 { return 0; } -#[derive(Default)] +#[derive(Clone, Default)] pub struct X1 {} -impl Clone for X1 { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for X1 { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/stable_sort.rs b/tests/unit/out/refcount/stable_sort.rs index 5ed2d31d..dc26d917 100644 --- a/tests/unit/out/refcount/stable_sort.rs +++ b/tests/unit/out/refcount/stable_sort.rs @@ -13,14 +13,8 @@ pub fn main() { fn main_0() -> i32 { let arr1: Value> = Rc::new(RefCell::new(Box::new([5, 2, 8, 1, 3]))); { - let fun = |x: Ptr, y: Ptr| { - (|x: i32, y: i32| { - let x: Value = Rc::new(RefCell::new(x)); - let y: Value = Rc::new(RefCell::new(y)); - return ((*x.borrow()) < (*y.borrow())); - }) - .call((x.read()).clone(), (y.read()).clone()) - }; + let fun = + |x: Ptr, y: Ptr| (lambda_0 {}).call((x.read()).clone(), (y.read()).clone()); (arr1.as_pointer() as Ptr).sort_with_cmp( (arr1.as_pointer() as Ptr) .offset((5) as isize) @@ -30,4 +24,32 @@ fn main_0() -> i32 { }; return 0; } +#[derive(Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub fn operator_call(x: i32, y: i32) -> bool { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + return ((*x.borrow()) < (*y.borrow())); + } +} +impl ByteRepr for lambda_0 { + fn byte_size() -> usize { + 1 + } + fn to_bytes(&self, buf: &mut [u8]) {} + fn from_bytes(buf: &[u8]) -> Self { + Self {} + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> FnPtr bool> { + FnPtr::new(lambda_0::operator_call) + } +} pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/refcount/static_var_in_class.rs b/tests/unit/out/refcount/static_var_in_class.rs index 25170f91..0996ec9f 100644 --- a/tests/unit/out/refcount/static_var_in_class.rs +++ b/tests/unit/out/refcount/static_var_in_class.rs @@ -9,15 +9,8 @@ use std::rc::{Rc, Weak}; thread_local!( static inner_const_0: Value = Rc::new(RefCell::new(1)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct C {} -impl Clone for C { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for C { fn byte_size() -> usize { 1 @@ -30,15 +23,8 @@ impl ByteRepr for C { thread_local!( pub static inner_const_1: Value = Rc::new(RefCell::new(2)); ); -#[derive(Default)] +#[derive(Clone, Default)] pub struct S {} -impl Clone for S { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for S { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/refcount/vector_with_allocator.rs b/tests/unit/out/refcount/vector_with_allocator.rs index 9787e6ea..401a0f8c 100644 --- a/tests/unit/out/refcount/vector_with_allocator.rs +++ b/tests/unit/out/refcount/vector_with_allocator.rs @@ -6,15 +6,8 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_int_ {} -impl Clone for TestAllocator_int_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_int_ { fn byte_size() -> usize { 1 @@ -24,15 +17,8 @@ impl ByteRepr for TestAllocator_int_ { Self {} } } -#[derive(Default)] +#[derive(Clone, Default)] pub struct TestAllocator_double_ {} -impl Clone for TestAllocator_double_ { - fn clone(&self) -> Self { - let __this: Value = Rc::new(RefCell::new(Self {})); - let this: Ptr = __this.as_pointer(); - Rc::try_unwrap(__this).ok().unwrap().into_inner() - } -} impl ByteRepr for TestAllocator_double_ { fn byte_size() -> usize { 1 diff --git a/tests/unit/out/unsafe/fn_ptr_default_arg.rs b/tests/unit/out/unsafe/fn_ptr_default_arg.rs index dfd44d75..00a52db9 100644 --- a/tests/unit/out/unsafe/fn_ptr_default_arg.rs +++ b/tests/unit/out/unsafe/fn_ptr_default_arg.rs @@ -26,10 +26,26 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { apply_1(5, None,) }) == (5))); assert!(((unsafe { apply_1(5, Some(None),) }) == (5))); assert!(((unsafe { apply_1(5, Some(Some(identity_0)),) }) == (5))); - let mut negate: Option i32> = Some(|x: i32| { - return -x; - }); + let mut negate: Option i32> = (unsafe { (lambda_2 {}).to_free_function() }); assert!(((unsafe { apply_1(5, Some(negate),) }) == (-5_i32))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 {} +impl lambda_2 { + pub unsafe fn operator_call(mut x: i32) -> i32 { + return -x; + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(a1) } + } +} +impl lambda_2 { + pub fn to_free_function(&self) -> Option i32> { + Some(lambda_2::operator_call) + } +} pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_as_template_argument.rs b/tests/unit/out/unsafe/lambda_as_template_argument.rs index 64723d95..a0af4388 100644 --- a/tests/unit/out/unsafe/lambda_as_template_argument.rs +++ b/tests/unit/out/unsafe/lambda_as_template_argument.rs @@ -23,6 +23,7 @@ pub unsafe fn apply_twice_6(mut fn_: lambda_3, mut x: i32) -> i32 { } pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -87,3 +88,4 @@ impl lambda_5 { Some(lambda_5::operator_call) } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_basic.rs b/tests/unit/out/unsafe/lambda_basic.rs index 58dcd490..49bc4ba6 100644 --- a/tests/unit/out/unsafe/lambda_basic.rs +++ b/tests/unit/out/unsafe/lambda_basic.rs @@ -8,6 +8,7 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -121,3 +122,4 @@ impl Callable0 for lambda_4 { unsafe { lambda_4::operator_call(self) } } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_implicit.rs b/tests/unit/out/unsafe/lambda_capture_implicit.rs index 44d507fe..a7e2a5f0 100644 --- a/tests/unit/out/unsafe/lambda_capture_implicit.rs +++ b/tests/unit/out/unsafe/lambda_capture_implicit.rs @@ -8,6 +8,7 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -88,3 +89,4 @@ impl Callable1 for lambda_2 { unsafe { lambda_2::operator_call(self, a1) } } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_ref.rs b/tests/unit/out/unsafe/lambda_capture_ref.rs index b66d9e18..a89edd89 100644 --- a/tests/unit/out/unsafe/lambda_capture_ref.rs +++ b/tests/unit/out/unsafe/lambda_capture_ref.rs @@ -14,6 +14,7 @@ pub struct S { } pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -104,3 +105,4 @@ impl Callable2 for lambda_3 { unsafe { lambda_3::operator_call(self, a1, a2) } } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_this.rs b/tests/unit/out/unsafe/lambda_capture_this.rs index 69d9e7a9..17e8ee87 100644 --- a/tests/unit/out/unsafe/lambda_capture_this.rs +++ b/tests/unit/out/unsafe/lambda_capture_this.rs @@ -86,6 +86,7 @@ impl Callable0 for lambda_2 { } pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -98,3 +99,4 @@ unsafe fn main_0() -> i32 { assert!(((unsafe { S::read_scaled(&s,) }) == (20))); return 0; } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_capture_value.rs b/tests/unit/out/unsafe/lambda_capture_value.rs index 449c4bba..5415ae3d 100644 --- a/tests/unit/out/unsafe/lambda_capture_value.rs +++ b/tests/unit/out/unsafe/lambda_capture_value.rs @@ -14,6 +14,7 @@ pub struct S { } pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -97,3 +98,4 @@ impl Callable1 for lambda_3 { unsafe { lambda_3::operator_call(self, a1) } } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_mutable.rs b/tests/unit/out/unsafe/lambda_mutable.rs index 8bd65bf9..ac77f664 100644 --- a/tests/unit/out/unsafe/lambda_mutable.rs +++ b/tests/unit/out/unsafe/lambda_mutable.rs @@ -8,6 +8,7 @@ use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -46,3 +47,4 @@ impl lambda_1 { return self.total; } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_nested.rs b/tests/unit/out/unsafe/lambda_nested.rs index d36a62c9..a5e43f6e 100644 --- a/tests/unit/out/unsafe/lambda_nested.rs +++ b/tests/unit/out/unsafe/lambda_nested.rs @@ -6,6 +6,54 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct S { + pub v: i32, +} +impl S { + pub unsafe fn nested_this(&mut self) -> i32 { + let mut outer: lambda_0 = (lambda_0 { + this_: (self as *mut S), + }); + return (unsafe { lambda_0::operator_call(&outer, 20) }); + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_1 { + this_: *mut S, + y: i32, +} +impl lambda_1 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return ((((*self.this_).v) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_1 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_1::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 { + this_: *mut S, +} +impl lambda_0 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_1 = (lambda_1 { + this_: self.this_, + y: y, + }); + return (unsafe { lambda_1::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_0 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_0::operator_call(self, a1) } + } +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -14,29 +62,44 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 10; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (31)) - ); + let mut outer: lambda_2 = (lambda_2 { x: &mut x }); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (31))); x = 100; - assert!( - ((unsafe { - (|y: i32| { - return (unsafe { - (|z: i32| { - return (((x) + (y)) + (z)); - })(1) - }); - })(20) - }) == (121)) - ); + assert!(((unsafe { lambda_2::operator_call(&outer, 20,) }) == (121))); + let mut s: S = S { v: 5 }; + assert!(((unsafe { S::nested_this(&mut s,) }) == (26))); return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_3 { + x: *mut i32, + y: i32, +} +impl lambda_3 { + pub unsafe fn operator_call(&self, mut z: i32) -> i32 { + return (((*self.x) + (self.y)) + (z)); + } +} +impl Callable1 for lambda_3 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_3::operator_call(self, a1) } + } +} +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_2 { + x: *mut i32, +} +impl lambda_2 { + pub unsafe fn operator_call(&self, mut y: i32) -> i32 { + let mut inner: lambda_3 = (lambda_3 { x: self.x, y: y }); + return (unsafe { lambda_3::operator_call(&inner, 1) }); + } +} +impl Callable1 for lambda_2 { + fn call(&self, a1: i32) -> i32 { + unsafe { lambda_2::operator_call(self, a1) } + } +} pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs index 26d137d3..7aa53ad9 100644 --- a/tests/unit/out/unsafe/lambda_to_fn_ptr.rs +++ b/tests/unit/out/unsafe/lambda_to_fn_ptr.rs @@ -11,6 +11,7 @@ pub unsafe fn apply_0(mut x: i32, mut fn_: Option i32>) -> i32 } pub fn main() { unsafe { + __cpp2rust_init_globals(); std::process::exit(main_0() as i32); } } @@ -61,3 +62,4 @@ impl lambda_2 { Some(lambda_2::operator_call) } } +pub unsafe fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/stable_sort.rs b/tests/unit/out/unsafe/stable_sort.rs index d21a3882..b4db8883 100644 --- a/tests/unit/out/unsafe/stable_sort.rs +++ b/tests/unit/out/unsafe/stable_sort.rs @@ -20,17 +20,9 @@ unsafe fn main_0() -> i32 { .offset((5) as isize) .offset_from(arr1.as_mut_ptr()) as usize; ::std::slice::from_raw_parts_mut(arr1.as_mut_ptr(), len).sort_by(|x, y| { - if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*x, *y) - { + if (lambda_0 {}).call(*x, *y) { std::cmp::Ordering::Less - } else if (|x: i32, y: i32| { - return ((x) < (y)); - }) - .call(*y, *x) - { + } else if (lambda_0 {}).call(*y, *x) { std::cmp::Ordering::Greater } else { std::cmp::Ordering::Equal @@ -39,4 +31,22 @@ unsafe fn main_0() -> i32 { }; return 0; } +#[repr(C)] +#[derive(Copy, Clone, Default)] +pub struct lambda_0 {} +impl lambda_0 { + pub unsafe fn operator_call(mut x: i32, mut y: i32) -> bool { + return ((x) < (y)); + } +} +impl Callable2 for lambda_0 { + fn call(&self, a1: i32, a2: i32) -> bool { + unsafe { lambda_0::operator_call(a1, a2) } + } +} +impl lambda_0 { + pub fn to_free_function(&self) -> Option bool> { + Some(lambda_0::operator_call) + } +} pub unsafe fn __cpp2rust_init_globals() {}