From 536bd43831b1a62e9ff00732e2dfac6e4b4d217b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Thu, 3 Oct 2024 21:58:20 -0400 Subject: [PATCH 1/5] fix: lower (nested) _braced-init-list_ (argument) --- .../pure2-bugfix-for-nested-lists.cpp2 | 27 ++++++ .../test-results/mixed-default-arguments.cpp | 4 +- .../pure2-bugfix-for-nested-lists.cpp | 86 +++++++++++++++++++ .../pure2-bugfix-for-nested-lists.cpp2.output | 2 + .../test-results/pure2-hashable.cpp | 2 +- source/parse.h | 30 +++++-- source/to_cpp1.h | 17 +++- 7 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 regression-tests/pure2-bugfix-for-nested-lists.cpp2 create mode 100644 regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp create mode 100644 regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp2.output diff --git a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 new file mode 100644 index 000000000..3c7604aae --- /dev/null +++ b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 @@ -0,0 +1,27 @@ +point: @value type = { + public x: int = 0; + public y: int = 0; + operator=: (implicit out this, x_: int, y_: int) = { + x = x_; + y = y_; + } +} + +check: (p: point) p; + +main: () = { + assert(check((17, 29)).x == 17); + assert(check((17, 29)).y == 29); + + board: std::array, 3> = (( + ('O', 'X', 'O'), + (' ', ('X'), 'X'), + ('X', 'O', 'O') + )); + assert(board[0] == :std::array = ('O', 'X', 'O')); + assert(board[1] == :std::array = (' ', 'X', 'X')); + assert(board[2] == :std::array = ('X', 'O', 'O')); + + // Still parentheses (for now?) + assert((:std::vector = (17, 29)).size() == 2); +} diff --git a/regression-tests/test-results/mixed-default-arguments.cpp b/regression-tests/test-results/mixed-default-arguments.cpp index 6703d73a1..8ba829ff4 100644 --- a/regression-tests/test-results/mixed-default-arguments.cpp +++ b/regression-tests/test-results/mixed-default-arguments.cpp @@ -33,8 +33,8 @@ auto cxx2(cpp2::impl::in x, cpp2::impl::in y) -> void{ #line 9 "mixed-default-arguments.cpp2" auto main() -> int{ cxx(1, "test"); - cxx({}, {}); + cxx({ }, { }); cxx2(1, "test"); - cxx2({}, {}); + cxx2({ }, { }); } diff --git a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp new file mode 100644 index 000000000..e07ea4975 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp @@ -0,0 +1,86 @@ + +#define CPP2_IMPORT_STD Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-nested-lists.cpp2" +class point; +#line 2 "pure2-bugfix-for-nested-lists.cpp2" + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-nested-lists.cpp2" +class point { +#line 2 "pure2-bugfix-for-nested-lists.cpp2" + public: int x {0}; + public: int y {0}; + public: point(cpp2::impl::in x_, cpp2::impl::in y_); + public: [[nodiscard]] auto operator<=>(point const& that) const& -> std::strong_ordering = default; +public: point(point const& that); + +public: auto operator=(point const& that) -> point& ; +public: point(point&& that) noexcept; +public: auto operator=(point&& that) noexcept -> point& ; +public: explicit point(); + +#line 8 "pure2-bugfix-for-nested-lists.cpp2" +}; + +[[nodiscard]] auto check(cpp2::impl::in p) -> auto; + +auto main() -> int; + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-bugfix-for-nested-lists.cpp2" + +#line 4 "pure2-bugfix-for-nested-lists.cpp2" + point::point(cpp2::impl::in x_, cpp2::impl::in y_) + : x{ x_ } + , y{ y_ }{ + +#line 7 "pure2-bugfix-for-nested-lists.cpp2" + } + + + point::point(point const& that) + : x{ that.x } + , y{ that.y }{} + +auto point::operator=(point const& that) -> point& { + x = that.x; + y = that.y; + return *this;} +point::point(point&& that) noexcept + : x{ std::move(that).x } + , y{ std::move(that).y }{} +auto point::operator=(point&& that) noexcept -> point& { + x = std::move(that).x; + y = std::move(that).y; + return *this;} +point::point(){} +#line 10 "pure2-bugfix-for-nested-lists.cpp2" +[[nodiscard]] auto check(cpp2::impl::in p) -> auto { return p; } + +#line 12 "pure2-bugfix-for-nested-lists.cpp2" +auto main() -> int{ + if (cpp2::cpp2_default.is_active() && !(check({ 17, 29 }).x == 17) ) { cpp2::cpp2_default.report_violation(""); } + if (cpp2::cpp2_default.is_active() && !(check({ 17, 29 }).y == 29) ) { cpp2::cpp2_default.report_violation(""); } + + std::array,3> board {{ { + 'O', 'X', 'O' }, { + ' ', { 'X' }, 'X' }, { + 'X', 'O', 'O' } }}; + + if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(board, 0) == std::array{'O', 'X', 'O'}) ) { cpp2::cpp2_default.report_violation(""); } + if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(board, 1) == std::array{' ', 'X', 'X'}) ) { cpp2::cpp2_default.report_violation(""); } + if (cpp2::cpp2_default.is_active() && !(CPP2_ASSERT_IN_BOUNDS_LITERAL(cpp2::move(board), 2) == std::array{'X', 'O', 'O'}) ) { cpp2::cpp2_default.report_violation(""); } + + // Still parentheses (for now?) + if (cpp2::cpp2_default.is_active() && !(CPP2_UFCS(size)((std::vector{17, 29})) == 2) ) { cpp2::cpp2_default.report_violation(""); } +} + diff --git a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp2.output new file mode 100644 index 000000000..777e34d55 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-nested-lists.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/regression-tests/test-results/pure2-hashable.cpp b/regression-tests/test-results/pure2-hashable.cpp index 008d74f8a..e7683fa81 100644 --- a/regression-tests/test-results/pure2-hashable.cpp +++ b/regression-tests/test-results/pure2-hashable.cpp @@ -66,7 +66,7 @@ return ret; mystruct::mystruct(auto&& i_, auto&& j_, auto&& k_) requires (std::is_convertible_v&> && std::is_convertible_v&> && std::is_convertible_v&>) - : base{ (1) } + : base{ { 1 } } , i{ CPP2_FORWARD(i_) } , j{ CPP2_FORWARD(j_) } , k{ CPP2_FORWARD(k_) }{} diff --git a/source/parse.h b/source/parse.h index d9fa3d2d0..3683a31c6 100644 --- a/source/parse.h +++ b/source/parse.h @@ -7058,9 +7058,9 @@ class parser // Next should be an expression-list followed by a ')' // If not, then this wasn't a call expression so backtrack to // the '(' which will be part of the next grammar production - is_inside_call_expr = true; - term.expr_list = expression_list(term.op, lexeme::RightParen); - is_inside_call_expr = false; + is_inside_call_expr = true; + term.expr_list = expression_list(term.op, lexeme::RightParen, true); + is_inside_call_expr = false; if ( term.expr_list @@ -7604,8 +7604,28 @@ class parser return n; } + auto add_expression = [&](expression_list_node::term t) { + std::function mark_nested_inside_initializer{ + [&](expression_list_node::term& u) { + if ( + inside_initializer + && u.expr->is_expression_list() + ) + { + auto l = const_cast(u.expr->get_expression_list()); + l->inside_initializer = true; + for (auto& e : l->expressions) { + mark_nested_inside_initializer(e); + } + } + } + }; + mark_nested_inside_initializer(t); + n->expressions.push_back(std::move(t)); + }; + // Otherwise remember the first expression - n->expressions.push_back( { pass, std::move(x) } ); + add_expression( { pass, std::move(x) } ); // and see if there are more... while (curr().type() == lexeme::Comma) { next(); @@ -7621,7 +7641,7 @@ class parser error("invalid text in expression list", true, {}, true); return {}; } - n->expressions.push_back( { pass, std::move(expr) } ); + add_expression( { pass, std::move(expr) } ); } return n; diff --git a/source/to_cpp1.h b/source/to_cpp1.h index ba23101d9..7fd2f191d 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -4235,7 +4235,22 @@ class cppfront assert(x.expr); current_args.push_back( {x.pass} ); - emit(*x.expr); + // In a nested expression-list in an initializer, we can + // take over direct control of emitting it without needing to + // go through the whole grammar, and surround it with braces + if ( + n.inside_initializer + && x.expr->is_expression_list() + ) + { + printer.print_cpp2( "{ ", n.position() ); + emit(*x.expr->get_expression_list(), false); + printer.print_cpp2( " }", n.position() ); + } + // Otherwise, just emit the general expression as usual + else { + emit(*x.expr); + } current_args.pop_back(); if (is_out) { From 6f16a23f9004b1bbe20a77bcef0db74c810faeb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Thu, 3 Oct 2024 22:23:05 -0400 Subject: [PATCH 2/5] fix: revert #1092 --- regression-tests/pure2-bugfix-for-nested-lists.cpp2 | 6 ++++++ .../test-results/pure2-bugfix-for-nested-lists.cpp | 10 ++++++++++ source/parse.h | 6 ------ source/to_cpp1.h | 7 ------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 index 3c7604aae..63570974e 100644 --- a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 +++ b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 @@ -25,3 +25,9 @@ main: () = { // Still parentheses (for now?) assert((:std::vector = (17, 29)).size() == 2); } + +issue_1283: () = { + arr: std::array = (); + f: MyFunctor = ("Some initial value"); + std::ranges::generate(arr, :() (f&$*)()); +} diff --git a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp index e07ea4975..fa021a340 100644 --- a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp @@ -34,6 +34,9 @@ public: explicit point(); auto main() -> int; +#line 29 "pure2-bugfix-for-nested-lists.cpp2" +auto issue_1283() -> void; + //=== Cpp2 function definitions ================================================= #line 1 "pure2-bugfix-for-nested-lists.cpp2" @@ -84,3 +87,10 @@ auto main() -> int{ if (cpp2::cpp2_default.is_active() && !(CPP2_UFCS(size)((std::vector{17, 29})) == 2) ) { cpp2::cpp2_default.report_violation(""); } } +#line 29 "pure2-bugfix-for-nested-lists.cpp2" +auto issue_1283() -> void{ + std::array arr {}; + MyFunctor f {"Some initial value"}; + std::ranges::generate(cpp2::move(arr), [_0 = (&f)]() mutable -> auto { return (*cpp2::impl::assert_not_null(_0))(); }); +} + diff --git a/source/parse.h b/source/parse.h index 3683a31c6..585801878 100644 --- a/source/parse.h +++ b/source/parse.h @@ -784,7 +784,6 @@ struct expression_list_node token const* open_paren = {}; token const* close_paren = {}; bool inside_initializer = false; - bool default_initializer = false; struct term { passing_style pass = {}; @@ -6514,7 +6513,6 @@ class parser }; mutable std::vector function_body_extents; mutable bool is_function_body_extents_sorted = false; - bool is_inside_call_expr = false; public: auto is_within_function_body(source_position p) const @@ -6901,8 +6899,6 @@ class parser expr_list->inside_initializer = false; } n->expression_list_is_fold_expression = expr_list->is_fold_expression(); - expr_list->default_initializer = - is_inside_call_expr && std::empty(expr_list->expressions); n->expr = std::move(expr_list); return n; @@ -7058,9 +7054,7 @@ class parser // Next should be an expression-list followed by a ')' // If not, then this wasn't a call expression so backtrack to // the '(' which will be part of the next grammar production - is_inside_call_expr = true; term.expr_list = expression_list(term.op, lexeme::RightParen, true); - is_inside_call_expr = false; if ( term.expr_list diff --git a/source/to_cpp1.h b/source/to_cpp1.h index 7fd2f191d..6bb6fd8eb 100644 --- a/source/to_cpp1.h +++ b/source/to_cpp1.h @@ -4191,13 +4191,6 @@ class cppfront !(n.inside_initializer && current_declarations.back()->initializer->position() != n.open_paren->position()) ; - if (n.default_initializer) { - if (add_parens) { - printer.print_cpp2("{}", n.position()); - } - return; - } - if (add_parens) { printer.print_cpp2( *n.open_paren, n.position()); } From cd7cb99c6fec16a8e22cdea5f87e145e942ee1ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Thu, 3 Oct 2024 22:42:51 -0400 Subject: [PATCH 3/5] test: make reproducer compilable --- regression-tests/pure2-bugfix-for-nested-lists.cpp2 | 5 ++--- .../test-results/pure2-bugfix-for-nested-lists.cpp | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 index 63570974e..df83bd79d 100644 --- a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 +++ b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 @@ -27,7 +27,6 @@ main: () = { } issue_1283: () = { - arr: std::array = (); - f: MyFunctor = ("Some initial value"); - std::ranges::generate(arr, :() (f&$*)()); + f := :() = { }; + _ = :() = (f&$*)(); } diff --git a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp index fa021a340..c57978513 100644 --- a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp @@ -89,8 +89,7 @@ auto main() -> int{ #line 29 "pure2-bugfix-for-nested-lists.cpp2" auto issue_1283() -> void{ - std::array arr {}; - MyFunctor f {"Some initial value"}; - std::ranges::generate(cpp2::move(arr), [_0 = (&f)]() mutable -> auto { return (*cpp2::impl::assert_not_null(_0))(); }); + auto f {[]() -> void{}}; + static_cast([_0 = (&f)]() mutable -> void { (*cpp2::impl::assert_not_null(_0))(); }); } From eefa21d4006d3df93003b354a4ffcc3f999d4fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Thu, 3 Oct 2024 22:43:28 -0400 Subject: [PATCH 4/5] test: fix default initializer --- regression-tests/pure2-hashable.cpp2 | 4 ++-- regression-tests/test-results/pure2-hashable.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/regression-tests/pure2-hashable.cpp2 b/regression-tests/pure2-hashable.cpp2 index 34a1e09ef..5e71a5aaa 100644 --- a/regression-tests/pure2-hashable.cpp2 +++ b/regression-tests/pure2-hashable.cpp2 @@ -3,7 +3,7 @@ base: @struct @hashable type = { } mystruct: @struct @hashable type = { - this: base = (1); + this: base = 1; i: i32; j: std::string; k: u64; @@ -12,4 +12,4 @@ mystruct: @struct @hashable type = { main: () = { x: mystruct = (2, "three", 4u); std::cout << x.hash(); -} \ No newline at end of file +} diff --git a/regression-tests/test-results/pure2-hashable.cpp b/regression-tests/test-results/pure2-hashable.cpp index e7683fa81..ccc116303 100644 --- a/regression-tests/test-results/pure2-hashable.cpp +++ b/regression-tests/test-results/pure2-hashable.cpp @@ -66,7 +66,7 @@ return ret; mystruct::mystruct(auto&& i_, auto&& j_, auto&& k_) requires (std::is_convertible_v&> && std::is_convertible_v&> && std::is_convertible_v&>) - : base{ { 1 } } + : base{ 1 } , i{ CPP2_FORWARD(i_) } , j{ CPP2_FORWARD(j_) } , k{ CPP2_FORWARD(k_) }{} From 4c18d9f716fec27d5ec5dac683227a4a6791ec32 Mon Sep 17 00:00:00 2001 From: Alistair Bell Date: Sat, 15 Nov 2025 12:52:20 -0500 Subject: [PATCH 5/5] Update testcase for recent cppfront developments. --- regression-tests/pure2-bugfix-for-nested-lists.cpp2 | 2 +- .../test-results/pure2-bugfix-for-nested-lists.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 index df83bd79d..e20b63e89 100644 --- a/regression-tests/pure2-bugfix-for-nested-lists.cpp2 +++ b/regression-tests/pure2-bugfix-for-nested-lists.cpp2 @@ -7,7 +7,7 @@ point: @value type = { } } -check: (p: point) p; +check: (copy p: point) -> point = p; main: () = { assert(check((17, 29)).x == 17); diff --git a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp index c57978513..d493910a9 100644 --- a/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp +++ b/regression-tests/test-results/pure2-bugfix-for-nested-lists.cpp @@ -30,7 +30,7 @@ public: explicit point(); #line 8 "pure2-bugfix-for-nested-lists.cpp2" }; -[[nodiscard]] auto check(cpp2::impl::in p) -> auto; +[[nodiscard]] auto check(point p) -> point; auto main() -> int; @@ -67,7 +67,7 @@ auto point::operator=(point&& that) noexcept -> point& { return *this;} point::point(){} #line 10 "pure2-bugfix-for-nested-lists.cpp2" -[[nodiscard]] auto check(cpp2::impl::in p) -> auto { return p; } +[[nodiscard]] auto check(point p) -> point { return cpp2::move(p); } #line 12 "pure2-bugfix-for-nested-lists.cpp2" auto main() -> int{ @@ -90,6 +90,6 @@ auto main() -> int{ #line 29 "pure2-bugfix-for-nested-lists.cpp2" auto issue_1283() -> void{ auto f {[]() -> void{}}; - static_cast([_0 = (&f)]() mutable -> void { (*cpp2::impl::assert_not_null(_0))(); }); + static_cast([_0 = (&f)]() mutable -> decltype(auto) { return (*cpp2::impl::assert_not_null(_0))(); }); }