Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parser: add error for ambiguous operator precedence #18341

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions lib/compiler/aro/aro/Compilation.zig
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fn generateSystemDefines(comp: *Compilation, w: anytype) !void {

if (comp.langopts.gnuc_version > 0) {
try w.print("#define __GNUC__ {d}\n", .{comp.langopts.gnuc_version / 10_000});
try w.print("#define __GNUC_MINOR__ {d}\n", .{comp.langopts.gnuc_version / 100 % 100});
try w.print("#define __GNUC_MINOR__ {d}\n", .{(comp.langopts.gnuc_version / 100) % 100});
try w.print("#define __GNUC_PATCHLEVEL__ {d}\n", .{comp.langopts.gnuc_version % 100});
}

Expand Down Expand Up @@ -534,7 +534,7 @@ pub fn generateBuiltinMacros(comp: *Compilation, system_defines_mode: SystemDefi

if (system_defines_mode == .include_system_defines) {
try buf.appendSlice(
\\#define __VERSION__ "Aro
\\#define __VERSION__ "Aro
++ @import("../backend.zig").version_str ++ "\"\n" ++
\\#define __Aro__
\\
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler/aro/aro/Driver.zig
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ pub const usage =
\\ -fhosted Compilation in a hosted environment
\\ -fms-extensions Enable support for Microsoft extensions
\\ -fno-ms-extensions Disable support for Microsoft extensions
\\ -fdollars-in-identifiers
\\ -fdollars-in-identifiers
\\ Allow '$' in identifiers
\\ -fno-dollars-in-identifiers
\\ -fno-dollars-in-identifiers
\\ Disallow '$' in identifiers
\\ -fmacro-backtrace-limit=<limit>
\\ Set limit on how many macro expansion traces are shown in errors (default 6)
Expand Down
4 changes: 2 additions & 2 deletions lib/compiler/aro/aro/char_info.zig
Original file line number Diff line number Diff line change
Expand Up @@ -492,15 +492,15 @@ pub fn isXidStart(c: u21) bool {
assert(c > 0x7F);
const idx = c / 8 / tables.chunk;
const chunk: usize = if (idx < tables.trie_start.len) tables.trie_start[idx] else 0;
const offset = chunk * tables.chunk / 2 + c / 8 % tables.chunk;
const offset = chunk * tables.chunk / 2 + (c / 8) % tables.chunk;
return (tables.leaf[offset] >> (@as(u3, @intCast(c % 8)))) & 1 != 0;
}

pub fn isXidContinue(c: u21) bool {
assert(c > 0x7F);
const idx = c / 8 / tables.chunk;
const chunk: usize = if (idx < tables.trie_continue.len) tables.trie_continue[idx] else 0;
const offset = chunk * tables.chunk / 2 + c / 8 % tables.chunk;
const offset = chunk * tables.chunk / 2 + (c / 8) % tables.chunk;
return (tables.leaf[offset] >> (@as(u3, @intCast(c % 8)))) & 1 != 0;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/compiler_rt/atomics.zig
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fn wideUpdate(comptime T: type, ptr: *T, val: T, update: anytype) T {
while (true) {
const old = @as(T, @truncate((wide_old & mask) >> inner_shift));
const new = update(val, old);
const wide_new = wide_old & ~mask | (@as(WideAtomic, new) << inner_shift);
const wide_new = (wide_old & ~mask) | (@as(WideAtomic, new) << inner_shift);
if (@cmpxchgWeak(WideAtomic, wide_ptr, wide_old, wide_new, .seq_cst, .seq_cst)) |new_wide_old| {
wide_old = new_wide_old;
} else {
Expand Down
2 changes: 1 addition & 1 deletion lib/std/math/big/int.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3741,7 +3741,7 @@ fn llshl(r: []Limb, a: []const Limb, shift: usize) void {

// We only need the extra limb if the shift of the last element overflows.
// This is useful for the implementation of `shiftLeftSat`.
if (a[a.len - 1] << interior_limb_shift >> interior_limb_shift != a[a.len - 1]) {
if ((a[a.len - 1] << interior_limb_shift) >> interior_limb_shift != a[a.len - 1]) {
assert(r.len >= a.len + (shift / limb_bits) + 1);
} else {
assert(r.len >= a.len + (shift / limb_bits));
Expand Down
5 changes: 4 additions & 1 deletion lib/std/zig/Ast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,6 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
.for_input_not_captured => {
return stream.writeAll("for input is not captured");
},

.expected_token => {
const found_tag = token_tags[parse_error.token + @intFromBool(parse_error.token_is_prev)];
const expected_symbol = parse_error.extra.expected_tag.symbol();
Expand All @@ -469,6 +468,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void {
}),
}
},
.ambiguous_operator_precedence => {
return stream.writeAll("ambiguous operator precedence; use parentheses to disambiguate");
},
}
}

Expand Down Expand Up @@ -2954,6 +2956,7 @@ pub const Error = struct {
var_const_decl,
extra_for_capture,
for_input_not_captured,
ambiguous_operator_precedence,

zig_style_container,
previous_field,
Expand Down
22 changes: 22 additions & 0 deletions lib/std/zig/Parse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,8 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!Node.Index {
}

var banned_prec: i8 = -1;
var prev_op: Token.Tag = .invalid;
var prev_prec: i8 = -1;

while (true) {
const tok_tag = p.token_tags[p.tok_i];
Expand All @@ -1688,6 +1690,26 @@ fn parseExprPrecedence(p: *Parse, min_prec: i32) Error!Node.Index {
if (info.prec == banned_prec) {
return p.fail(.chained_comparison_operators);
}
if (info.prec > 0) {
if (tok_tag != prev_op and info.prec == prev_prec) blk: {
if (prev_op == .plus and tok_tag == .minus) break :blk;
if (prev_op == .minus and tok_tag == .plus) break :blk;
if (prev_op == .plus_percent and tok_tag == .minus_percent) break :blk;
if (prev_op == .minus_percent and tok_tag == .plus_percent) break :blk;
if (prev_op == .plus_pipe and tok_tag == .minus_pipe) break :blk;
if (prev_op == .minus_pipe and tok_tag == .plus_pipe) break :blk;

if (prev_op == .asterisk and tok_tag == .slash) break :blk;
if (prev_op == .slash and tok_tag == .asterisk) break :blk;
Comment on lines +1695 to +1703
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO it'd be better to allow mixing all operators with the same precedence (except maybe || and ** which could also have their precedences raised) but I'm fine with this too.


if (prev_op == .keyword_catch and tok_tag == .keyword_orelse) break :blk;
if (prev_op == .keyword_orelse and tok_tag == .keyword_catch) break :blk;

return p.fail(.ambiguous_operator_precedence);
}
prev_op = tok_tag;
prev_prec = info.prec;
}

const oper_token = p.nextToken();
// Special-case handling for "catch"
Expand Down
2 changes: 0 additions & 2 deletions lib/std/zig/parser_test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3000,9 +3000,7 @@ test "zig fmt: precedence" {
\\ (a << b) + c;
\\ a & b << c;
\\ (a & b) << c;
\\ a ^ b & c;
\\ (a ^ b) & c;
\\ a | b ^ c;
\\ (a | b) ^ c;
\\ a == b | c;
\\ (a == b) | c;
Expand Down
10 changes: 5 additions & 5 deletions lib/std/zig/system.zig
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,8 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
// Minor * 1(0),000 summed has been convention since FreeBSD 2.2 (1997)
// e.g. 492101 = 4.11-STABLE = 4.(9+2)
const major = value / 100_000;
const minor1 = value % 100_000 / 10_000; // usually 0 since 5.1
const minor2 = value % 10_000 / 1_000; // 0 before 5.1, minor version since
const minor1 = (value % 100_000) / 10_000; // usually 0 since 5.1
const minor2 = (value % 10_000) / 1_000; // 0 before 5.1, minor version since
const patch = value % 1_000;
os.version_range.semver.min = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
os.version_range.semver.max = os.version_range.semver.min;
Expand All @@ -235,8 +235,8 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
// r = 0 (*)
// p = patchlevel
const major = value / 100_000_000;
const minor = value % 100_000_000 / 1_000_000;
const patch = value % 10_000 / 100;
const minor = (value % 100_000_000) / 1_000_000;
const patch = (value % 10_000) / 100;
os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
os.version_range.semver.max = os.version_range.semver.min;
},
Expand All @@ -247,7 +247,7 @@ pub fn resolveTargetQuery(query: Target.Query) DetectError!Target {
// m = minor; odd-numbers indicate current dev branch
// p = patch
const major = value / 100_000;
const minor = value % 100_000 / 100;
const minor = (value % 100_000) / 100;
const patch = value % 100;
os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
os.version_range.semver.max = os.version_range.semver.min;
Expand Down
4 changes: 2 additions & 2 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11228,7 +11228,7 @@ fn lowerSystemVFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.E
const size: u64 = struct_type.size(ip).*;
assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
if (size % 8 > 0) {
types_buffer[types_index - 1] = try o.builder.intType(@intCast(size % 8 * 8));
types_buffer[types_index - 1] = try o.builder.intType(@intCast((size % 8) * 8));
}
},
else => {},
Expand Down Expand Up @@ -11536,7 +11536,7 @@ const ParamTypeIterator = struct {
assert((std.math.divCeil(u64, size, 8) catch unreachable) == types_index);
if (size % 8 > 0) {
types_buffer[types_index - 1] =
try it.object.builder.intType(@intCast(size % 8 * 8));
try it.object.builder.intType(@intCast((size % 8) * 8));
}
},
else => {},
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/llvm/bitcode_writer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub fn BitcodeWriter(comptime types: []const type) type {
// If input is larger than one VBR block can store
// then store vbr_bits - 1 bits and a continue bit
while (in_buffer > mask) {
try self.writeBits(in_buffer & mask | continue_bit, vbr_bits);
try self.writeBits((in_buffer & mask) | continue_bit, vbr_bits);
in_buffer >>= @intCast(vbr_bits - 1);
}

Expand Down
2 changes: 1 addition & 1 deletion test/behavior/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ fn testThreeExprInARow(f: bool, t: bool) !void {
try assertFalse(9 << 1 << 2 != 9 << 3);
try assertFalse(90 >> 1 >> 2 != 90 >> 3);
try assertFalse(100 - 1 + 1000 != 1099);
try assertFalse(5 * 4 / 2 % 3 != 1);
try assertFalse((5 * 4 / 2) % 3 != 1);
try assertFalse(@as(i32, @as(i32, 5)) != 5);
try assertFalse(!!false);
try assertFalse(@as(i32, 7) != --(@as(i32, 7)));
Expand Down
14 changes: 14 additions & 0 deletions test/cases/compile_errors/ambiguous_operator_precedence.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const std = @import("std");

test {
var x: u16 = 0xFF00;
const y: u8 = 0xFF;
x = x | y & 0x0F;
try std.testing.expect(x == 0xFF0F);
}

// error
// backend=stage2
// target=native
//
// :6:15: error: ambiguous operator precedence; use parentheses to disambiguate
Loading