Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4016,10 +4016,12 @@ void Converter::ConvertLambdaCapture(const clang::FieldDecl *field,
void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
clang::CXXMethodDecl *call_operator) {
StrCat('|');
in_function_formals_ = true;
for (auto p : call_operator->parameters()) {
StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()),
token::kComma);
ConvertVarDeclSkipInit(p);
StrCat(token::kComma);
}
in_function_formals_ = false;
StrCat('|');
ConvertFunctionReturnType(call_operator);
PushBrace body(*this);
Expand All @@ -4030,6 +4032,7 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
}
EmitFunctionPreamble(call_operator);
PushCurrFunction push_fn(*this, call_operator);
PushConstInitializer function_body(*this, false);
ConvertFunctionBody(curr_function_);
}

Expand Down
13 changes: 3 additions & 10 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -854,18 +854,11 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
struct PushConstInitializer {
Converter &c;
bool prev;
bool enabled;
PushConstInitializer(Converter &c, bool enabled)
: c(c), prev(c.in_const_initializer_), enabled(enabled) {
if (enabled) {
c.in_const_initializer_ = true;
}
}
~PushConstInitializer() {
if (enabled) {
c.in_const_initializer_ = prev;
}
: c(c), prev(c.in_const_initializer_) {
c.in_const_initializer_ = enabled;
}
~PushConstInitializer() { c.in_const_initializer_ = prev; }
};
std::vector<clang::Expr *> curr_for_inc_;
std::vector<clang::QualType> curr_init_type_;
Expand Down
5 changes: 2 additions & 3 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1252,8 +1252,7 @@ const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field) {

bool IsLambdaCopyOrMoveConstructor(const clang::CXXConstructorDecl *ctor) {
auto decl = ctor->getParent();
return ctor->isCopyOrMoveConstructor() && decl->isLambda() &&
!decl->captures().empty();
return ctor->isCopyOrMoveConstructor() && decl->isLambda();
}

bool LambdaNeedsDestruction(const clang::CXXRecordDecl *decl) {
Expand Down Expand Up @@ -1335,7 +1334,7 @@ bool HasStaticLocal(const clang::Stmt *stmt) {

bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
const auto *callee = expr->getDirectCallee();
if (!callee) {
if (!callee || AsLambdaOperatorCall(callee)) {
return false;
}
if (callee->isDefaulted() && IsComparisonOperator(callee)) {
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,8 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) {
if (auto *opcall = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr);
opcall && !IsUserOperatorCall(opcall) &&
!Mapper::Contains(ctx_, expr->getCallee())) {
PushConversionKind push(*this, ConversionKind::Unboxed,
opcall->getOperator() == clang::OO_Call);
return ConvertCXXOperatorCallExpr(opcall);
}

Expand Down
12 changes: 11 additions & 1 deletion libcc2rs-macros/src/lambda.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ impl Parse for Lambda {
input.parse::<Token![,]>()?;
}
let captures = input.parse()?;
if is_generic && input.is_empty() {
return Ok(Lambda {
is_generic,
captures,
closures: Vec::new(),
});
}
input.parse::<Token![,]>()?;
let mut closures = vec![input.parse()?];
while input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
Expand Down Expand Up @@ -60,8 +67,11 @@ fn rewrite_nested_lambda(
tokens: proc_macro2::TokenStream,
names: &HashSet<String>,
) -> Result<proc_macro2::TokenStream> {
let mut tokens = tokens.into_iter();
let mut tokens = tokens.into_iter().peekable();
let mut out = Vec::new();
if is_ident(tokens.peek(), "Generic") {
out.extend(tokens.by_ref().take(2));
}
if let Some(TokenTree::Group(captures)) = tokens.next() {
let mut group = Group::new(
captures.delimiter(),
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/lambda_as_field.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
// no-compile
#include <assert.h>
#include <utility>

template <typename F> struct Guard {
F f;
Expand All @@ -16,6 +17,13 @@ template <typename F> struct Holder {
}
};

template <typename F> struct Moving {
F f;
int moves = 0;
Moving(F f) : f(f) {}
Moving(Moving &&o) : f(std::move(o.f)), moves(o.moves + 1) {}
};

template <typename T> auto wrap(T fn) {
return [fn](int x) { return fn(x) + 1; };
}
Expand Down Expand Up @@ -54,5 +62,10 @@ int main() {
auto ww = wrap(w);
assert(ww(2) == 202);

Moving m{[](int x) { return x * 2; }};
Moving m2(std::move(m));
assert(m2.f(3) == 6);
assert(m2.moves == 1);

return 0;
}
9 changes: 9 additions & 0 deletions tests/unit/lambda_as_template_argument.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ template <typename F> double apply_double(F fn, double x) { return fn(x); }

template <typename F> int apply_twice(F fn, int x) { return fn(fn(x)); }

template <typename Pred> bool none_match(Pred pred, int a, int b) {
auto neg_pred = [&](int x) { return !pred(x); };
return neg_pred(a) && neg_pred(b);
}

int main() {
int factor = 3;
auto scale = [factor](int x) { return x * factor; };
Expand All @@ -24,5 +29,9 @@ int main() {
assert(apply_int(offset, 4) == 7);
assert(apply_double(offset, 1.5) == 4.5);

auto is_even = [](int x) { return x % 2 == 0; };
assert(none_match(is_even, 1, 3));
assert(!none_match(is_even, 1, 4));

return 0;
}
19 changes: 19 additions & 0 deletions tests/unit/lambda_basic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,24 @@ int main() {
auto implicit = [=](int x) { return x + k; };
assert(implicit(1) == 4);

auto bump = [](int x) {
x += 1;
return x;
};
assert(bump(1) == 2);

auto through_ptr = [](int x) {
int *p = &x;
*p = *p * 2;
return x;
};
assert(through_ptr(4) == 8);

int seed = 5;
int boxed = through_ptr(seed);
int *boxed_ptr = &boxed;
assert(*boxed_ptr == 10);
assert(seed == 5);

return 0;
}
9 changes: 9 additions & 0 deletions tests/unit/lambda_generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,14 @@ int main() {
assert(mixed(2, 3) == 16);
assert(mixed(2, 0.5) == 11.0);

auto unused = [](auto x) { return x; };
(void)unused;

auto outer = [base](int y) {
auto inner = [](auto z) { return z + 1; };
return inner(y) + base;
};
assert(outer(5) == 16);

return 0;
}
6 changes: 6 additions & 0 deletions tests/unit/lambda_namespace_scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ auto bump = []() {

template <typename F> int apply(F f, int x) { return f(x); }

int by_ref(const int &v) { return v * 2; }

auto twice_next = [](int x) { return by_ref(x + 1); };

int main() {
assert(inc(41) == 42);

Expand All @@ -25,5 +29,7 @@ int main() {
int (*fp)(int) = inc;
assert(fp(-1) == 0);

assert(twice_next(4) == 10);

return 0;
}
2 changes: 1 addition & 1 deletion tests/unit/out/refcount/fn_ptr_default_arg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ fn main_0() -> i32 {
assert!((({ apply_1(5, None,) }) == 5));
assert!((({ apply_1(5, Some(FnPtr::<fn(i32) -> i32>::null()),) }) == 5));
assert!((({ apply_1(5, Some(FnPtr::<fn(i32) -> i32>::new(identity_0)),) }) == 5));
let mut negate: FnPtr<fn(i32) -> i32> = FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
let mut negate: FnPtr<fn(i32) -> i32> = FnPtr::<fn(i32) -> i32>::new(|mut x: i32| -> i32 {
{
return -x;
}
Expand Down
35 changes: 28 additions & 7 deletions tests/unit/out/refcount/lambda_as_template_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,18 @@ pub fn apply_twice_6(fn_: FnPtr<fn(i32) -> i32>, mut x: i32) -> i32 {
})
.clone();
}
pub fn none_match_7(pred: FnPtr<fn(i32) -> bool>, mut a: i32, mut b: i32) -> bool {
let pred: Value<FnPtr<fn(i32) -> bool>> = Rc::new(RefCell::new(pred));
let neg_pred: Value<FnPtr<fn(i32) -> bool>> = Rc::new(RefCell::new(lambda!(
{
let pred: Ptr<FnPtr<fn(i32) -> bool>> = pred.as_pointer();
},
|mut x: i32| -> bool {
return !({ (*pred.upgrade().deref()).call(x) });
}
)));
return ({ (*neg_pred.borrow()).call(a) }) && ({ (*neg_pred.borrow()).call(b) });
}
pub fn main() {
__cpp2rust_init_globals();
std::process::exit(main_0());
Expand All @@ -48,15 +60,15 @@ fn main_0() -> i32 {
{
let factor: Value<i32> = Rc::new(RefCell::new((*factor.borrow())));
},
|x: i32| -> i32 {
|mut x: i32| -> i32 {
return (x * (*factor.borrow()));
}
)));
assert!((({ apply_twice_6((*scale.borrow()).copy_from(), 4,) }) == 36));
assert!(
(({
apply_int_0(
FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
FnPtr::<fn(i32) -> i32>::new(|mut x: i32| -> i32 {
{
return -x;
}
Expand All @@ -70,10 +82,10 @@ fn main_0() -> i32 {
{
let factor: Value<i32> = Rc::new(RefCell::new((*factor.borrow())));
},
|x: i32| -> i32 {
|mut x: i32| -> i32 {
return (x * (*factor.borrow()));
},
|x: f64| -> f64 {
|mut x: f64| -> f64 {
return (x * ((*factor.borrow()) as f64));
}
)));
Expand All @@ -82,7 +94,7 @@ fn main_0() -> i32 {
assert!(
(({
apply_int_2(
lambda!(Generic, {}, |x: i32| -> i32 {
lambda!(Generic, {}, |mut x: i32| -> i32 {
return -x;
}),
9,
Expand All @@ -94,15 +106,24 @@ fn main_0() -> i32 {
{
let factor: Value<i32> = Rc::new(RefCell::new((*factor.borrow())));
},
|x: i32| -> i32 {
|mut x: i32| -> i32 {
return (x + (*factor.borrow()));
},
|x: f64| -> f64 {
|mut x: f64| -> f64 {
return (x + ((*factor.borrow()) as f64));
}
)));
assert!((({ apply_int_3((*offset.borrow()).copy_from(), 4,) }) == 7));
assert!((({ apply_double_5((*offset.borrow()).copy_from(), 1.5_f64,) }) == 4.5_f64));
let is_even: Value<FnPtr<fn(i32) -> bool>> = Rc::new(RefCell::new(
FnPtr::<fn(i32) -> bool>::new(|mut x: i32| -> bool {
{
return ((x % 2) == 0);
}
}),
));
assert!(({ none_match_7((*is_even.borrow()).copy_from(), 1, 3,) }));
assert!(!({ none_match_7((*is_even.borrow()).copy_from(), 1, 4,) }));
return 0;
}
pub fn __cpp2rust_init_globals() {}
35 changes: 30 additions & 5 deletions tests/unit/out/refcount/lambda_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ fn main_0() -> i32 {
})));
assert!((({ (*zero.borrow()).call() }) == 42));
let one: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::<fn(i32) -> i32>::new(
|x: i32| -> i32 {
|mut x: i32| -> i32 {
{
return (x + 1);
}
Expand All @@ -28,7 +28,7 @@ fn main_0() -> i32 {
assert!((({ (*one.borrow()).call(1,) }) == 2));
let three: Value<FnPtr<fn(i32, i32, i32) -> i32>> =
Rc::new(RefCell::new(FnPtr::<fn(i32, i32, i32) -> i32>::new(
|x: i32, y: i32, z: i32| -> i32 {
|mut x: i32, mut y: i32, mut z: i32| -> i32 {
{
return (((x * 100) + (y * 10)) + z);
}
Expand All @@ -38,7 +38,7 @@ fn main_0() -> i32 {
let mut k: i32 = 3;
let mut m: i32 = 4;
let constants: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(
FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
FnPtr::<fn(i32) -> i32>::new(|mut x: i32| -> i32 {
{
return ((x + 3) + 4);
}
Expand All @@ -47,21 +47,46 @@ fn main_0() -> i32 {
assert!((({ (*constants.borrow()).call(1,) }) == 8));
let mut n: i32 = (k + m);
let derived: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(
FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
FnPtr::<fn(i32) -> i32>::new(|mut x: i32| -> i32 {
{
return (x + (3 + 4));
}
}),
));
assert!((({ (*derived.borrow()).call(1,) }) == 8));
let implicit: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(
FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
FnPtr::<fn(i32) -> i32>::new(|mut x: i32| -> i32 {
{
return (x + 3);
}
}),
));
assert!((({ (*implicit.borrow()).call(1,) }) == 4));
let bump: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::<fn(i32) -> i32>::new(
|mut x: i32| -> i32 {
{
x += 1;
return x;
}
},
)));
assert!((({ (*bump.borrow()).call(1,) }) == 2));
let through_ptr: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(
FnPtr::<fn(i32) -> i32>::new(|x: i32| -> i32 {
{
let x: Value<i32> = Rc::new(RefCell::new(x));
let mut p: Ptr<i32> = (x.as_pointer());
p.write({ ((p.read()) * 2) });
return (*x.borrow());
}
}),
));
assert!((({ (*through_ptr.borrow()).call(4,) }) == 8));
let mut seed: i32 = 5;
let boxed: Value<i32> = Rc::new(RefCell::new(({ (*through_ptr.borrow()).call(seed) })));
let mut boxed_ptr: Ptr<i32> = (boxed.as_pointer());
assert!(((boxed_ptr.read()) == 10));
assert!((seed == 5));
return 0;
}
pub fn __cpp2rust_init_globals() {}
Loading
Loading