Skip to content

Commit c1f3439

Browse files
authored
fix(parse): allow (to omit) semicolon after _unnamed-declaration_ (#479)
1 parent cff231c commit c1f3439

6 files changed

+96
-11
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
return :i32 = 0;
12+
}
13+
14+
x :== :i32 = 0;
15+
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: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
2+
#define CPP2_IMPORT_STD Yes
3+
4+
//=== Cpp2 type declarations ====================================================
5+
6+
7+
#include "cpp2util.h"
8+
9+
#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2"
10+
class t;
11+
#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2"
12+
13+
14+
//=== Cpp2 type definitions and function declarations ===========================
15+
16+
#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2"
17+
class t {
18+
#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2"
19+
public: auto operator[](auto const& f) const& -> void;
20+
public: t() = default;
21+
public: t(t const&) = delete; /* No 'that' constructor, suppress copy */
22+
public: auto operator=(t const&) -> void = delete;
23+
24+
#line 3 "pure2-bugfix-for-unbraced-function-expression.cpp2"
25+
};
26+
27+
[[nodiscard]] auto main() -> int;
28+
29+
#line 14 "pure2-bugfix-for-unbraced-function-expression.cpp2"
30+
auto inline constexpr x = cpp2::i32{0};
31+
extern cpp2::i32 y;
32+
33+
//=== Cpp2 function definitions =================================================
34+
35+
#line 1 "pure2-bugfix-for-unbraced-function-expression.cpp2"
36+
37+
#line 2 "pure2-bugfix-for-unbraced-function-expression.cpp2"
38+
auto t::operator[](auto const& f) const& -> void{}
39+
40+
#line 5 "pure2-bugfix-for-unbraced-function-expression.cpp2"
41+
[[nodiscard]] auto main() -> int{
42+
{
43+
auto const& x = t();
44+
#line 6 "pure2-bugfix-for-unbraced-function-expression.cpp2"
45+
{CPP2_ASSERT_IN_BOUNDS(x, []() mutable -> auto { return 0; }); }
46+
}
47+
{
48+
auto const& x = t();
49+
#line 7 "pure2-bugfix-for-unbraced-function-expression.cpp2"
50+
{CPP2_ASSERT_IN_BOUNDS(x, []() mutable -> auto { return 0; }); }
51+
}
52+
53+
#line 9 "pure2-bugfix-for-unbraced-function-expression.cpp2"
54+
cpp2::Default.expects(!((cpp2::is<int>([]() mutable -> void { 0; }))), "");
55+
56+
return cpp2::i32{0};
57+
}
58+
59+
#line 15 "pure2-bugfix-for-unbraced-function-expression.cpp2"
60+
cpp2::i32 y {0};
61+
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: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5507,6 +5507,7 @@ class parser
55075507
!decl->has_name()
55085508
&& "ICE: declaration should have been unnamed"
55095509
);
5510+
55105511
if (auto obj = std::get_if<declaration_node::an_object>(&decl->type)) {
55115512
if ((*obj)->is_wildcard()) {
55125513
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)");
@@ -5531,24 +5532,30 @@ class parser
55315532
next();
55325533
return {};
55335534
}
5534-
if (
5535-
peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is short function syntax
5536-
&& curr().type() != lexeme::LeftParen // not imediatelly called
5537-
&& curr().type() != lexeme::RightParen // not as a last argument to function
5538-
&& curr().type() != lexeme::Comma // not as first or in-the-middle, function argument
5539-
) {
5540-
// this is a fix for a short function syntax that should have double semicolon used
5541-
// (check comment in expression_statement(bool semicolon_required))
5542-
// We simulate double semicolon by moving back to single semicolon.
5543-
next(-1);
5544-
}
55455535
}
55465536
else {
55475537
error("(temporary alpha limitation) an unnamed declaration at expression scope must be a function or an object");
55485538
next();
55495539
return {};
55505540
}
55515541

5542+
if (
5543+
peek(-1) && peek(-1)->type() != lexeme::RightBrace // it is not a braced function expression
5544+
&& curr().type() != lexeme::LeftParen // not imediatelly called
5545+
&& curr().type() != lexeme::RightParen // not as a last argument to function
5546+
&& curr().type() != lexeme::Comma // not as first or in-the-middle, function argument
5547+
&& curr().type() != lexeme::Greater // not as the last argument to template
5548+
&& curr().type() != lexeme::RightBracket // not as the last index argument
5549+
&& curr() != "is" // not as the argument to is
5550+
&& curr() != "as" // not as the argument to as
5551+
&& curr() != "do" // not as `for`'s `next`.
5552+
) {
5553+
// this is a fix for a short function syntax that should have double semicolon used
5554+
// (check comment in expression_statement(bool semicolon_required))
5555+
// We simulate double semicolon by moving back to single semicolon.
5556+
next(-1);
5557+
}
5558+
55525559
n->expr = std::move(decl);
55535560
return n;
55545561
}

0 commit comments

Comments
 (0)