| author | |
| committer | |
| log | 711b656773fe1d3840c74a4ea1e526ae9bf589fb |
| tree | 1f996c3fec496336d7ec6041289a2eb2421f5484 |
| parent | ff7ec4efb5a6da565b92bc7b129d03680a4a72bd |
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 | 15938 | } |
| 15939 | 15939 | |
| 15940 | 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 | } |
| 15943 | 15952 | |
| 15944 | 15953 | fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -18924,6 +18933,7 @@ pub const PanicId = enum { |
| 18924 | 18933 | exact_division_remainder, |
| 18925 | 18934 | /// TODO make this call `std.builtin.panicInactiveUnionField`. |
| 18926 | 18935 | inactive_union_field, |
| 18936 | integer_part_out_of_bounds, | |
| 18927 | 18937 | }; |
| 18928 | 18938 | |
| 18929 | 18939 | fn addSafetyCheck( |
| ... | ... | @@ -19147,6 +19157,7 @@ fn safetyPanic( |
| 19147 | 19157 | .remainder_division_zero_negative => "remainder division by zero or negative value", |
| 19148 | 19158 | .exact_division_remainder => "exact division produced remainder", |
| 19149 | 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 | }; |
| 19151 | 19162 | |
| 19152 | 19163 | const msg_inst = msg_inst: { |
test/behavior/cast.zig+3| ... | ... | @@ -127,6 +127,7 @@ test "@intToFloat(f80)" { |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | fn testIntToFloat(comptime Int: type, k: Int) !void { |
| 130 | @setRuntimeSafety(false); // TODO | |
| 130 | 131 | const f = @intToFloat(f80, k); |
| 131 | 132 | const i = @floatToInt(Int, f); |
| 132 | 133 | try expect(i == k); |
| ... | ... | @@ -151,6 +152,8 @@ test "@intToFloat(f80)" { |
| 151 | 152 | test "@floatToInt" { |
| 152 | 153 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 153 | 154 | 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 | |
| 154 | 157 | |
| 155 | 158 | try testFloatToInts(); |
| 156 | 159 | comptime try testFloatToInts(); |
test/cases/safety/@floatToInt cannot fit - negative out of range.zig	+6-4| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(-129.1)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) i8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: i8) void { } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(-1.1)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) u8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: u8) void { } |
| 16 | 18 | // 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 | 1 | const std = @import("std"); |
| 2 | 2 | |
| 3 | 3 | pub fn panic(message: []const u8, stack_trace: ?*std.builtin.StackTrace) noreturn { |
| 4 | _ = message; | |
| 5 | 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 | } |
| 8 | 10 | pub fn main() !void { |
| 9 | 11 | baz(bar(256.2)); |
| ... | ... | @@ -14,5 +16,5 @@ fn bar(a: f32) u8 { |
| 14 | 16 | } |
| 15 | 17 | fn baz(_: u8) void { } |
| 16 | 18 | // run |
| 17 | // backend=stage1 | |
| 18 | // target=native | |
| \ No newline at end of file | ||
| 19 | // backend=llvm | |
| 20 | // target=native |