Skip to content

Commit 2af70b4

Browse files
committed
fix(parse): allow (to omit) semicolon after _unnamed-declaration_
1 parent 083c8a0 commit 2af70b4

6 files changed

+101
-11
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
t: type = {
2+
operator[]: (this, f) = { }
3+
}
4+
5+
main: () -> int = {
6+
(x := t()) { x[:() -> _ = 0]; }
7+
(x := t()) { x[:() -> _ = 0;]; }
8+
9+
[[assert: !(:() = 0; is int) ]]
10+
11+
_ = :i32 = 0;
12+
[[assert: true]]
13+
14+
return :i32 = 0;
15+
}
16+
17+
x :== :i32 = 0;
18+
y: i32 = 0;

regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.execution

Whitespace-only changes.

regression-tests/test-results/gcc-13/pure2-bugfix-for-unbraced-function-expression.cpp.output

Whitespace-only changes.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
class t;
10+
11+
12+
//=== Cpp2 type definitions and function declarations ===========================
13+
14+
class t {
15+
public: auto operator[](auto const& f) const& -> void;
16+
17+
public: t() = default;
18+
public: t(t const&) = delete; /* No 'that' constructor, suppress copy */
19+
public: auto operator=(t const&) -> void = delete;
20+
#line 3 "pure2-bugfix-for-unbraced-function-expression.cpp2"
21+
};
22+
23+
[[nodiscard]] auto main() -> int;
24+
25+
26+
#line 17 "pure2-bugfix-for-unbraced-function-expression.cpp2"
27+
auto inline constexpr x = cpp2::i32{0};
28+
extern cpp2::i32 y;
29+
30+
//=== Cpp2 function definitions =================================================
31+
32+
33+
#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2"
34+
auto t::operator[](auto const& f) const& -> void{}
35+
36+
#line 5 "pure2-bugfix-for-unbraced-function-expression.cpp2"
37+
[[nodiscard]] auto main() -> int{
38+
{
39+
auto const& x = t();
40+
#line 6 "pure2-bugfix-for-unbraced-function-expression.cpp2"
41+
{cpp2::assert_in_bounds(x, []() -> auto { return 0; }); }
42+
}
43+
{
44+
auto const& x = t();
45+
#line 7 "pure2-bugfix-for-unbraced-function-expression.cpp2"
46+
{cpp2::assert_in_bounds(x, []() -> auto { return 0; }); }
47+
}
48+
49+
#line 9 "pure2-bugfix-for-unbraced-function-expression.cpp2"
50+
cpp2::Default.expects(!((cpp2::is<int>([]() -> void { 0; }))), "");
51+
52+
static_cast<void>(cpp2::i32{0});
53+
cpp2::Default.expects(true, "");
54+
55+
return cpp2::i32{0};
56+
}
57+
58+
#line 18 "pure2-bugfix-for-unbraced-function-expression.cpp2"
59+
cpp2::i32 y {0};
60+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pure2-bugfix-for-unbraced-function-expression.cpp2... ok (all Cpp2, passes safety checks)
2+

source/parse.h

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5335,12 +5335,32 @@ class parser
53355335
!decl->has_name()
53365336
&& "ICE: declaration should have been unnamed"
53375337
);
5338+
auto simulate_double_semicolon = [&]() {
5339+
if (
5340+
peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is short function syntax
5341+
&& curr().type() != lexeme::LeftParen // not imediatelly called
5342+
&& curr().type() != lexeme::RightParen // not as a last argument to function
5343+
&& curr().type() != lexeme::Comma // not as first or in-the-middle, function argument
5344+
&& curr().type() != lexeme::Greater // not as the last argument to template
5345+
&& curr().type() != lexeme::RightBracket // not as the last index argument
5346+
&& curr() != "is" // not as the argument to is
5347+
&& curr() != "as" // not as the argument to as
5348+
&& curr() != "do" // not as `for`'s `next`.
5349+
) {
5350+
// this is a fix for a short function syntax that should have double semicolon used
5351+
// (check comment in expression_statement(bool semicolon_required))
5352+
// We simulate double semicolon by moving back to single semicolon.
5353+
next(-1);
5354+
}
5355+
};
5356+
53385357
if (auto obj = std::get_if<declaration_node::an_object>(&decl->type)) {
53395358
if ((*obj)->is_wildcard()) {
53405359
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)");
53415360
next();
53425361
return {};
53435362
}
5363+
simulate_double_semicolon();
53445364
}
53455365
else if (auto func = std::get_if<declaration_node::a_function>(&decl->type)) {
53465366
if ((*func)->returns.index() == function_type_node::list) {
@@ -5359,17 +5379,7 @@ class parser
53595379
next();
53605380
return {};
53615381
}
5362-
if (
5363-
peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is short function syntax
5364-
&& curr().type() != lexeme::LeftParen // not imediatelly called
5365-
&& curr().type() != lexeme::RightParen // not as a last argument to function
5366-
&& curr().type() != lexeme::Comma // not as first or in-the-middle, function argument
5367-
) {
5368-
// this is a fix for a short function syntax that should have double semicolon used
5369-
// (check comment in expression_statement(bool semicolon_required))
5370-
// We simulate double semicolon by moving back to single semicolon.
5371-
next(-1);
5372-
}
5382+
simulate_double_semicolon();
53735383
}
53745384
else {
53755385
error("(temporary alpha limitation) an unnamed declaration at expression scope must be a function or an object");

0 commit comments

Comments
 (0)