From 283afb50b56fb8a2c288d2452bdf6e595a1bbb06 Mon Sep 17 00:00:00 2001 From: mlugg Date: Mon, 21 Aug 2023 02:27:11 +0100 Subject: [PATCH] AstGen: disallow '-0' integer literal The intent here is ambiguous: this resolves to the comptime_int '0', but it's likely the user meant to use a floating-point literal. Resolves: #16890 --- lib/std/math/big/int_test.zig | 13 ------------- lib/std/math/pow.zig | 4 ++-- src/AstGen.zig | 10 +++++++++- test/behavior/bitcast.zig | 2 -- test/cases/compile_errors/negative_zero_literal.zig | 11 +++++++++++ 5 files changed, 22 insertions(+), 18 deletions(-) create mode 100644 test/cases/compile_errors/negative_zero_literal.zig diff --git a/lib/std/math/big/int_test.zig b/lib/std/math/big/int_test.zig index 6f1133d21f..8215cea4d2 100644 --- a/lib/std/math/big/int_test.zig +++ b/lib/std/math/big/int_test.zig @@ -2317,17 +2317,6 @@ test "big.int bitwise xor single negative simple" { try testing.expect((try a.to(i64)) == -0x2efed94fcb932ef9); } -test "big.int bitwise xor single negative zero" { - var a = try Managed.initSet(testing.allocator, 0); - defer a.deinit(); - var b = try Managed.initSet(testing.allocator, -0); - defer b.deinit(); - - try a.bitXor(&a, &b); - - try testing.expect(a.eqlZero()); -} - test "big.int bitwise xor single negative multi-limb" { var a = try Managed.initSet(testing.allocator, -0x9849c6e7a10d66d0e4260d4846254c32); defer a.deinit(); @@ -2687,8 +2676,6 @@ test "big int popcount" { try a.set(0); try popCountTest(&a, 0, 0); try popCountTest(&a, 567, 0); - try a.set(-0); - try popCountTest(&a, 0, 0); try a.set(1); try popCountTest(&a, 1, 1); diff --git a/lib/std/math/pow.zig b/lib/std/math/pow.zig index 36aef966cf..927a4d68f4 100644 --- a/lib/std/math/pow.zig +++ b/lib/std/math/pow.zig @@ -209,8 +209,8 @@ test "math.pow.special" { try expect(pow(f32, -45, 1.0) == -45); try expect(math.isNan(pow(f32, math.nan(f32), 5.0))); try expect(math.isPositiveInf(pow(f32, -math.inf(f32), 0.5))); - try expect(math.isPositiveInf(pow(f32, -0, -0.5))); - try expect(pow(f32, -0, 0.5) == 0); + try expect(math.isPositiveInf(pow(f32, -0.0, -0.5))); + try expect(pow(f32, -0.0, 0.5) == 0); try expect(math.isNan(pow(f32, 5.0, math.nan(f32)))); try expect(math.isPositiveInf(pow(f32, 0.0, -1.0))); //expect(math.isNegativeInf(pow(f32, -0.0, -3.0))); TODO is this required? diff --git a/src/AstGen.zig b/src/AstGen.zig index 388b3c7a83..590e2a5edd 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -7270,7 +7270,15 @@ fn numberLiteral(gz: *GenZir, ri: ResultInfo, node: Ast.Node.Index, source_node: const result: Zir.Inst.Ref = switch (std.zig.parseNumberLiteral(bytes)) { .int => |num| switch (num) { - 0 => .zero, + 0 => if (sign == .positive) .zero else return astgen.failTokNotes( + num_token, + "integer literal '-0' is ambiguous", + .{}, + &.{ + try astgen.errNoteTok(num_token, "use '0' for an integer zero", .{}), + try astgen.errNoteTok(num_token, "use '-0.0' for a floating-point signed zero", .{}), + }, + ), 1 => .one, else => try gz.addInt(num), }, diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index e47d9f2f0b..4fb937fa2c 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -63,8 +63,6 @@ fn testBitCast(comptime N: usize) !void { try expect(conv_uN(N, 0) == 0); try expect(conv_iN(N, 0) == 0); - try expect(conv_iN(N, -0) == 0); - if (N > 24) { try expect(conv_uN(N, 0xf23456) == 0xf23456); } diff --git a/test/cases/compile_errors/negative_zero_literal.zig b/test/cases/compile_errors/negative_zero_literal.zig new file mode 100644 index 0000000000..4ae9931e8d --- /dev/null +++ b/test/cases/compile_errors/negative_zero_literal.zig @@ -0,0 +1,11 @@ +export fn foo() void { + _ = -0; +} + +// error +// backend=stage2 +// target=native +// +// :2:10: error: integer literal '-0' is ambiguous +// :2:10: note: use '0' for an integer zero +// :2:10: note: use '-0.0' for a floating-point signed zero