authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-26 22:40:43+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-29 15:47:02+02:00
log34be5784a3f19658d15d1fb24bb07800cdb025c4
treeab1808cfc8fdadcb682d2d5f490162f7cb15d519
parent1829b6eab8dc52ad2961467e23bfb36055cc8583

parser: disallow defer and variable declaration as else branch

Closes #13658

2 files changed, 39 insertions(+), 13 deletions(-)

lib/std/zig/parse.zig+15-13
...@@ -950,13 +950,15 @@ const Parser = struct {...@@ -950,13 +950,15 @@ const Parser = struct {
950 /// / LabeledStatement950 /// / LabeledStatement
951 /// / SwitchExpr951 /// / SwitchExpr
952 /// / AssignExpr SEMICOLON952 /// / AssignExpr SEMICOLON
953 fn parseStatement(p: *Parser) Error!Node.Index {953 fn parseStatement(p: *Parser, allow_defer_var: bool) Error!Node.Index {
954 const comptime_token = p.eatToken(.keyword_comptime);954 const comptime_token = p.eatToken(.keyword_comptime);
955955
956 const var_decl = try p.parseVarDecl();956 if (allow_defer_var) {
957 if (var_decl != 0) {957 const var_decl = try p.parseVarDecl();
958 try p.expectSemicolon(.expected_semi_after_decl, true);958 if (var_decl != 0) {
959 return var_decl;959 try p.expectSemicolon(.expected_semi_after_decl, true);
960 return var_decl;
961 }
960 }962 }
961963
962 if (comptime_token) |token| {964 if (comptime_token) |token| {
...@@ -993,7 +995,7 @@ const Parser = struct {...@@ -993,7 +995,7 @@ const Parser = struct {
993 },995 },
994 });996 });
995 },997 },
996 .keyword_defer => return p.addNode(.{998 .keyword_defer => if (allow_defer_var) return p.addNode(.{
997 .tag = .@"defer",999 .tag = .@"defer",
998 .main_token = p.nextToken(),1000 .main_token = p.nextToken(),
999 .data = .{1001 .data = .{
...@@ -1001,7 +1003,7 @@ const Parser = struct {...@@ -1001,7 +1003,7 @@ const Parser = struct {
1001 .rhs = try p.expectBlockExprStatement(),1003 .rhs = try p.expectBlockExprStatement(),
1002 },1004 },
1003 }),1005 }),
1004 .keyword_errdefer => return p.addNode(.{1006 .keyword_errdefer => if (allow_defer_var) return p.addNode(.{
1005 .tag = .@"errdefer",1007 .tag = .@"errdefer",
1006 .main_token = p.nextToken(),1008 .main_token = p.nextToken(),
1007 .data = .{1009 .data = .{
...@@ -1040,8 +1042,8 @@ const Parser = struct {...@@ -1040,8 +1042,8 @@ const Parser = struct {
1040 return null_node;1042 return null_node;
1041 }1043 }
10421044
1043 fn expectStatement(p: *Parser) !Node.Index {1045 fn expectStatement(p: *Parser, allow_defer_var: bool) !Node.Index {
1044 const statement = try p.parseStatement();1046 const statement = try p.parseStatement(allow_defer_var);
1045 if (statement == 0) {1047 if (statement == 0) {
1046 return p.fail(.expected_statement);1048 return p.fail(.expected_statement);
1047 }1049 }
...@@ -1053,7 +1055,7 @@ const Parser = struct {...@@ -1053,7 +1055,7 @@ const Parser = struct {
1053 /// statement, returns 0.1055 /// statement, returns 0.
1054 fn expectStatementRecoverable(p: *Parser) Error!Node.Index {1056 fn expectStatementRecoverable(p: *Parser) Error!Node.Index {
1055 while (true) {1057 while (true) {
1056 return p.expectStatement() catch |err| switch (err) {1058 return p.expectStatement(true) catch |err| switch (err) {
1057 error.OutOfMemory => return error.OutOfMemory,1059 error.OutOfMemory => return error.OutOfMemory,
1058 error.ParseError => {1060 error.ParseError => {
1059 p.findNextStmt(); // Try to skip to the next statement.1061 p.findNextStmt(); // Try to skip to the next statement.
...@@ -1114,7 +1116,7 @@ const Parser = struct {...@@ -1114,7 +1116,7 @@ const Parser = struct {
1114 });1116 });
1115 };1117 };
1116 _ = try p.parsePayload();1118 _ = try p.parsePayload();
1117 const else_expr = try p.expectStatement();1119 const else_expr = try p.expectStatement(false);
1118 return p.addNode(.{1120 return p.addNode(.{
1119 .tag = .@"if",1121 .tag = .@"if",
1120 .main_token = if_token,1122 .main_token = if_token,
...@@ -1226,7 +1228,7 @@ const Parser = struct {...@@ -1226,7 +1228,7 @@ const Parser = struct {
1226 .lhs = array_expr,1228 .lhs = array_expr,
1227 .rhs = try p.addExtra(Node.If{1229 .rhs = try p.addExtra(Node.If{
1228 .then_expr = then_expr,1230 .then_expr = then_expr,
1229 .else_expr = try p.expectStatement(),1231 .else_expr = try p.expectStatement(false),
1230 }),1232 }),
1231 },1233 },
1232 });1234 });
...@@ -1309,7 +1311,7 @@ const Parser = struct {...@@ -1309,7 +1311,7 @@ const Parser = struct {
1309 }1311 }
1310 };1312 };
1311 _ = try p.parsePayload();1313 _ = try p.parsePayload();
1312 const else_expr = try p.expectStatement();1314 const else_expr = try p.expectStatement(false);
1313 return p.addNode(.{1315 return p.addNode(.{
1314 .tag = .@"while",1316 .tag = .@"while",
1315 .main_token = while_token,1317 .main_token = while_token,
lib/std/zig/parser_test.zig+24
...@@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {...@@ -4233,6 +4233,30 @@ test "zig fmt: remove newlines surrounding doc comment within container decl" {
4233 );4233 );
4234}4234}
42354235
4236test "zig fmt: invalid else branch statement" {
4237 try testError(
4238 \\comptime {
4239 \\ if (true) {} else var a = 0;
4240 \\ if (true) {} else defer {}
4241 \\}
4242 \\comptime {
4243 \\ while (true) {} else var a = 0;
4244 \\ while (true) {} else defer {}
4245 \\}
4246 \\comptime {
4247 \\ for ("") |_| {} else var a = 0;
4248 \\ for ("") |_| {} else defer {}
4249 \\}
4250 , &[_]Error{
4251 .expected_statement,
4252 .expected_statement,
4253 .expected_statement,
4254 .expected_statement,
4255 .expected_statement,
4256 .expected_statement,
4257 });
4258}
4259
4236test "zig fmt: anytype struct field" {4260test "zig fmt: anytype struct field" {
4237 try testError(4261 try testError(
4238 \\pub const Pointer = struct {4262 \\pub const Pointer = struct {