diff --git a/lib/compiler/aro/aro/Compilation.zig b/lib/compiler/aro/aro/Compilation.zig index d6b9b9178012..5ad7009c2cf0 100644 --- a/lib/compiler/aro/aro/Compilation.zig +++ b/lib/compiler/aro/aro/Compilation.zig @@ -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}); } @@ -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__ \\ diff --git a/lib/compiler/aro/aro/Driver.zig b/lib/compiler/aro/aro/Driver.zig index f3d5d5a988ba..34ed917d956a 100644 --- a/lib/compiler/aro/aro/Driver.zig +++ b/lib/compiler/aro/aro/Driver.zig @@ -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= \\ Set limit on how many macro expansion traces are shown in errors (default 6) diff --git a/lib/compiler/aro/aro/char_info.zig b/lib/compiler/aro/aro/char_info.zig index c2134efa987a..a36e64f22818 100644 --- a/lib/compiler/aro/aro/char_info.zig +++ b/lib/compiler/aro/aro/char_info.zig @@ -492,7 +492,7 @@ 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; } @@ -500,7 +500,7 @@ 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; } diff --git a/lib/compiler_rt/atomics.zig b/lib/compiler_rt/atomics.zig index 77519ee9a7f2..be363677d2dd 100644 --- a/lib/compiler_rt/atomics.zig +++ b/lib/compiler_rt/atomics.zig @@ -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 { diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 0a5c3c6ca5cf..9469ef0ebf78 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -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)); diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig index 20bdba8cf796..e579697663fe 100644 --- a/lib/std/zig/Ast.zig +++ b/lib/std/zig/Ast.zig @@ -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(); @@ -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"); + }, } } @@ -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, diff --git a/lib/std/zig/Parse.zig b/lib/std/zig/Parse.zig index 369e2ef125b4..b75df737bcbb 100644 --- a/lib/std/zig/Parse.zig +++ b/lib/std/zig/Parse.zig @@ -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]; @@ -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; + + 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" diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 38d279461ec5..83f0acc9b179 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -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; diff --git a/lib/std/zig/system.zig b/lib/std/zig/system.zig index 83c798c34204..82b77b6f7855 100644 --- a/lib/std/zig/system.zig +++ b/lib/std/zig/system.zig @@ -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; @@ -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; }, @@ -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; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 04a5af8bb0a2..3d0afe3deb0c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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 => {}, @@ -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 => {}, diff --git a/src/codegen/llvm/bitcode_writer.zig b/src/codegen/llvm/bitcode_writer.zig index 0b821a32e7e1..6052ce2d7cb5 100644 --- a/src/codegen/llvm/bitcode_writer.zig +++ b/src/codegen/llvm/bitcode_writer.zig @@ -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); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index efc698c128f8..437790592a21 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -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))); diff --git a/test/cases/compile_errors/ambiguous_operator_precedence.zig b/test/cases/compile_errors/ambiguous_operator_precedence.zig new file mode 100644 index 000000000000..e6b52939da13 --- /dev/null +++ b/test/cases/compile_errors/ambiguous_operator_precedence.zig @@ -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