aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorVeikka Tuominen <git@vexu.eu>2022-11-26 22:40:43 +0200
committerVeikka Tuominen <git@vexu.eu>2022-11-29 15:47:02 +0200
commit34be5784a3f19658d15d1fb24bb07800cdb025c4 (patch)
treeab1808cfc8fdadcb682d2d5f490162f7cb15d519 /lib/std
parent1829b6eab8dc52ad2961467e23bfb36055cc8583 (diff)
downloadzig-34be5784a3f19658d15d1fb24bb07800cdb025c4.tar.gz
zig-34be5784a3f19658d15d1fb24bb07800cdb025c4.zip
parser: disallow defer and variable declaration as else branch
Closes #13658
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/zig/parse.zig28
-rw-r--r--lib/std/zig/parser_test.zig24
2 files changed, 39 insertions, 13 deletions
diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig
index 77ed67b3d2..2ae0221d8a 100644
--- a/lib/std/zig/parse.zig
+++ b/lib/std/zig/parse.zig
@@ -950,13 +950,15 @@ const Parser = struct {
/// / LabeledStatement
/// / SwitchExpr
/// / AssignExpr SEMICOLON
- fn parseStatement(p: *Parser) Error!Node.Index {
+ fn parseStatement(p: *Parser, allow_defer_var: bool) Error!Node.Index {
const comptime_token = p.eatToken(.keyword_comptime);
- const var_decl = try p.parseVarDecl();
- if (var_decl != 0) {
- try p.expectSemicolon(.expected_semi_after_decl, true);
- return var_decl;
+ if (allow_defer_var) {
+ const var_decl = try p.parseVarDecl();
+ if (var_decl != 0) {
+ try p.expectSemicolon(.expected_semi_after_decl, true);
+ return var_decl;
+ }
}
if (comptime_token) |token| {
@@ -993,7 +995,7 @@ const Parser = struct {
},
});
},
- .keyword_defer => return p.addNode(.{
+ .keyword_defer => if (allow_defer_var) return p.addNode(.{
.tag = .@"defer",
.main_token = p.nextToken(),
.data = .{
@@ -1001,7 +1003,7 @@ const Parser = struct {
.rhs = try p.expectBlockExprStatement(),
},
}),
- .keyword_errdefer => return p.addNode(.{
+ .keyword_errdefer => if (allow_defer_var) return p.addNode(.{
.tag = .@"errdefer",
.main_token = p.nextToken(),
.data = .{
@@ -1040,8 +1042,8 @@ const Parser = struct {
return null_node;
}
- fn expectStatement(p: *Parser) !Node.Index {
- const statement = try p.parseStatement();
+ fn expectStatement(p: *Parser, allow_defer_var: bool) !Node.Index {
+ const statement = try p.parseStatement(allow_defer_var);
if (statement == 0) {
return p.fail(.expected_statement);
}
@@ -1053,7 +1055,7 @@ const Parser = struct {
/// statement, returns 0.
fn expectStatementRecoverable(p: *Parser) Error!Node.Index {
while (true) {
- return p.expectStatement() catch |err| switch (err) {
+ return p.expectStatement(true) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
error.ParseError => {
p.findNextStmt(); // Try to skip to the next statement.
@@ -1114,7 +1116,7 @@ const Parser = struct {
});
};
_ = try p.parsePayload();
- const else_expr = try p.expectStatement();
+ const else_expr = try p.expectStatement(false);
return p.addNode(.{
.tag = .@"if",
.main_token = if_token,
@@ -1226,7 +1228,7 @@ const Parser = struct {
.lhs = array_expr,
.rhs = try p.addExtra(Node.If{
.then_expr = then_expr,
- .else_expr = try p.expectStatement(),
+ .else_expr = try p.expectStatement(false),
}),
},
});
@@ -1309,7 +1311,7 @@ const Parser = struct {
}
};
_ = try p.parsePayload();
- const else_expr = try p.expectStatement();
+ const else_expr = try p.expectStatement(false);
return p.addNode(.{
.tag = .@"while",
.main_token = while_token,
diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig
index e554c51f70..d2f7a15994 100644
--- a/lib/std/zig/parser_test.zig
+++ b/lib/std/zig/parser_test.zig
@@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {
);
}
+test "zig fmt: invalid else branch statement" {
+ try testError(
+ \\comptime {
+ \\ if (true) {} else var a = 0;
+ \\ if (true) {} else defer {}
+ \\}
+ \\comptime {
+ \\ while (true) {} else var a = 0;
+ \\ while (true) {} else defer {}
+ \\}
+ \\comptime {
+ \\ for ("") |_| {} else var a = 0;
+ \\ for ("") |_| {} else defer {}
+ \\}
+ , &[_]Error{
+ .expected_statement,
+ .expected_statement,
+ .expected_statement,
+ .expected_statement,
+ .expected_statement,
+ .expected_statement,
+ });
+}
+
test "zig fmt: anytype struct field" {
try testError(
\\pub const Pointer = struct {