| author | |
| committer | |
| log | 89c98e200166aa3e4f5b41859f450d1307216191 |
| tree | 7f251a8a0d46414bc63d011bbf805180f4fdba53 |
| parent | b4ffb402c082605c4b324e88120306fc8fb3cf32 |
| signature |
This is a follow-up to PR #30053 / commit 484cc15366.
The code previously did not handle `c_longdouble`, whose size depends on
the target. A `floatSignificandBits` helper function and a smoke test
were added.
Also added the missing max int value to the exhaustive `f16` test cases.5 files changed, 68 insertions(+), 61 deletions(-)
src/Sema.zig+1-9| ... | @@ -27774,15 +27774,7 @@ fn coerceExtra( | ... | @@ -27774,15 +27774,7 @@ fn coerceExtra( |
| 27774 | } | 27774 | } |
| 27775 | const int_info = inst_ty.intInfo(zcu); | 27775 | const int_info = inst_ty.intInfo(zcu); |
| 27776 | const int_precision = int_info.bits - @intFromBool(int_info.signedness == .signed); | 27776 | const int_precision = int_info.bits - @intFromBool(int_info.signedness == .signed); |
| 27777 | const float_precision: u8 = switch (dest_ty.toIntern()) { | 27777 | if (int_precision <= dest_ty.floatSignificandBits(target)) { |
| 27778 | .f16_type => 11, | ||
| 27779 | .f32_type => 24, | ||
| 27780 | .f64_type => 53, | ||
| 27781 | .f80_type => 64, | ||
| 27782 | .f128_type => 113, | ||
| 27783 | else => unreachable, | ||
| 27784 | }; | ||
| 27785 | if (int_precision <= float_precision) { | ||
| 27786 | try sema.requireRuntimeBlock(block, inst_src, null); | 27778 | try sema.requireRuntimeBlock(block, inst_src, null); |
| 27787 | return block.addTyOp(.float_from_int, dest_ty, inst); | 27779 | return block.addTyOp(.float_from_int, dest_ty, inst); |
| 27788 | } | 27780 | } |
src/Type.zig+12| ... | @@ -1936,6 +1936,18 @@ pub fn floatBits(ty: Type, target: *const Target) u16 { | ... | @@ -1936,6 +1936,18 @@ pub fn floatBits(ty: Type, target: *const Target) u16 { |
| 1936 | }; | 1936 | }; |
| 1937 | } | 1937 | } |
| 1938 | 1938 | ||
| 1939 | /// Asserts the type is a fixed-size float or comptime_float. | ||
| 1940 | pub fn floatSignificandBits(ty: Type, target: *const Target) u16 { | ||
| 1941 | return switch (ty.floatBits(target)) { | ||
| 1942 | 16 => 11, | ||
| 1943 | 32 => 24, | ||
| 1944 | 64 => 53, | ||
| 1945 | 80 => 64, | ||
| 1946 | 128 => 113, | ||
| 1947 | else => unreachable, | ||
| 1948 | }; | ||
| 1949 | } | ||
| 1950 | |||
| 1939 | /// Asserts the type is a function or a function pointer. | 1951 | /// Asserts the type is a function or a function pointer. |
| 1940 | pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type { | 1952 | pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type { |
| 1941 | return Type.fromInterned(zcu.intern_pool.funcTypeReturnType(ty.toIntern())); | 1953 | return Type.fromInterned(zcu.intern_pool.funcTypeReturnType(ty.toIntern())); |
test/behavior/cast.zig+3| ... | @@ -175,6 +175,7 @@ test "type coercion from int to float" { | ... | @@ -175,6 +175,7 @@ test "type coercion from int to float" { |
| 175 | var int: Int = std.math.minInt(Int); | 175 | var int: Int = std.math.minInt(Int); |
| 176 | while (int < std.math.maxInt(Int)) : (int += 1) | 176 | while (int < std.math.maxInt(Int)) : (int += 1) |
| 177 | try value(Float, int); | 177 | try value(Float, int); |
| 178 | try value(Float, int); // max | ||
| 178 | } | 179 | } |
| 179 | 180 | ||
| 180 | // Check that the min and max values of the integer type can safely be | 181 | // Check that the min and max values of the integer type can safely be |
| ... | @@ -202,6 +203,8 @@ test "type coercion from int to float" { | ... | @@ -202,6 +203,8 @@ test "type coercion from int to float" { |
| 202 | try check.edgeValues(f128, u113); | 203 | try check.edgeValues(f128, u113); |
| 203 | try check.edgeValues(f128, i114); | 204 | try check.edgeValues(f128, i114); |
| 204 | 205 | ||
| 206 | try check.value(c_longdouble, @as(u1, 0)); // Smoke test - size varies by target. | ||
| 207 | |||
| 205 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 208 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 206 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 209 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 207 | 210 |
test/cases/compile_errors/coerce_int_to_float.zig deleted-52| ... | @@ -1,52 +0,0 @@ | ||
| 1 | // Test that integer types above a certain size will not coerce to a float. | ||
| 2 | |||
| 3 | fn testCoerce(Float: type, Int: type) void { | ||
| 4 | var i: Int = 0; | ||
| 5 | _ = &i; | ||
| 6 | _ = @as(Float, i); | ||
| 7 | } | ||
| 8 | |||
| 9 | export fn entry() void { | ||
| 10 | testCoerce(f16, u11); // Okay | ||
| 11 | testCoerce(f16, u12); // Too big | ||
| 12 | |||
| 13 | testCoerce(f16, i12); | ||
| 14 | testCoerce(f16, i13); | ||
| 15 | |||
| 16 | testCoerce(f32, u24); | ||
| 17 | testCoerce(f32, u25); | ||
| 18 | |||
| 19 | testCoerce(f32, i25); | ||
| 20 | testCoerce(f32, i26); | ||
| 21 | |||
| 22 | testCoerce(f64, u53); | ||
| 23 | testCoerce(f64, u54); | ||
| 24 | |||
| 25 | testCoerce(f64, i54); | ||
| 26 | testCoerce(f64, i55); | ||
| 27 | |||
| 28 | testCoerce(f80, u64); | ||
| 29 | testCoerce(f80, u65); | ||
| 30 | |||
| 31 | testCoerce(f80, i65); | ||
| 32 | testCoerce(f80, i66); | ||
| 33 | |||
| 34 | testCoerce(f128, u113); | ||
| 35 | testCoerce(f128, u114); | ||
| 36 | |||
| 37 | testCoerce(f128, i114); | ||
| 38 | testCoerce(f128, i115); | ||
| 39 | } | ||
| 40 | |||
| 41 | // error | ||
| 42 | // | ||
| 43 | // :6:20: error: expected type 'f128', found 'i115' | ||
| 44 | // :6:20: error: expected type 'f128', found 'u114' | ||
| 45 | // :6:20: error: expected type 'f16', found 'i13' | ||
| 46 | // :6:20: error: expected type 'f16', found 'u12' | ||
| 47 | // :6:20: error: expected type 'f32', found 'i26' | ||
| 48 | // :6:20: error: expected type 'f32', found 'u25' | ||
| 49 | // :6:20: error: expected type 'f64', found 'i55' | ||
| 50 | // :6:20: error: expected type 'f64', found 'u54' | ||
| 51 | // :6:20: error: expected type 'f80', found 'i66' | ||
| 52 | // :6:20: error: expected type 'f80', found 'u65' | ||
test/cases/compile_errors/coerce_large_int_to_float.zig created+52| ... | @@ -0,0 +1,52 @@ | ||
| 1 | // Test that integer types above a certain size will not coerce to a float. | ||
| 2 | |||
| 3 | fn testCoerce(Float: type, Int: type) void { | ||
| 4 | var i: Int = 0; | ||
| 5 | _ = &i; | ||
| 6 | _ = @as(Float, i); | ||
| 7 | } | ||
| 8 | |||
| 9 | export fn entry() void { | ||
| 10 | testCoerce(f16, u11); // Okay | ||
| 11 | testCoerce(f16, u12); // Too big | ||
| 12 | |||
| 13 | testCoerce(f16, i12); | ||
| 14 | testCoerce(f16, i13); | ||
| 15 | |||
| 16 | testCoerce(f32, u24); | ||
| 17 | testCoerce(f32, u25); | ||
| 18 | |||
| 19 | testCoerce(f32, i25); | ||
| 20 | testCoerce(f32, i26); | ||
| 21 | |||
| 22 | testCoerce(f64, u53); | ||
| 23 | testCoerce(f64, u54); | ||
| 24 | |||
| 25 | testCoerce(f64, i54); | ||
| 26 | testCoerce(f64, i55); | ||
| 27 | |||
| 28 | testCoerce(f80, u64); | ||
| 29 | testCoerce(f80, u65); | ||
| 30 | |||
| 31 | testCoerce(f80, i65); | ||
| 32 | testCoerce(f80, i66); | ||
| 33 | |||
| 34 | testCoerce(f128, u113); | ||
| 35 | testCoerce(f128, u114); | ||
| 36 | |||
| 37 | testCoerce(f128, i114); | ||
| 38 | testCoerce(f128, i115); | ||
| 39 | } | ||
| 40 | |||
| 41 | // error | ||
| 42 | // | ||
| 43 | // :6:20: error: expected type 'f128', found 'i115' | ||
| 44 | // :6:20: error: expected type 'f128', found 'u114' | ||
| 45 | // :6:20: error: expected type 'f16', found 'i13' | ||
| 46 | // :6:20: error: expected type 'f16', found 'u12' | ||
| 47 | // :6:20: error: expected type 'f32', found 'i26' | ||
| 48 | // :6:20: error: expected type 'f32', found 'u25' | ||
| 49 | // :6:20: error: expected type 'f64', found 'i55' | ||
| 50 | // :6:20: error: expected type 'f64', found 'u54' | ||
| 51 | // :6:20: error: expected type 'f80', found 'i66' | ||
| 52 | // :6:20: error: expected type 'f80', found 'u65' | ||