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..e3789105bd --- /dev/null +++ b/regression-tests/pure2-bugfix-for-unbraced-function-expression.cpp2 @@ -0,0 +1,15 @@ +t: type = { + operator[]: (this, f) = { } +} + +main: () -> int = { + (x := t()) { x[:() -> _ = 0]; } + (x := t()) { x[:() -> _ = 0;]; } + + assert(!(:() = 0; is int)); + + 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..9a59f198f2 --- /dev/null +++ b/regression-tests/test-results/pure2-bugfix-for-unbraced-function-expression.cpp @@ -0,0 +1,61 @@ + +#define CPP2_IMPORT_STD Yes + +//=== Cpp2 type declarations ==================================================== + + +#include "cpp2util.h" + +#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2" +class t; +#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2" + + +//=== Cpp2 type definitions and function declarations =========================== + +#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2" +class t { +#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2" + 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 14 "pure2-bugfix-for-unbraced-function-expression.cpp2" +auto inline constexpr x = cpp2::i32{0}; +extern cpp2::i32 y; + +//=== Cpp2 function definitions ================================================= + +#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2" + +#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, []() mutable -> auto { return 0; }); } +} +{ +auto const& x = t(); +#line 7 "pure2-bugfix-for-unbraced-function-expression.cpp2" + {CPP2_ASSERT_IN_BOUNDS(x, []() mutable -> auto { return 0; }); } +} + +#line 9 "pure2-bugfix-for-unbraced-function-expression.cpp2" + cpp2::Default.expects(!((cpp2::is([]() mutable -> void { 0; }))), ""); + + return cpp2::i32{0}; +} + +#line 15 "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 3fdd54d735..8cf4d91917 100644 --- a/source/parse.h +++ b/source/parse.h @@ -5480,6 +5480,7 @@ class parser !decl->has_name() && "ICE: declaration should have been unnamed" ); + 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)"); @@ -5504,17 +5505,6 @@ 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); - } } else { error("(temporary alpha limitation) an unnamed declaration at expression scope must be a function or an object"); @@ -5522,6 +5512,23 @@ class parser return {}; } + if ( + peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is not a braced function expression + && 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); + } + n->expr = std::move(decl); return n; }