Skip to content

Commit 87c5fca

Browse files
authored
Fix lambda calls, parameters, captures and namespace-scope lambdas (#501)
In VisitCallExpr convert the arguments of the operator call in Unboxed context to avoid unnecessary Value boxes Use ConvertVarDeclSkipInit to convert the params of the operator call so that it can add mut where needed PushConstInitializer(false) before converting the body of lambda to fix translation of global lambdas Call the move constructor when the lambda is moved Fix generic lambdas with no specialisations in libcc2rs-macros Fix lambda in lambda syntax in libcc2rs-macros
1 parent cea543b commit 87c5fca

40 files changed

Lines changed: 364 additions & 148 deletions

‎cpp2rust/converter/converter.cpp‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4056,10 +4056,12 @@ void Converter::ConvertLambdaCapture(const clang::FieldDecl *field,
40564056
void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
40574057
clang::CXXMethodDecl *call_operator) {
40584058
StrCat('|');
4059+
in_function_formals_ = true;
40594060
for (auto p : call_operator->parameters()) {
4060-
StrCat(GetNamedDeclAsString(p), token::kColon, ToString(p->getType()),
4061-
token::kComma);
4061+
ConvertVarDeclSkipInit(p);
4062+
StrCat(token::kComma);
40624063
}
4064+
in_function_formals_ = false;
40634065
StrCat('|');
40644066
ConvertFunctionReturnType(call_operator);
40654067
PushBrace body(*this);
@@ -4070,6 +4072,7 @@ void Converter::ConvertLambdaClosure(const clang::CXXRecordDecl *decl,
40704072
}
40714073
EmitFunctionPreamble(call_operator);
40724074
PushCurrFunction push_fn(*this, call_operator);
4075+
PushConstInitializer function_body(*this, false);
40734076
ConvertFunctionBody(curr_function_);
40744077
}
40754078

‎cpp2rust/converter/converter.h‎

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -856,18 +856,11 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
856856
struct PushConstInitializer {
857857
Converter &c;
858858
bool prev;
859-
bool enabled;
860859
PushConstInitializer(Converter &c, bool enabled)
861-
: c(c), prev(c.in_const_initializer_), enabled(enabled) {
862-
if (enabled) {
863-
c.in_const_initializer_ = true;
864-
}
865-
}
866-
~PushConstInitializer() {
867-
if (enabled) {
868-
c.in_const_initializer_ = prev;
869-
}
860+
: c(c), prev(c.in_const_initializer_) {
861+
c.in_const_initializer_ = enabled;
870862
}
863+
~PushConstInitializer() { c.in_const_initializer_ = prev; }
871864
};
872865
std::vector<clang::Expr *> curr_for_inc_;
873866
std::vector<clang::QualType> curr_init_type_;

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,8 +1257,7 @@ const clang::LambdaCapture *AsLambdaCapture(const clang::FieldDecl *field) {
12571257

12581258
bool IsLambdaCopyOrMoveConstructor(const clang::CXXConstructorDecl *ctor) {
12591259
auto decl = ctor->getParent();
1260-
return ctor->isCopyOrMoveConstructor() && decl->isLambda() &&
1261-
!decl->captures().empty();
1260+
return ctor->isCopyOrMoveConstructor() && decl->isLambda();
12621261
}
12631262

12641263
bool LambdaNeedsDestruction(const clang::CXXRecordDecl *decl) {
@@ -1340,7 +1339,7 @@ bool HasStaticLocal(const clang::Stmt *stmt) {
13401339

13411340
bool IsUserOperatorCall(const clang::CXXOperatorCallExpr *expr) {
13421341
const auto *callee = expr->getDirectCallee();
1343-
if (!callee) {
1342+
if (!callee || AsLambdaOperatorCall(callee)) {
13441343
return false;
13451344
}
13461345
if (callee->isDefaulted() && IsComparisonOperator(callee)) {

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,6 +1332,8 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) {
13321332
if (auto *opcall = clang::dyn_cast<clang::CXXOperatorCallExpr>(expr);
13331333
opcall && !IsUserOperatorCall(opcall) &&
13341334
!Mapper::Contains(ctx_, expr->getCallee())) {
1335+
PushConversionKind push(*this, ConversionKind::Unboxed,
1336+
opcall->getOperator() == clang::OO_Call);
13351337
return ConvertCXXOperatorCallExpr(opcall);
13361338
}
13371339

‎libcc2rs-macros/src/lambda.rs‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ impl Parse for Lambda {
2525
input.parse::<Token![,]>()?;
2626
}
2727
let captures = input.parse()?;
28+
if is_generic && input.is_empty() {
29+
return Ok(Lambda {
30+
is_generic,
31+
captures,
32+
closures: Vec::new(),
33+
});
34+
}
2835
input.parse::<Token![,]>()?;
2936
let mut closures = vec![input.parse()?];
3037
while input.parse::<Option<Token![,]>>()?.is_some() && !input.is_empty() {
@@ -60,8 +67,11 @@ fn rewrite_nested_lambda(
6067
tokens: proc_macro2::TokenStream,
6168
names: &HashSet<String>,
6269
) -> Result<proc_macro2::TokenStream> {
63-
let mut tokens = tokens.into_iter();
70+
let mut tokens = tokens.into_iter().peekable();
6471
let mut out = Vec::new();
72+
if is_ident(tokens.peek(), "Generic") {
73+
out.extend(tokens.by_ref().take(2));
74+
}
6575
if let Some(TokenTree::Group(captures)) = tokens.next() {
6676
let mut group = Group::new(
6777
captures.delimiter(),

‎tests/unit/lambda_as_field.cpp‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ADDITIONAL_COMPILE_FLAGS: -std=c++23
22
// no-compile
33
#include <assert.h>
4+
#include <utility>
45

56
template <typename F> struct Guard {
67
F f;
@@ -16,6 +17,13 @@ template <typename F> struct Holder {
1617
}
1718
};
1819

20+
template <typename F> struct Moving {
21+
F f;
22+
int moves = 0;
23+
Moving(F f) : f(f) {}
24+
Moving(Moving &&o) : f(std::move(o.f)), moves(o.moves + 1) {}
25+
};
26+
1927
template <typename T> auto wrap(T fn) {
2028
return [fn](int x) { return fn(x) + 1; };
2129
}
@@ -54,5 +62,10 @@ int main() {
5462
auto ww = wrap(w);
5563
assert(ww(2) == 202);
5664

65+
Moving m{[](int x) { return x * 2; }};
66+
Moving m2(std::move(m));
67+
assert(m2.f(3) == 6);
68+
assert(m2.moves == 1);
69+
5770
return 0;
5871
}

‎tests/unit/lambda_as_template_argument.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ template <typename F> double apply_double(F fn, double x) { return fn(x); }
77

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

10+
template <typename Pred> bool none_match(Pred pred, int a, int b) {
11+
auto neg_pred = [&](int x) { return !pred(x); };
12+
return neg_pred(a) && neg_pred(b);
13+
}
14+
1015
int main() {
1116
int factor = 3;
1217
auto scale = [factor](int x) { return x * factor; };
@@ -24,5 +29,9 @@ int main() {
2429
assert(apply_int(offset, 4) == 7);
2530
assert(apply_double(offset, 1.5) == 4.5);
2631

32+
auto is_even = [](int x) { return x % 2 == 0; };
33+
assert(none_match(is_even, 1, 3));
34+
assert(!none_match(is_even, 1, 4));
35+
2736
return 0;
2837
}

‎tests/unit/lambda_basic.cpp‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,24 @@ int main() {
2222
auto implicit = [=](int x) { return x + k; };
2323
assert(implicit(1) == 4);
2424

25+
auto bump = [](int x) {
26+
x += 1;
27+
return x;
28+
};
29+
assert(bump(1) == 2);
30+
31+
auto through_ptr = [](int x) {
32+
int *p = &x;
33+
*p = *p * 2;
34+
return x;
35+
};
36+
assert(through_ptr(4) == 8);
37+
38+
int seed = 5;
39+
int boxed = through_ptr(seed);
40+
int *boxed_ptr = &boxed;
41+
assert(*boxed_ptr == 10);
42+
assert(seed == 5);
43+
2544
return 0;
2645
}

‎tests/unit/lambda_generic.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,14 @@ int main() {
2727
assert(mixed(2, 3) == 16);
2828
assert(mixed(2, 0.5) == 11.0);
2929

30+
auto unused = [](auto x) { return x; };
31+
(void)unused;
32+
33+
auto outer = [base](int y) {
34+
auto inner = [](auto z) { return z + 1; };
35+
return inner(y) + base;
36+
};
37+
assert(outer(5) == 16);
38+
3039
return 0;
3140
}

‎tests/unit/lambda_namespace_scope.cpp‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ auto bump = []() {
1010

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

13+
int by_ref(const int &v) { return v * 2; }
14+
15+
auto twice_next = [](int x) { return by_ref(x + 1); };
16+
1317
int main() {
1418
assert(inc(41) == 42);
1519

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

32+
assert(twice_next(4) == 10);
33+
2834
return 0;
2935
}

0 commit comments

Comments
 (0)