Skip to content

Commit 4bd0c04

Browse files
committed
Emit anonymous functions as mutable lambdas
This example now works: main: () = { v: std::vector = ( 1, 2, 3, 4, 5 ); // Definite last use of v => move-capture v into f's closure f := :() -> forward _ = v$; // Now we can access the vector captured inside f()... f().push_back(6); for f() do(e) std::cout << e; // prints 123456 }
1 parent 0b333f3 commit 4bd0c04

17 files changed

+40
-34
lines changed

include/cpp2util.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,7 +1079,7 @@ auto is( X const& x ) -> bool {
10791079

10801080
// Values
10811081
//
1082-
inline constexpr auto is( auto const& x, auto const& value ) -> bool
1082+
inline constexpr auto is( auto const& x, auto&& value ) -> bool
10831083
{
10841084
// Value with customized operator_is case
10851085
if constexpr (requires{ x.op_is(value); }) {
@@ -1313,7 +1313,7 @@ auto is( std::variant<Ts...> const& x );
13131313
// is Value
13141314
//
13151315
template<typename... Ts>
1316-
constexpr auto is( std::variant<Ts...> const& x, auto const& value ) -> bool
1316+
constexpr auto is( std::variant<Ts...> const& x, auto&& value ) -> bool
13171317
{
13181318
// Predicate case
13191319
if constexpr (requires{ bool{ value(operator_as< 0>(x)) }; }) { if (x.index() == 0) return value(operator_as< 0>(x)); }
@@ -1494,7 +1494,7 @@ constexpr auto is( X const& x ) -> bool
14941494

14951495
// is Value
14961496
//
1497-
inline constexpr auto is( std::any const& x, auto const& value ) -> bool
1497+
inline constexpr auto is( std::any const& x, auto&& value ) -> bool
14981498
{
14991499
// Predicate case
15001500
if constexpr (requires{ bool{ value(x) }; }) {
@@ -1542,7 +1542,7 @@ constexpr auto is( std::optional<U> const& x ) -> bool
15421542
// is Value
15431543
//
15441544
template<typename T>
1545-
constexpr auto is( std::optional<T> const& x, auto const& value ) -> bool
1545+
constexpr auto is( std::optional<T> const& x, auto&& value ) -> bool
15461546
{
15471547
// Predicate case
15481548
if constexpr (requires{ bool{ value(x) }; }) {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
pure2-bugfix-for-non-local-function-expression.cpp2:5:34: error: lambda expression in an unevaluated operand
2-
template<typename T> concept v = []() -> bool { return true; }();
2+
template<typename T> concept v = []() mutable -> bool { return true; }();
33
^
44
pure2-bugfix-for-non-local-function-expression.cpp2:7:41: error: lambda expression in an unevaluated operand
5-
using u = std::type_identity_t<decltype([]() -> void{})>;
5+
using u = std::type_identity_t<decltype([]() mutable -> void{})>;
66
^
77
pure2-bugfix-for-non-local-function-expression.cpp2:9:47: error: lambda expression in an unevaluated operand
8-
class t: public std::type_identity_t<decltype([]() -> void{})> {
8+
class t: public std::type_identity_t<decltype([]() mutable -> void{})> {
99
^
1010
3 errors generated.

regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ auto insert_at(cpp2::in<int> where, cpp2::in<int> val) -> void;
3333
"hello", "2022"};
3434

3535
std::string y {"\n"};
36-
auto callback {[_0 = (&y)](auto const& x) -> void { std::cout << x << *cpp2::assert_not_null(_0); }};
36+
auto callback {[_0 = (&y)](auto const& x) mutable -> void { std::cout << x << *cpp2::assert_not_null(_0); }};
3737

3838
std::ranges::for_each(vec, callback);
3939
y = "-ish\n";

regression-tests/test-results/mixed-function-expression-and-std-for-each.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,11 @@
3232
// Passing a function expression
3333
std::ranges::for_each(
3434
vec,
35-
[](auto& x) -> void { x += "-ish"; }
35+
[](auto& x) mutable -> void { x += "-ish"; }
3636
);
3737

3838
// Initializing from a function expression
39-
auto callback {[](auto& x) -> void { x += " maybe"; }};
39+
auto callback {[](auto& x) mutable -> void { x += " maybe"; }};
4040
std::ranges::for_each(
4141
vec,
4242
std::move(callback)

regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each-with-capture.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232

3333
auto y {"\n"};
3434
std::ranges::for_each
35-
(vec, [_0 = std::move(y)](auto const& x) -> void { std::cout << x << _0; });
35+
(vec, [_0 = std::move(y)](auto const& x) mutable -> void { std::cout << x << _0; });
3636

37-
auto callback {[](auto& x) -> void { x += "-ish"; }};
37+
auto callback {[](auto& x) mutable -> void { x += "-ish"; }};
3838
std::ranges::for_each(vec, std::move(callback));
3939

4040
for ( auto const& str : vec )

regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
"hello", "2022"};
3232

3333
std::ranges::for_each
34-
(vec, [](auto const& x) -> void { std::cout << x << "\n"; });
34+
(vec, [](auto const& x) mutable -> void { std::cout << x << "\n"; });
3535

36-
auto callback {[](auto& x) -> void { x += "-ish"; }};
36+
auto callback {[](auto& x) mutable -> void { x += "-ish"; }};
3737
std::ranges::for_each(vec, std::move(callback));
3838

3939
for ( auto const& str : vec )

regression-tests/test-results/mixed-function-expression-with-pointer-capture.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
"hello", "2023"};
3232

3333
std::string y {"\n"};
34-
std::ranges::for_each(vec, [_0 = (&y)](auto const& x) -> void {
34+
std::ranges::for_each(vec, [_0 = (&y)](auto const& x) mutable -> void {
3535
std::cout << CPP2_UFCS_0(c_str, (*cpp2::assert_not_null(_0))) << x << *cpp2::assert_not_null(_0); }
3636
);
3737

38-
auto callback {[](auto& x) -> void { x += "-ish"; }};
38+
auto callback {[](auto& x) mutable -> void { x += "-ish"; }};
3939
std::ranges::for_each(vec, std::move(callback));
4040

4141
for ( auto const& str : vec )

regression-tests/test-results/mixed-function-expression-with-repeated-capture.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@
3232

3333
auto y {"\n"};
3434
std::ranges::for_each
35-
(vec, [_0 = std::move(y)](auto const& x) -> void { std::cout << _0 << x << _0; });
35+
(vec, [_0 = std::move(y)](auto const& x) mutable -> void { std::cout << _0 << x << _0; });
3636

37-
auto callback {[](auto& x) -> void { x += "-ish"; }};
37+
auto callback {[](auto& x) mutable -> void { x += "-ish"; }};
3838
std::ranges::for_each(vec, std::move(callback));
3939

4040
for ( auto const& str : vec )

regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ class t;
2020
// Standalone Cpp1 repro: https://godbolt.org/z/dznnYTvc6
2121

2222
#line 5 "pure2-bugfix-for-non-local-function-expression.cpp2"
23-
template<typename T> concept v = []() -> bool { return true; }();
23+
template<typename T> concept v = []() mutable -> bool { return true; }();
2424

25-
using u = std::type_identity_t<decltype([]() -> void{})>;
25+
using u = std::type_identity_t<decltype([]() mutable -> void{})>;
2626

27-
class t: public std::type_identity_t<decltype([]() -> void{})> {
27+
class t: public std::type_identity_t<decltype([]() mutable -> void{})> {
2828

2929
};
3030

regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ using g_ret = int;
3333
[[nodiscard]] auto f() -> f_ret{
3434
int ri {0};
3535
#line 3 "pure2-look-up-parameter-across-unnamed-function.cpp2"
36-
auto pred {[](auto const& e) -> auto { return e == 1; }};
36+
auto pred {[](auto const& e) mutable -> auto { return e == 1; }};
3737
ri = 42;
3838
std::move(pred)(ri);
3939
return std::move(ri); // "return;" is implicit"
@@ -43,7 +43,7 @@ using g_ret = int;
4343
cpp2::deferred_init<int> ri;
4444
#line 10 "pure2-look-up-parameter-across-unnamed-function.cpp2"
4545
ri.construct(0);
46-
auto pred {[](auto const& e) -> auto { return e == 1; }};
46+
auto pred {[](auto const& e) mutable -> auto { return e == 1; }};
4747
ri.value() = 42;
4848
std::move(pred)(ri.value());
4949
return std::move(ri.value());

regression-tests/test-results/pure2-more-wildcards.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
#line 1 "pure2-more-wildcards.cpp2"
2424

2525
#line 2 "pure2-more-wildcards.cpp2"
26-
[[nodiscard]] auto less_than(auto const& value) -> auto { return [_0 = value](auto const& x) -> auto { return cpp2::cmp_less(x,_0); }; }
26+
[[nodiscard]] auto less_than(auto const& value) -> auto { return [_0 = value](auto const& x) mutable -> auto { return cpp2::cmp_less(x,_0); }; }
2727

2828
[[nodiscard]] auto main() -> int
2929
{

regression-tests/test-results/pure2-print.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,9 @@ requires (true) inline CPP2_CONSTEXPR T outer::object_alias = 42;
116116
cpp2::Default.expects(CPP2_UFCS_0(empty, m) == false || false, "message");
117117
cpp2::Bounds.expects([_0 = 0, _1 = CPP2_UFCS_0(ssize, m), _2 = 100]{ return cpp2::cmp_less(_0,_1) && cpp2::cmp_less(_1,_2); }() && true != false, "");
118118
#line 35 "pure2-print.cpp2"
119-
auto a {[]() -> void{}};
120-
auto b {[]() -> void{}};
121-
auto c {[]() -> void{}};
119+
auto a {[]() mutable -> void{}};
120+
auto b {[]() mutable -> void{}};
121+
auto c {[]() mutable -> void{}};
122122

123123
for( ; CPP2_UFCS_0(empty, s); a() ) {break; }
124124

@@ -133,7 +133,7 @@ requires (true) inline CPP2_CONSTEXPR T outer::object_alias = 42;
133133

134134
cpp2::Default.expects(true, "");
135135

136-
return [_0 = (s + CPP2_ASSERT_IN_BOUNDS(m, 0))]() -> std::string { return _0; }();
136+
return [_0 = (s + CPP2_ASSERT_IN_BOUNDS(m, 0))]() mutable -> std::string { return _0; }();
137137
}
138138

139139
template<typename T> [[nodiscard]] auto outer::mytype::values([[maybe_unused]] T const& unnamed_param_2) const& -> values_ret{

regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ namespace N {
150150
#line 35 "pure2-types-order-independence-and-nesting.cpp2"
151151
auto X::exx(cpp2::in<int> count) const& -> void{
152152
// Exercise '_' anonymous objects too while we're at it
153-
cpp2::finally auto_37_9 {[&]() -> void { std::cout << "leaving call to 'why(" + cpp2::to_string(count) + ")'\n"; }};
153+
cpp2::finally auto_37_9 {[&]() mutable -> void { std::cout << "leaving call to 'why(" + cpp2::to_string(count) + ")'\n"; }};
154154
if (cpp2::cmp_less(count,5)) {
155155
CPP2_UFCS(why, (*cpp2::assert_not_null(py)), count + 1);// use Y object from X
156156
}

regression-tests/test-results/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.3.0 Build 8B20:1424
2+
cppfront compiler v0.3.0 Build 8B21:1401
33
Copyright(c) Herb Sutter All rights reserved
44

55
SPDX-License-Identifier: CC-BY-NC-ND-4.0

source/build.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"8B20:1424"
1+
"8B21:1401"

source/reflect.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,7 @@ namespace meta {
769769
CPP2_UFCS(push_back, generated_lines, std::vector<source_line>());
770770
auto lines {&CPP2_UFCS_0(back, generated_lines)};
771771

772-
auto add_line {[&, _1 = lines](cpp2::in<std::string_view> s) -> void{
772+
auto add_line {[&, _1 = lines](cpp2::in<std::string_view> s) mutable -> void{
773773
static_cast<void>(CPP2_UFCS(emplace_back, (*cpp2::assert_not_null(_1)), s, source_line::category::cpp2));
774774
}};
775775
{
@@ -1531,7 +1531,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void
15311531
{
15321532
// Let basic_enum do its thing, with an incrementing value generator
15331533
CPP2_UFCS(basic_enum, t,
1534-
[](std::string& value, cpp2::in<std::string> specified_value) -> void{
1534+
[](std::string& value, cpp2::in<std::string> specified_value) mutable -> void{
15351535
if (!(CPP2_UFCS_0(empty, specified_value))) {
15361536
value = specified_value;
15371537
}else {
@@ -1548,7 +1548,7 @@ auto flag_enum(meta::type_declaration& t) -> void
15481548
{
15491549
// Let basic_enum do its thing, with a power-of-two value generator
15501550
CPP2_UFCS(basic_enum, t,
1551-
[](std::string& value, cpp2::in<std::string> specified_value) -> void{
1551+
[](std::string& value, cpp2::in<std::string> specified_value) mutable -> void{
15521552
if (!(CPP2_UFCS_0(empty, specified_value))) {
15531553
value = specified_value;
15541554
}else {

source/to_cpp1.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4421,6 +4421,12 @@ class cppfront
44214421
emit(*n.parameters);
44224422
}
44234423

4424+
// For an anonymous function, make the emitted lambda 'mutable'
4425+
if (!n.my_decl->has_name())
4426+
{
4427+
printer.print_cpp2( " mutable", n.position() );
4428+
}
4429+
44244430
// For now, adding implicit noexcept only for move/swap/dtor functions
44254431
if (
44264432
n.is_move()

0 commit comments

Comments
 (0)