authorgravatar for jay@jayschwa.netJay Petacat <jay@jayschwa.net> 2026-01-21 22:57:32-07:00
committergravatar for jay@jayschwa.netJay Petacat <jay@jayschwa.net> 2026-03-11 10:24:42-06:00
log89c98e200166aa3e4f5b41859f450d1307216191
tree7f251a8a0d46414bc63d011bbf805180f4fdba53
parentb4ffb402c082605c4b324e88120306fc8fb3cf32
signaturebadge-check Signed by SSH key SHA256:gFsluxqxLX9Aks7x0PXTsmNb7kH6i2dF38wwPoX4sZ4

Sema: fix integer coercion to `c_longdouble`

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}
19381938
1939/// Asserts the type is a fixed-size float or comptime_float.
1940pub 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.
1940pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type {1952pub 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 }
179180
180 // Check that the min and max values of the integer type can safely be181 // 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);
204205
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;
207210
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
3fn testCoerce(Float: type, Int: type) void {
4 var i: Int = 0;
5 _ = &i;
6 _ = @as(Float, i);
7}
8
9export 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
3fn testCoerce(Float: type, Int: type) void {
4 var i: Int = 0;
5 _ = &i;
6 _ = @as(Float, i);
7}
8
9export 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'