From 00982f75e92119aac6182ab9876adfb13305d1ed Mon Sep 17 00:00:00 2001 From: Dmitry Matveyev Date: Mon, 21 Jun 2021 00:04:14 +0600 Subject: [PATCH] stage2: Remove special double ampersand parsing case (#9114) * Remove parser error on double ampersand * Add failing test for double ampersand case * Add error when encountering double ampersand in AstGen "Bit and" operator should not make sense when one of its operands is an address. * Check that 2 ampersands are adjacent to each other in source string * Remove cases of unused variables in tests --- doc/docgen.zig | 2 +- lib/std/zig/ast.zig | 4 ---- lib/std/zig/parse.zig | 4 ---- lib/std/zig/parser_test.zig | 12 ------------ lib/std/zig/tokenizer.zig | 7 ------- src/AstGen.zig | 18 +++++++++++++++++- test/stage2/test.zig | 23 +++++++++++++++++++++++ 7 files changed, 41 insertions(+), 29 deletions(-) diff --git a/doc/docgen.zig b/doc/docgen.zig index 22d8d151c1..d02987ab7e 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -999,7 +999,7 @@ fn tokenizeAndPrintRaw(docgen_tokenizer: *Tokenizer, out: anytype, source_token: .tilde, => try writeEscaped(out, src[token.loc.start..token.loc.end]), - .invalid, .invalid_ampersands, .invalid_periodasterisks => return parseError( + .invalid, .invalid_periodasterisks => return parseError( docgen_tokenizer, source_token, "syntax error", diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index 7c67e03b67..6658092398 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -280,9 +280,6 @@ pub const Tree = struct { token_tags[parse_error.token].symbol(), }); }, - .invalid_and => { - return stream.writeAll("`&&` is invalid; note that `and` is boolean AND"); - }, .invalid_bit_range => { return stream.writeAll("bit range not allowed on slices and arrays"); }, @@ -2412,7 +2409,6 @@ pub const Error = struct { extra_const_qualifier, extra_volatile_qualifier, ptr_mod_on_array_child_type, - invalid_and, invalid_bit_range, invalid_token, same_line_doc_comment, diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index cc323382cd..3390e29426 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1333,7 +1333,6 @@ const Parser = struct { .keyword_or = .{ .prec = 10, .tag = .bool_or }, .keyword_and = .{ .prec = 20, .tag = .bool_and }, - .invalid_ampersands = .{ .prec = 20, .tag = .bool_and }, .equal_equal = .{ .prec = 30, .tag = .equal_equal, .assoc = Assoc.none }, .bang_equal = .{ .prec = 30, .tag = .bang_equal, .assoc = Assoc.none }, @@ -1385,9 +1384,6 @@ const Parser = struct { .keyword_catch => { _ = try p.parsePayload(); }, - .invalid_ampersands => { - try p.warn(.invalid_and); - }, else => {}, } const rhs = try p.parseExprPrecedence(info.prec + 1); diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index f6aab4ceca..e2797a33f8 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -4930,7 +4930,6 @@ test "recovery: missing comma" { , &[_]Error{ .expected_token, .expected_token, - .invalid_and, .invalid_token, }); } @@ -4963,7 +4962,6 @@ test "recovery: missing return type" { \\test "" , &[_]Error{ .expected_return_type, - .invalid_and, .expected_block, }); } @@ -4980,7 +4978,6 @@ test "recovery: continue after invalid decl" { .expected_token, .expected_pub_item, .expected_param_list, - .invalid_and, }); try testError( \\threadlocal test "" { @@ -4989,7 +4986,6 @@ test "recovery: continue after invalid decl" { , &[_]Error{ .expected_var_decl, .expected_param_list, - .invalid_and, }); } @@ -4998,13 +4994,11 @@ test "recovery: invalid extern/inline" { \\inline test "" { a && b; } , &[_]Error{ .expected_fn, - .invalid_and, }); try testError( \\extern "" test "" { a && b; } , &[_]Error{ .expected_var_decl_or_fn, - .invalid_and, }); } @@ -5016,9 +5010,7 @@ test "recovery: missing semicolon" { \\ @foo \\} , &[_]Error{ - .invalid_and, .expected_token, - .invalid_and, .expected_token, .expected_param_list, .expected_token, @@ -5038,7 +5030,6 @@ test "recovery: invalid container members" { .expected_expr, .expected_token, .expected_container_members, - .invalid_and, .expected_token, }); } @@ -5076,7 +5067,6 @@ test "recovery: invalid global error set access" { , &[_]Error{ .expected_token, .expected_token, - .invalid_and, }); } @@ -5094,7 +5084,6 @@ test "recovery: invalid asterisk after pointer dereference" { \\} , &[_]Error{ .asterisk_after_ptr_deref, - .invalid_and, }); } @@ -5110,7 +5099,6 @@ test "recovery: missing semicolon after if, for, while stmt" { .expected_semi_or_else, .expected_semi_or_else, .expected_semi_or_else, - .invalid_and, }); } diff --git a/lib/std/zig/tokenizer.zig b/lib/std/zig/tokenizer.zig index 39d24493e9..f44b140c63 100644 --- a/lib/std/zig/tokenizer.zig +++ b/lib/std/zig/tokenizer.zig @@ -76,7 +76,6 @@ pub const Token = struct { pub const Tag = enum { invalid, - invalid_ampersands, invalid_periodasterisks, identifier, string_literal, @@ -210,7 +209,6 @@ pub const Token = struct { .container_doc_comment, => null, - .invalid_ampersands => "&&", .invalid_periodasterisks => ".**", .bang => "!", .pipe => "|", @@ -579,11 +577,6 @@ pub const Tokenizer = struct { }, .ampersand => switch (c) { - '&' => { - result.tag = .invalid_ampersands; - self.index += 1; - break; - }, '=' => { result.tag = .ampersand_equal; self.index += 1; diff --git a/src/AstGen.zig b/src/AstGen.zig index bba82f24a6..1eb12af99d 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -551,7 +551,23 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr .mul_wrap => return simpleBinOp(gz, scope, rl, node, .mulwrap), .div => return simpleBinOp(gz, scope, rl, node, .div), .mod => return simpleBinOp(gz, scope, rl, node, .mod_rem), - .bit_and => return simpleBinOp(gz, scope, rl, node, .bit_and), + .bit_and => { + const current_ampersand_token = main_tokens[node]; + if (token_tags[current_ampersand_token + 1] == .ampersand) { + const token_starts = tree.tokens.items(.start); + const current_token_offset = token_starts[current_ampersand_token]; + const next_token_offset = token_starts[current_ampersand_token + 1]; + if (current_token_offset + 1 == next_token_offset) { + return astgen.failTok( + current_ampersand_token, + "`&&` is invalid; note that `and` is boolean AND", + .{}, + ); + } + } + + return simpleBinOp(gz, scope, rl, node, .bit_and); + }, .bit_or => return simpleBinOp(gz, scope, rl, node, .bit_or), .bit_xor => return simpleBinOp(gz, scope, rl, node, .xor), diff --git a/test/stage2/test.zig b/test/stage2/test.zig index 46f5fa1ba0..32b03bb912 100644 --- a/test/stage2/test.zig +++ b/test/stage2/test.zig @@ -1565,4 +1565,27 @@ pub fn addCases(ctx: *TestContext) !void { \\} , "HeHelHellHello"); } + + { + var case = ctx.exe("double ampersand", linux_x64); + + case.addError( + \\pub const a = if (true && false) 1 else 2; + , &[_][]const u8{":1:24: error: `&&` is invalid; note that `and` is boolean AND"}); + + case.addError( + \\pub fn main() void { + \\ const a = true; + \\ const b = false; + \\ _ = a & &b; + \\} + , &[_][]const u8{":4:11: error: incompatible types: 'bool' and '*const bool'"}); + + case.addCompareOutput( + \\pub fn main() void { + \\ const b: u8 = 1; + \\ _ = &&b; + \\} + , ""); + } }