diff --git a/include/cpp2util.h b/include/cpp2util.h index ad4f3af5c..4f9677f40 100644 --- a/include/cpp2util.h +++ b/include/cpp2util.h @@ -1079,7 +1079,7 @@ auto is( X const& x ) -> bool { // Values // -inline constexpr auto is( auto const& x, auto const& value ) -> bool +inline constexpr auto is( auto const& x, auto&& value ) -> bool { // Value with customized operator_is case if constexpr (requires{ x.op_is(value); }) { @@ -1313,7 +1313,7 @@ auto is( std::variant const& x ); // is Value // template -constexpr auto is( std::variant const& x, auto const& value ) -> bool +constexpr auto is( std::variant const& x, auto&& value ) -> bool { // Predicate case 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 // is Value // -inline constexpr auto is( std::any const& x, auto const& value ) -> bool +inline constexpr auto is( std::any const& x, auto&& value ) -> bool { // Predicate case if constexpr (requires{ bool{ value(x) }; }) { @@ -1542,7 +1542,7 @@ constexpr auto is( std::optional const& x ) -> bool // is Value // template -constexpr auto is( std::optional const& x, auto const& value ) -> bool +constexpr auto is( std::optional const& x, auto&& value ) -> bool { // Predicate case if constexpr (requires{ bool{ value(x) }; }) { diff --git a/regression-tests/test-results/clang-12/pure2-bugfix-for-non-local-function-expression.cpp.output b/regression-tests/test-results/clang-12/pure2-bugfix-for-non-local-function-expression.cpp.output index 7922990a5..b82b09129 100644 --- a/regression-tests/test-results/clang-12/pure2-bugfix-for-non-local-function-expression.cpp.output +++ b/regression-tests/test-results/clang-12/pure2-bugfix-for-non-local-function-expression.cpp.output @@ -1,10 +1,10 @@ pure2-bugfix-for-non-local-function-expression.cpp2:5:34: error: lambda expression in an unevaluated operand -template concept v = []() -> bool { return true; }(); +template concept v = []() mutable -> bool { return true; }(); ^ pure2-bugfix-for-non-local-function-expression.cpp2:7:41: error: lambda expression in an unevaluated operand -using u = std::type_identity_t void{})>; +using u = std::type_identity_t void{})>; ^ pure2-bugfix-for-non-local-function-expression.cpp2:9:47: error: lambda expression in an unevaluated operand -class t: public std::type_identity_t void{})> { +class t: public std::type_identity_t void{})> { ^ 3 errors generated. diff --git a/regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp b/regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp index c8d25f39c..1b7893e48 100644 --- a/regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp +++ b/regression-tests/test-results/mixed-captures-in-expressions-and-postconditions.cpp @@ -33,7 +33,7 @@ auto insert_at(cpp2::in where, cpp2::in val) -> void; "hello", "2022"}; std::string y {"\n"}; - auto callback {[_0 = (&y)](auto const& x) -> void { std::cout << x << *cpp2::assert_not_null(_0); }}; + auto callback {[_0 = (&y)](auto const& x) mutable -> void { std::cout << x << *cpp2::assert_not_null(_0); }}; std::ranges::for_each(vec, callback); y = "-ish\n"; diff --git a/regression-tests/test-results/mixed-function-expression-and-std-for-each.cpp b/regression-tests/test-results/mixed-function-expression-and-std-for-each.cpp index 6346fb6dc..1ed322444 100644 --- a/regression-tests/test-results/mixed-function-expression-and-std-for-each.cpp +++ b/regression-tests/test-results/mixed-function-expression-and-std-for-each.cpp @@ -32,11 +32,11 @@ // Passing a function expression std::ranges::for_each( vec, - [](auto& x) -> void { x += "-ish"; } + [](auto& x) mutable -> void { x += "-ish"; } ); // Initializing from a function expression - auto callback {[](auto& x) -> void { x += " maybe"; }}; + auto callback {[](auto& x) mutable -> void { x += " maybe"; }}; std::ranges::for_each( vec, std::move(callback) diff --git a/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each-with-capture.cpp b/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each-with-capture.cpp index df9460f2e..5cfec66f9 100644 --- a/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each-with-capture.cpp +++ b/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each-with-capture.cpp @@ -32,9 +32,9 @@ auto y {"\n"}; std::ranges::for_each - (vec, [_0 = std::move(y)](auto const& x) -> void { std::cout << x << _0; }); + (vec, [_0 = std::move(y)](auto const& x) mutable -> void { std::cout << x << _0; }); - auto callback {[](auto& x) -> void { x += "-ish"; }}; + auto callback {[](auto& x) mutable -> void { x += "-ish"; }}; std::ranges::for_each(vec, std::move(callback)); for ( auto const& str : vec ) diff --git a/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each.cpp b/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each.cpp index 00367a429..7fcfc8177 100644 --- a/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each.cpp +++ b/regression-tests/test-results/mixed-function-expression-and-std-ranges-for-each.cpp @@ -31,9 +31,9 @@ "hello", "2022"}; std::ranges::for_each - (vec, [](auto const& x) -> void { std::cout << x << "\n"; }); + (vec, [](auto const& x) mutable -> void { std::cout << x << "\n"; }); - auto callback {[](auto& x) -> void { x += "-ish"; }}; + auto callback {[](auto& x) mutable -> void { x += "-ish"; }}; std::ranges::for_each(vec, std::move(callback)); for ( auto const& str : vec ) diff --git a/regression-tests/test-results/mixed-function-expression-with-pointer-capture.cpp b/regression-tests/test-results/mixed-function-expression-with-pointer-capture.cpp index 6e3df47f9..571d076d4 100644 --- a/regression-tests/test-results/mixed-function-expression-with-pointer-capture.cpp +++ b/regression-tests/test-results/mixed-function-expression-with-pointer-capture.cpp @@ -31,11 +31,11 @@ "hello", "2023"}; std::string y {"\n"}; - std::ranges::for_each(vec, [_0 = (&y)](auto const& x) -> void { + std::ranges::for_each(vec, [_0 = (&y)](auto const& x) mutable -> void { std::cout << CPP2_UFCS_0(c_str, (*cpp2::assert_not_null(_0))) << x << *cpp2::assert_not_null(_0); } ); - auto callback {[](auto& x) -> void { x += "-ish"; }}; + auto callback {[](auto& x) mutable -> void { x += "-ish"; }}; std::ranges::for_each(vec, std::move(callback)); for ( auto const& str : vec ) diff --git a/regression-tests/test-results/mixed-function-expression-with-repeated-capture.cpp b/regression-tests/test-results/mixed-function-expression-with-repeated-capture.cpp index 08863a288..9e38b1c44 100644 --- a/regression-tests/test-results/mixed-function-expression-with-repeated-capture.cpp +++ b/regression-tests/test-results/mixed-function-expression-with-repeated-capture.cpp @@ -32,9 +32,9 @@ auto y {"\n"}; std::ranges::for_each - (vec, [_0 = std::move(y)](auto const& x) -> void { std::cout << _0 << x << _0; }); + (vec, [_0 = std::move(y)](auto const& x) mutable -> void { std::cout << _0 << x << _0; }); - auto callback {[](auto& x) -> void { x += "-ish"; }}; + auto callback {[](auto& x) mutable -> void { x += "-ish"; }}; std::ranges::for_each(vec, std::move(callback)); for ( auto const& str : vec ) diff --git a/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp b/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp index 90b4f54a1..43165f8fe 100644 --- a/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-non-local-function-expression.cpp @@ -20,11 +20,11 @@ class t; // Standalone Cpp1 repro: https://godbolt.org/z/dznnYTvc6 #line 5 "pure2-bugfix-for-non-local-function-expression.cpp2" -template concept v = []() -> bool { return true; }(); +template concept v = []() mutable -> bool { return true; }(); -using u = std::type_identity_t void{})>; +using u = std::type_identity_t void{})>; -class t: public std::type_identity_t void{})> { +class t: public std::type_identity_t void{})> { }; diff --git a/regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp b/regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp index 2511a56e3..620c479c8 100644 --- a/regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp +++ b/regression-tests/test-results/pure2-look-up-parameter-across-unnamed-function.cpp @@ -33,7 +33,7 @@ using g_ret = int; [[nodiscard]] auto f() -> f_ret{ int ri {0}; #line 3 "pure2-look-up-parameter-across-unnamed-function.cpp2" - auto pred {[](auto const& e) -> auto { return e == 1; }}; + auto pred {[](auto const& e) mutable -> auto { return e == 1; }}; ri = 42; std::move(pred)(ri); return std::move(ri); // "return;" is implicit" @@ -43,7 +43,7 @@ using g_ret = int; cpp2::deferred_init ri; #line 10 "pure2-look-up-parameter-across-unnamed-function.cpp2" ri.construct(0); - auto pred {[](auto const& e) -> auto { return e == 1; }}; + auto pred {[](auto const& e) mutable -> auto { return e == 1; }}; ri.value() = 42; std::move(pred)(ri.value()); return std::move(ri.value()); diff --git a/regression-tests/test-results/pure2-more-wildcards.cpp b/regression-tests/test-results/pure2-more-wildcards.cpp index 64caecef5..23a368073 100644 --- a/regression-tests/test-results/pure2-more-wildcards.cpp +++ b/regression-tests/test-results/pure2-more-wildcards.cpp @@ -23,7 +23,7 @@ #line 1 "pure2-more-wildcards.cpp2" #line 2 "pure2-more-wildcards.cpp2" -[[nodiscard]] auto less_than(auto const& value) -> auto { return [_0 = value](auto const& x) -> auto { return cpp2::cmp_less(x,_0); }; } +[[nodiscard]] auto less_than(auto const& value) -> auto { return [_0 = value](auto const& x) mutable -> auto { return cpp2::cmp_less(x,_0); }; } [[nodiscard]] auto main() -> int { diff --git a/regression-tests/test-results/pure2-print.cpp b/regression-tests/test-results/pure2-print.cpp index 5aa201184..ff88280cb 100644 --- a/regression-tests/test-results/pure2-print.cpp +++ b/regression-tests/test-results/pure2-print.cpp @@ -116,9 +116,9 @@ requires (true) inline CPP2_CONSTEXPR T outer::object_alias = 42; cpp2::Default.expects(CPP2_UFCS_0(empty, m) == false || false, "message"); 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, ""); #line 35 "pure2-print.cpp2" - auto a {[]() -> void{}}; - auto b {[]() -> void{}}; - auto c {[]() -> void{}}; + auto a {[]() mutable -> void{}}; + auto b {[]() mutable -> void{}}; + auto c {[]() mutable -> void{}}; for( ; CPP2_UFCS_0(empty, s); a() ) {break; } @@ -133,7 +133,7 @@ requires (true) inline CPP2_CONSTEXPR T outer::object_alias = 42; cpp2::Default.expects(true, ""); - return [_0 = (s + CPP2_ASSERT_IN_BOUNDS(m, 0))]() -> std::string { return _0; }(); + return [_0 = (s + CPP2_ASSERT_IN_BOUNDS(m, 0))]() mutable -> std::string { return _0; }(); } template [[nodiscard]] auto outer::mytype::values([[maybe_unused]] T const& unnamed_param_2) const& -> values_ret{ diff --git a/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp b/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp index 96b0499e3..90e02ce98 100644 --- a/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp +++ b/regression-tests/test-results/pure2-types-order-independence-and-nesting.cpp @@ -150,7 +150,7 @@ namespace N { #line 35 "pure2-types-order-independence-and-nesting.cpp2" auto X::exx(cpp2::in count) const& -> void{ // Exercise '_' anonymous objects too while we're at it - cpp2::finally auto_37_9 {[&]() -> void { std::cout << "leaving call to 'why(" + cpp2::to_string(count) + ")'\n"; }}; + cpp2::finally auto_37_9 {[&]() mutable -> void { std::cout << "leaving call to 'why(" + cpp2::to_string(count) + ")'\n"; }}; if (cpp2::cmp_less(count,5)) { CPP2_UFCS(why, (*cpp2::assert_not_null(py)), count + 1);// use Y object from X } diff --git a/regression-tests/test-results/version b/regression-tests/test-results/version index 3bfb0e91a..2e8007917 100644 --- a/regression-tests/test-results/version +++ b/regression-tests/test-results/version @@ -1,5 +1,5 @@ -cppfront compiler v0.3.0 Build 8B20:1424 +cppfront compiler v0.3.0 Build 8B21:1401 Copyright(c) Herb Sutter All rights reserved SPDX-License-Identifier: CC-BY-NC-ND-4.0 diff --git a/source/build.info b/source/build.info index 18c3e1117..40bcc415c 100644 --- a/source/build.info +++ b/source/build.info @@ -1 +1 @@ -"8B20:1424" \ No newline at end of file +"8B21:1401" \ No newline at end of file diff --git a/source/reflect.h b/source/reflect.h index 6998680d9..94946ab11 100644 --- a/source/reflect.h +++ b/source/reflect.h @@ -769,7 +769,7 @@ namespace meta { CPP2_UFCS(push_back, generated_lines, std::vector()); auto lines {&CPP2_UFCS_0(back, generated_lines)}; - auto add_line {[&, _1 = lines](cpp2::in s) -> void{ + auto add_line {[&, _1 = lines](cpp2::in s) mutable -> void{ static_cast(CPP2_UFCS(emplace_back, (*cpp2::assert_not_null(_1)), s, source_line::category::cpp2)); }}; { @@ -1531,7 +1531,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void { // Let basic_enum do its thing, with an incrementing value generator CPP2_UFCS(basic_enum, t, - [](std::string& value, cpp2::in specified_value) -> void{ + [](std::string& value, cpp2::in specified_value) mutable -> void{ if (!(CPP2_UFCS_0(empty, specified_value))) { value = specified_value; }else { @@ -1548,7 +1548,7 @@ auto flag_enum(meta::type_declaration& t) -> void { // Let basic_enum do its thing, with a power-of-two value generator CPP2_UFCS(basic_enum, t, - [](std::string& value, cpp2::in specified_value) -> void{ + [](std::string& value, cpp2::in specified_value) mutable -> void{ if (!(CPP2_UFCS_0(empty, specified_value))) { value = specified_value; }else { diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 4d27cfcb0..21ac26f34 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -4421,6 +4421,12 @@ class cppfront emit(*n.parameters); } + // For an anonymous function, make the emitted lambda 'mutable' + if (!n.my_decl->has_name()) + { + printer.print_cpp2( " mutable", n.position() ); + } + // For now, adding implicit noexcept only for move/swap/dtor functions if ( n.is_move()