authorgravatar for justus@klausecker.deJustus Klausecker <justus@klausecker.de> 2026-06-29 22:12:49+02:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-17 09:43:53+01:00
log274949fdbb7a98d374d5e994110dbfd639c70acf
tree72c4009cdeee36154dd0d456a7f2cb656a7c852f
parent919a5dd8ce8c64d7b9a924ea12215fc5f0227e51
signaturelock-open Commit is signed but in an unrecognized format.

wasm: lower `packed union` backing integer type correctly

`IntType.fromType` would previously set the signedness of any backing int of a `packed union` to `unsigned` unconditionally which caused comparisons of packed unions with large, signed backing integers to miscompile. Packed unions are now lowered correctly to their actual backing int type.

3 files changed, 30 insertions(+), 12 deletions(-)

src/codegen/wasm/CodeGen.zig+4-12
...@@ -2527,18 +2527,10 @@ const IntType = struct {...@@ -2527,18 +2527,10 @@ const IntType = struct {
2527 .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable,2527 .f16, .f32, .f64, .f80, .f128, .c_longdouble => unreachable,
2528 .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable,2528 .anyopaque, .void, .type, .comptime_int, .comptime_float, .noreturn, .null, .undefined, .enum_literal, .generic_poison => unreachable,
2529 },2529 },
2530 .struct_type => {2530 .enum_type,
2531 const loaded_struct = ip.loadStructType(ty_index);2531 .struct_type,
2532 switch (loaded_struct.layout) {2532 .union_type,
2533 .auto, .@"extern" => unreachable,2533 => ty_index = Type.fromInterned(ty_index).backingIntType(zcu).toIntern(),
2534 .@"packed" => ty_index = loaded_struct.packed_backing_int_type,
2535 }
2536 },
2537 .union_type => return switch (ip.loadUnionType(ty_index).layout) {
2538 .auto, .@"extern" => unreachable,
2539 .@"packed" => .{ .is_signed = false, .bits = @intCast(ty.bitSize(zcu)) },
2540 },
2541 .enum_type => ty_index = ip.loadEnumType(ty_index).int_tag_type,
2542 .error_set_type, .inferred_error_set_type => return .{ .is_signed = false, .bits = zcu.errorSetBits() },2534 .error_set_type, .inferred_error_set_type => return .{ .is_signed = false, .bits = zcu.errorSetBits() },
2543 else => unreachable,2535 else => unreachable,
2544 };2536 };
test/behavior/packed-struct.zig+13
...@@ -1261,3 +1261,16 @@ test "convert from/to backing int" {...@@ -1261,3 +1261,16 @@ test "convert from/to backing int" {
1261 try S.doTheTest(.{ .a = 123, .b = .y, .c = 0.23 });1261 try S.doTheTest(.{ .a = 123, .b = .y, .c = 0.23 });
1262 try comptime S.doTheTest(.{ .a = 123, .b = .y, .c = 0.23 });1262 try comptime S.doTheTest(.{ .a = 123, .b = .y, .c = 0.23 });
1263}1263}
1264
1265test "equality with wide backing integer" {
1266 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35982
1267
1268 const S = packed struct(i200) {
1269 x: u200,
1270 fn doTheTest(s: @This(), int: i200) !void {
1271 try expect(s == @as(@This(), @bitCast(int)));
1272 }
1273 };
1274 try S.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
1275 try comptime S.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
1276}
test/behavior/packed-union.zig+13
...@@ -241,3 +241,16 @@ test "convert from/to backing int" {...@@ -241,3 +241,16 @@ test "convert from/to backing int" {
241 try U.doTheTest(.{ .a = 123 });241 try U.doTheTest(.{ .a = 123 });
242 try comptime U.doTheTest(.{ .a = 123 });242 try comptime U.doTheTest(.{ .a = 123 });
243}243}
244
245test "equality with wide backing integer" {
246 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/35982
247
248 const U = packed union(i200) {
249 x: u200,
250 fn doTheTest(s: @This(), int: i200) !void {
251 try expect(s == @as(@This(), @bitCast(int)));
252 }
253 };
254 try U.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
255 try comptime U.doTheTest(.{ .x = (1 << 200) - 1 }, -1);
256}