From 2af70b4853ca6166132a61a6f8f9cf7a53b0d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johel=20Ernesto=20Guerrero=20Pe=C3=B1a?= Date: Tue, 30 May 2023 21:57:44 -0400 Subject: [PATCH] fix(parse): allow (to omit) semicolon after _unnamed-declaration_ --- ...gfix-for-unbraced-function-expression.cpp2 | 18 ++++++ ...unbraced-function-expression.cpp.execution | 0 ...or-unbraced-function-expression.cpp.output | 0 ...ugfix-for-unbraced-function-expression.cpp | 60 +++++++++++++++++++ ...r-unbraced-function-expression.cpp2.output | 2 + source/parse.h | 32 ++++++---- 6 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 regression-tests/pure2-bugfix-for-unbraced-function-expression.cpp2 create mode 100644 regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.execution create mode 100644 regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.output create mode 100644 regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp create mode 100644 regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp2.output diff --git a/regression-tests/pure2-bugfix-for-unbraced-function-expression.cpp2 b/regression-tests/pure2-bugfix-for-unbraced-function-expression.cpp2 new file mode 100644 index 0000000000..fd7b5e8690 --- /dev/null +++ b/regression-tests/pure2-bugfix-for-unbraced-function-expression.cpp2 @@ -0,0 +1,18 @@ +t: type = { + operator[]: (this, f) = { } +} + +main: () -> int = { + (x := t()) { x[:() -> _ = 0]; } + (x := t()) { x[:() -> _ = 0;]; } + + [[assert: !(:() = 0; is int) ]] + + _ = :i32 = 0; + [[assert: true]] + + return :i32 = 0; +} + +x :== :i32 = 0; +y: i32 = 0; diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.execution b/regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.execution new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.output b/regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.output new file mode 100644 index 0000000000..e69de29bb2 diff --git a/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp b/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp new file mode 100644 index 0000000000..b90a98097e --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp @@ -0,0 +1,60 @@ + +#define CPP2_IMPORT_STD Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +class t; + + +//=== Cpp2 type definitions and function declarations =========================== + +class t { + public: auto operator[](auto const& f) const& -> void; + + public: t() = default; + public: t(t const&) = delete; /* No 'that' constructor, suppress copy */ + public: auto operator=(t const&) -> void = delete; +#line 3 "pure2-bugfix-for-unbraced-function-expression.cpp2" +}; + +[[nodiscard]] auto main() -> int; + + +#line 17 "pure2-bugfix-for-unbraced-function-expression.cpp2" +auto inline constexpr x = cpp2::i32{0}; +extern cpp2::i32 y; + +//=== Cpp2 function definitions ================================================= + + +#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2" + auto t::operator[](auto const& f) const& -> void{} + +#line 5 "pure2-bugfix-for-unbraced-function-expression.cpp2" +[[nodiscard]] auto main() -> int{ +{ +auto const& x = t(); +#line 6 "pure2-bugfix-for-unbraced-function-expression.cpp2" + {cpp2::assert_in_bounds(x, []() -> auto { return 0; }); } +} +{ +auto const& x = t(); +#line 7 "pure2-bugfix-for-unbraced-function-expression.cpp2" + {cpp2::assert_in_bounds(x, []() -> auto { return 0; }); } +} + +#line 9 "pure2-bugfix-for-unbraced-function-expression.cpp2" + cpp2::Default.expects(!((cpp2::is([]() -> void { 0; }))), ""); + + static_cast(cpp2::i32{0}); + cpp2::Default.expects(true, ""); + + return cpp2::i32{0}; +} + +#line 18 "pure2-bugfix-for-unbraced-function-expression.cpp2" +cpp2::i32 y {0}; + diff --git a/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp2.output b/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp2.output new file mode 100644 index 0000000000..5fb1a9712f --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp2.output @@ -0,0 +1,2 @@ +pure2-bugfix-for-unbraced-function-expression.cpp2... ok (all Cpp2, passes safety checks) + diff --git a/source/parse.h b/source/parse.h index bedb265b65..700086347a 100644 --- a/source/parse.h +++ b/source/parse.h @@ -5335,12 +5335,32 @@ class parser !decl->has_name() && "ICE: declaration should have been unnamed" ); + auto simulate_double_semicolon = [&]() { + if ( + peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is short function syntax + && curr().type() != lexeme::LeftParen // not imediatelly called + && curr().type() != lexeme::RightParen // not as a last argument to function + && curr().type() != lexeme::Comma // not as first or in-the-middle, function argument + && curr().type() != lexeme::Greater // not as the last argument to template + && curr().type() != lexeme::RightBracket // not as the last index argument + && curr() != "is" // not as the argument to is + && curr() != "as" // not as the argument to as + && curr() != "do" // not as `for`'s `next`. + ) { + // this is a fix for a short function syntax that should have double semicolon used + // (check comment in expression_statement(bool semicolon_required)) + // We simulate double semicolon by moving back to single semicolon. + next(-1); + } + }; + if (auto obj = std::get_if(&decl->type)) { if ((*obj)->is_wildcard()) { error("an unnamed object at expression scope currently cannot have a deduced type (the reason to create an unnamed object is typically to create a temporary of a named type)"); next(); return {}; } + simulate_double_semicolon(); } else if (auto func = std::get_if(&decl->type)) { if ((*func)->returns.index() == function_type_node::list) { @@ -5359,17 +5379,7 @@ class parser next(); return {}; } - if ( - peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is short function syntax - && curr().type() != lexeme::LeftParen // not imediatelly called - && curr().type() != lexeme::RightParen // not as a last argument to function - && curr().type() != lexeme::Comma // not as first or in-the-middle, function argument - ) { - // this is a fix for a short function syntax that should have double semicolon used - // (check comment in expression_statement(bool semicolon_required)) - // We simulate double semicolon by moving back to single semicolon. - next(-1); - } + simulate_double_semicolon(); } else { error("(temporary alpha limitation) an unnamed declaration at expression scope must be a function or an object");