authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-16 23:16:18+03:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-07-23 15:40:11+03:00
log711b656773fe1d3840c74a4ea1e526ae9bf589fb
tree1f996c3fec496336d7ec6041289a2eb2421f5484
parentff7ec4efb5a6da565b92bc7b129d03680a4a72bd

Sema: `@floatToInt` safety


5 files changed, 33 insertions(+), 13 deletions(-)

src/Sema.zig+12-1
...@@ -15938,7 +15938,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -15938,7 +15938,16 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
15938 }15938 }
1593915939
15940 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);15940 try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
15941 return block.addTyOp(.float_to_int, dest_ty, operand);15941 const result = try block.addTyOp(.float_to_int, dest_ty, operand);
15942 if (block.wantSafety()) {
15943 const back = try block.addTyOp(.int_to_float, operand_ty, result);
15944 const diff = try block.addBinOp(.sub, operand, back);
15945 const ok_pos = try block.addBinOp(.cmp_lt, diff, try sema.addConstant(operand_ty, Value.one));
15946 const ok_neg = try block.addBinOp(.cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one));
15947 const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
15948 try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
15949 }
15950 return result;
15942}15951}
1594315952
15944fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {15953fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -18924,6 +18933,7 @@ pub const PanicId = enum {...@@ -18924,6 +18933,7 @@ pub const PanicId = enum {
18924 exact_division_remainder,18933 exact_division_remainder,
18925 /// TODO make this call `std.builtin.panicInactiveUnionField`.18934 /// TODO make this call `std.builtin.panicInactiveUnionField`.
18926 inactive_union_field,18935 inactive_union_field,
18936 integer_part_out_of_bounds,
18927};18937};
1892818938
18929fn addSafetyCheck(18939fn addSafetyCheck(
...@@ -19147,6 +19157,7 @@ fn safetyPanic(...@@ -19147,6 +19157,7 @@ fn safetyPanic(
19147 .remainder_division_zero_negative => "remainder division by zero or negative value",19157 .remainder_division_zero_negative => "remainder division by zero or negative value",
19148 .exact_division_remainder => "exact division produced remainder",19158 .exact_division_remainder => "exact division produced remainder",
19149 .inactive_union_field => "access of inactive union field",19159 .inactive_union_field => "access of inactive union field",
19160 .integer_part_out_of_bounds => "integer part of floating point value out of bounds",
19150 };19161 };
1915119162
19152 const msg_inst = msg_inst: {19163 const msg_inst = msg_inst: {
test/behavior/cast.zig+3
...@@ -127,6 +127,7 @@ test "@intToFloat(f80)" {...@@ -127,6 +127,7 @@ test "@intToFloat(f80)" {
127 }127 }
128128
129 fn testIntToFloat(comptime Int: type, k: Int) !void {129 fn testIntToFloat(comptime Int: type, k: Int) !void {
130 @setRuntimeSafety(false); // TODO
130 const f = @intToFloat(f80, k);131 const f = @intToFloat(f80, k);
131 const i = @floatToInt(Int, f);132 const i = @floatToInt(Int, f);
132 try expect(i == k);133 try expect(i == k);
...@@ -151,6 +152,8 @@ test "@intToFloat(f80)" {...@@ -151,6 +152,8 @@ test "@intToFloat(f80)" {
151test "@floatToInt" {152test "@floatToInt" {
152 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO153 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
153 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO154 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
155 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
156 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
154157
155 try testFloatToInts();158 try testFloatToInts();
156 comptime try testFloatToInts();159 comptime try testFloatToInts();
test/cases/safety/@floatToInt cannot fit - negative out of range.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(-129.1));11 baz(bar(-129.1));
...@@ -14,5 +16,5 @@ fn bar(a: f32) i8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) i8 {
14}16}
15fn baz(_: i8) void { }17fn baz(_: i8) void { }
16// run18// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/@floatToInt cannot fit - negative to unsigned.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(-1.1));11 baz(bar(-1.1));
...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
14}16}
15fn baz(_: u8) void { }17fn baz(_: u8) void { }
16// run18// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native
test/cases/safety/@floatToInt cannot fit - positive out of range.zig +6-4
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const std = @import("std");1const std = @import("std");
22
3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {3pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn {
4 _ = message;
5 _ = stack_trace;4 _ = stack_trace;
6 std.process.exit(0);5 if (std.mem.eql(u8, message, "integer part of floating point value out of bounds")) {
6 std.process.exit(0);
7 }
8 std.process.exit(1);
7}9}
8pub fn main() !void {10pub fn main() !void {
9 baz(bar(256.2));11 baz(bar(256.2));
...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {...@@ -14,5 +16,5 @@ fn bar(a: f32) u8 {
14}16}
15fn baz(_: u8) void { }17fn baz(_: u8) void { }
16// run18// run
17// backend=stage1
18// target=native
\ No newline at end of file
19// backend=llvm
20// target=native