From 3756b5dc5edeb5df95f1e59bfc19ac22bd6eb76b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Fri, 9 Oct 2026 10:04:54 +0100 Subject: [PATCH] Fix lambdas that receive pack captures --- cpp2rust/converter/converter_lib.cpp | 16 +++ tests/unit/lambda_pack_capture.cpp | 1 - .../unit/out/refcount/lambda_pack_capture.rs | 122 ++++++++++++++++++ tests/unit/out/unsafe/lambda_pack_capture.rs | 111 ++++++++++++++++ 4 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 tests/unit/out/refcount/lambda_pack_capture.rs create mode 100644 tests/unit/out/unsafe/lambda_pack_capture.rs diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index f33d1a809..357c7ce22 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -1005,6 +1005,22 @@ std::string GetNamedDeclAsString(const clang::NamedDecl *decl) { name += '_'; name += std::to_string(pdecl->getFunctionScopeIndex()); } + } else if (auto *var = llvm::dyn_cast(decl); + var && var->isInitCapture()) { + auto lambda = + llvm::cast(var->getDeclContext())->getParent(); + if (llvm::count_if(lambda->captures(), [&](const clang::LambdaCapture &c) { + return c.capturesVariable() && + c.getCapturedVar()->getName() == var->getName(); + }) > 1) { + auto captures = lambda->captures(); + auto it = llvm::find_if(captures, [&](const clang::LambdaCapture &c) { + return c.capturesVariable() && c.getCapturedVar() == var; + }); + assert(it != captures.end()); + name += '_'; + name += std::to_string(it - captures.begin()); + } } return name; diff --git a/tests/unit/lambda_pack_capture.cpp b/tests/unit/lambda_pack_capture.cpp index 80581282e..f46fc0c67 100644 --- a/tests/unit/lambda_pack_capture.cpp +++ b/tests/unit/lambda_pack_capture.cpp @@ -1,5 +1,4 @@ // ADDITIONAL_COMPILE_FLAGS: -std=c++23 -// no-compile #include int sum() { return 0; } diff --git a/tests/unit/out/refcount/lambda_pack_capture.rs b/tests/unit/out/refcount/lambda_pack_capture.rs new file mode 100644 index 000000000..bf7a3343d --- /dev/null +++ b/tests/unit/out/refcount/lambda_pack_capture.rs @@ -0,0 +1,122 @@ +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 sum_0() -> i32 { + return 0; +} +pub fn sum_1(mut t: i32, mut u_1: i32, mut u_2: i32) -> i32 { + return (t + ({ sum_2(u_1, u_2) })); +} +pub fn sum_2(mut t: i32, mut u: i32) -> i32 { + return (t + ({ sum_3(u) })); +} +pub fn sum_3(mut t: i32) -> i32 { + return (t + ({ sum_0() })); +} +pub fn by_value_4() -> i32 { + let f: Value i32>> = + Rc::new(RefCell::new(FnPtr:: i32>::new(|| -> i32 { + { + return ({ sum_0() }); + } + }))); + (); + return ({ (*f.borrow()).call() }).clone(); +} +pub fn by_value_5(t_0: i32, t_1: i32, t_2: i32) -> i32 { + let t_0: Value = Rc::new(RefCell::new(t_0)); + let t_1: Value = Rc::new(RefCell::new(t_1)); + let t_2: Value = Rc::new(RefCell::new(t_2)); + let f: Value i32>> = Rc::new(RefCell::new(lambda!( + { + let t_0: Value = Rc::new(RefCell::new((*t_0.borrow()))); + let t_1: Value = Rc::new(RefCell::new((*t_1.borrow()))); + let t_2: Value = Rc::new(RefCell::new((*t_2.borrow()))); + }, + || -> i32 { + return ({ sum_1((*t_0.borrow()), (*t_1.borrow()), (*t_2.borrow())) }); + } + ))); + { + (*t_0.borrow_mut()) = 0; + { + (*t_1.borrow_mut()) = 0; + (*t_2.borrow_mut()) = 0 + } + }; + return ({ (*f.borrow()).call() }).clone(); +} +pub fn by_ref_6(t_0: i32, t_1: i32, t_2: i32) -> i32 { + let t_0: Value = Rc::new(RefCell::new(t_0)); + let t_1: Value = Rc::new(RefCell::new(t_1)); + let t_2: Value = Rc::new(RefCell::new(t_2)); + let f: Value> = Rc::new(RefCell::new(lambda!( + { + let t_0: Ptr = t_0.as_pointer(); + let t_1: Ptr = t_1.as_pointer(); + let t_2: Ptr = t_2.as_pointer(); + }, + || { + { + { + t_0.with_mut(|__v| *__v = *__v * 2) + }; + { + { + t_1.with_mut(|__v| *__v = *__v * 2) + }; + { t_2.with_mut(|__v| *__v = *__v * 2) } + } + }; + } + ))); + ({ (*f.borrow()).call() }); + return ({ sum_1((*t_0.borrow()), (*t_1.borrow()), (*t_2.borrow())) }); +} +pub fn init_pack_7(mut t_0: i32, mut t_1: i32, mut t_2: i32) -> i32 { + let f: Value i32>> = Rc::new(RefCell::new(lambda!( + { + let xs_0: Value = Rc::new(RefCell::new((t_0 + 1))); + let xs_1: Value = Rc::new(RefCell::new((t_1 + 1))); + let xs_2: Value = Rc::new(RefCell::new((t_2 + 1))); + }, + || -> i32 { + return ({ sum_1((*xs_0.borrow()), (*xs_1.borrow()), (*xs_2.borrow())) }); + } + ))); + return ({ (*f.borrow()).call() }).clone(); +} +pub fn implicit_8(t_0: i32, t_1: i32) -> i32 { + let t_0: Value = Rc::new(RefCell::new(t_0)); + let t_1: Value = Rc::new(RefCell::new(t_1)); + return ({ + lambda!( + { + let t_0: Value = Rc::new(RefCell::new((*t_0.borrow()))); + let t_1: Value = Rc::new(RefCell::new((*t_1.borrow()))); + }, + || -> i32 { + return ({ sum_2((*t_0.borrow()), (*t_1.borrow())) }); + } + ) + .call() + }); +} +pub fn main() { + __cpp2rust_init_globals(); + std::process::exit(main_0()); +} +fn main_0() -> i32 { + assert!((({ by_value_4() }) == 0)); + assert!((({ by_value_5(1, 2, 3,) }) == 6)); + assert!((({ by_ref_6(1, 2, 3,) }) == 12)); + assert!((({ init_pack_7(1, 2, 3,) }) == 9)); + assert!((({ implicit_8(4, 5,) }) == 9)); + return 0; +} +pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/lambda_pack_capture.rs b/tests/unit/out/unsafe/lambda_pack_capture.rs new file mode 100644 index 000000000..fbae3cba8 --- /dev/null +++ b/tests/unit/out/unsafe/lambda_pack_capture.rs @@ -0,0 +1,111 @@ +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 sum_0() -> i32 { + return 0; +} +pub unsafe fn sum_1(mut t: i32, mut u_1: i32, mut u_2: i32) -> i32 { + return ((t) + (unsafe { sum_2(u_1, u_2) })); +} +pub unsafe fn sum_2(mut t: i32, mut u: i32) -> i32 { + return ((t) + (unsafe { sum_3(u) })); +} +pub unsafe fn sum_3(mut t: i32) -> i32 { + return ((t) + (unsafe { sum_0() })); +} +pub unsafe fn by_value_4() -> i32 { + let mut f: FnPtr i32> = FnPtr:: i32>::new(|| -> i32 { + unsafe { + return (unsafe { sum_0() }); + } + }); + (); + return (unsafe { f.call() }); +} +pub unsafe fn by_value_5(mut t_0: i32, mut t_1: i32, mut t_2: i32) -> i32 { + let mut f: FnPtr i32> = lambda_unsafe!( + { + let t_0: i32 = t_0; + let t_1: i32 = t_1; + let t_2: i32 = t_2; + }, + || -> i32 { + return (unsafe { sum_1(t_0, t_1, t_2) }); + } + ); + { + t_0 = 0; + { + t_1 = 0; + t_2 = 0 + } + }; + return (unsafe { f.call() }); +} +pub unsafe fn by_ref_6(mut t_0: i32, mut t_1: i32, mut t_2: i32) -> i32 { + let mut f: FnPtr = lambda_unsafe!( + { + let t_0: *mut i32 = &mut t_0; + let t_1: *mut i32 = &mut t_1; + let t_2: *mut i32 = &mut t_2; + }, + || { + { + (*t_0) *= 2; + { + (*t_1) *= 2; + (*t_2) *= 2 + } + }; + } + ); + (unsafe { f.call() }); + return (unsafe { sum_1(t_0, t_1, t_2) }); +} +pub unsafe fn init_pack_7(mut t_0: i32, mut t_1: i32, mut t_2: i32) -> i32 { + let mut f: FnPtr i32> = lambda_unsafe!( + { + let xs_0: i32 = ((t_0) + (1)); + let xs_1: i32 = ((t_1) + (1)); + let xs_2: i32 = ((t_2) + (1)); + }, + || -> i32 { + return (unsafe { sum_1(xs_0, xs_1, xs_2) }); + } + ); + return (unsafe { f.call() }); +} +pub unsafe fn implicit_8(mut t_0: i32, mut t_1: i32) -> i32 { + return (unsafe { + lambda_unsafe!( + { + let t_0: i32 = t_0; + let t_1: i32 = t_1; + }, + || -> i32 { + return (unsafe { sum_2(t_0, t_1) }); + } + ) + .call() + }); +} +pub fn main() { + unsafe { + __cpp2rust_init_globals(); + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + assert!(((unsafe { by_value_4() }) == (0))); + assert!(((unsafe { by_value_5(1, 2, 3,) }) == (6))); + assert!(((unsafe { by_ref_6(1, 2, 3,) }) == (12))); + assert!(((unsafe { init_pack_7(1, 2, 3,) }) == (9))); + assert!(((unsafe { implicit_8(4, 5,) }) == (9))); + return 0; +} +pub unsafe fn __cpp2rust_init_globals() {}