authorgravatar for 19855629+SuperAuguste@users.noreply.github.comSuperAuguste <19855629+SuperAuguste@users.noreply.github.com> 2023-12-10 05:10:58-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-29 13:09:17-08:00
loga479fd313248a55273a17de5f9af6b82abdb0be4
treebef7ec6d1fd27407f18f19f3dde973ff639da507
parentf4f8036ec048daa072c7caa72edd320c85bf426c

Fix some comptime packed struct issues

Co-authored-by: Veikka Tuominen <git@vexu.eu>

5 files changed, 75 insertions(+), 10 deletions(-)

src/Sema.zig+9-1
...@@ -30341,6 +30341,7 @@ fn storePtrVal(...@@ -30341,6 +30341,7 @@ fn storePtrVal(
30341 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);30341 var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
30342 try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);30342 try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);
3034330343
30344 try sema.resolveTypeLayout(operand_ty);
30344 switch (mut_kit.pointee) {30345 switch (mut_kit.pointee) {
30345 .opv => {},30346 .opv => {},
30346 .direct => |val_ptr| {30347 .direct => |val_ptr| {
...@@ -30355,6 +30356,7 @@ fn storePtrVal(...@@ -30355,6 +30356,7 @@ fn storePtrVal(
30355 val_ptr.* = Value.fromInterned((try operand_val.intern(operand_ty, mod)));30356 val_ptr.* = Value.fromInterned((try operand_val.intern(operand_ty, mod)));
30356 },30357 },
30357 .reinterpret => |reinterpret| {30358 .reinterpret => |reinterpret| {
30359 try sema.resolveTypeLayout(mut_kit.ty);
30358 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));30360 const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
30359 const buffer = try sema.gpa.alloc(u8, abi_size);30361 const buffer = try sema.gpa.alloc(u8, abi_size);
30360 defer sema.gpa.free(buffer);30362 defer sema.gpa.free(buffer);
...@@ -31373,6 +31375,9 @@ fn bitCastUnionFieldVal(...@@ -31373,6 +31375,9 @@ fn bitCastUnionFieldVal(
31373 const mod = sema.mod;31375 const mod = sema.mod;
31374 if (old_ty.eql(field_ty, mod)) return val;31376 if (old_ty.eql(field_ty, mod)) return val;
3137531377
31378 // Bitcasting a union field value requires that that field's layout be known
31379 try sema.resolveTypeLayout(field_ty);
31380
31376 const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));31381 const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
31377 const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod));31382 const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod));
31378 const endian = mod.getTarget().cpu.arch.endian();31383 const endian = mod.getTarget().cpu.arch.endian();
...@@ -35301,7 +35306,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -35301,7 +35306,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
35301 },35306 },
35302 },35307 },
35303 .un => |un| {35308 .un => |un| {
35304 const resolved_tag = (try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern();35309 const resolved_tag = if (un.tag == .none)
35310 .none
35311 else
35312 (try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern();
35305 const resolved_val = (try sema.resolveLazyValue(Value.fromInterned(un.val))).toIntern();35313 const resolved_val = (try sema.resolveLazyValue(Value.fromInterned(un.val))).toIntern();
35306 return if (resolved_tag == un.tag and resolved_val == un.val)35314 return if (resolved_tag == un.tag and resolved_val == un.val)
35307 val35315 val
src/type.zig+6-2
...@@ -1607,8 +1607,12 @@ pub const Type = struct {...@@ -1607,8 +1607,12 @@ pub const Type = struct {
1607 .type_info => unreachable,1607 .type_info => unreachable,
1608 },1608 },
1609 .struct_type => |struct_type| {1609 .struct_type => |struct_type| {
1610 if (struct_type.layout == .Packed) {1610 const is_packed = struct_type.layout == .Packed;
1611 if (opt_sema) |sema| try sema.resolveTypeLayout(ty);1611 if (opt_sema) |sema| {
1612 try sema.resolveTypeFields(ty);
1613 if (is_packed) try sema.resolveTypeLayout(ty);
1614 }
1615 if (is_packed) {
1612 return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema);1616 return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema);
1613 }1617 }
1614 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;1618 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
src/value.zig+14-7
...@@ -847,16 +847,23 @@ pub const Value = struct {...@@ -847,16 +847,23 @@ pub const Value = struct {
847 // and Extern is handled in non-packed writeToMemory.847 // and Extern is handled in non-packed writeToMemory.
848 assert(struct_type.layout == .Packed);848 assert(struct_type.layout == .Packed);
849 var bits: u16 = 0;849 var bits: u16 = 0;
850 const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
851 for (0..struct_type.field_types.len) |i| {850 for (0..struct_type.field_types.len) |i| {
851 const field_val = switch (val.ip_index) {
852 .none => switch (val.tag()) {
853 .bytes => unreachable,
854 .aggregate => val.castTag(.aggregate).?.data[i],
855 .repeated => val.castTag(.repeated).?.data,
856 else => unreachable,
857 },
858 else => Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
859 .bytes => unreachable,
860 .elems => |elems| elems[i],
861 .repeated_elem => |elem| elem,
862 }),
863 };
852 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);864 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
853 const field_bits: u16 = @intCast(field_ty.bitSize(mod));865 const field_bits: u16 = @intCast(field_ty.bitSize(mod));
854 const field_val = switch (storage) {866 try field_val.writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
855 .bytes => unreachable,
856 .elems => |elems| elems[i],
857 .repeated_elem => |elem| elem,
858 };
859 try Value.fromInterned(field_val).writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
860 bits += field_bits;867 bits += field_bits;
861 }868 }
862 },869 },
test/behavior/packed-struct.zig+19
...@@ -1229,3 +1229,22 @@ test "load flag from packed struct in union" {...@@ -1229,3 +1229,22 @@ test "load flag from packed struct in union" {
1229 try X.b(&x);1229 try X.b(&x);
1230 comptime if (@sizeOf(A) != 1) unreachable;1230 comptime if (@sizeOf(A) != 1) unreachable;
1231}1231}
1232
1233test "bitcasting a packed struct at comptime and using the result" {
1234 comptime {
1235 const Struct = packed struct {
1236 x: packed union { a: u63, b: i32 },
1237 y: u1,
1238
1239 pub fn bitcast(fd: u64) @This() {
1240 return @bitCast(fd);
1241 }
1242
1243 pub fn cannotReach(_: @This()) i32 {
1244 return 0;
1245 }
1246 };
1247
1248 _ = Struct.bitcast(@as(u64, 0)).cannotReach();
1249 }
1250}
test/behavior/packed-union.zig+27
...@@ -8,6 +8,11 @@ test "flags in packed union" {...@@ -8,6 +8,11 @@ test "flags in packed union" {
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1010
11 try testFlagsInPackedUnion();
12 try comptime testFlagsInPackedUnion();
13}
14
15fn testFlagsInPackedUnion() !void {
11 const FlagBits = packed struct(u8) {16 const FlagBits = packed struct(u8) {
12 enable_1: bool = false,17 enable_1: bool = false,
13 enable_2: bool = false,18 enable_2: bool = false,
...@@ -45,6 +50,11 @@ test "flags in packed union at offset" {...@@ -45,6 +50,11 @@ test "flags in packed union at offset" {
45 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
46 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;51 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
4752
53 try testFlagsInPackedUnionAtOffset();
54 try comptime testFlagsInPackedUnionAtOffset();
55}
56
57fn testFlagsInPackedUnionAtOffset() !void {
48 const FlagBits = packed union {58 const FlagBits = packed union {
49 base_flags: packed union {59 base_flags: packed union {
50 flags: packed struct(u4) {60 flags: packed struct(u4) {
...@@ -90,6 +100,11 @@ test "packed union in packed struct" {...@@ -90,6 +100,11 @@ test "packed union in packed struct" {
90 // Originally reported at https://github.com/ziglang/zig/issues/16581100 // Originally reported at https://github.com/ziglang/zig/issues/16581
91 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;101 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
92102
103 try testPackedUnionInPackedStruct();
104 try comptime testPackedUnionInPackedStruct();
105}
106
107fn testPackedUnionInPackedStruct() !void {
93 const ReadRequest = packed struct { key: i32 };108 const ReadRequest = packed struct { key: i32 };
94 const RequestType = enum {109 const RequestType = enum {
95 read,110 read,
...@@ -142,3 +157,15 @@ test "packed union initialized with a runtime value" {...@@ -142,3 +157,15 @@ test "packed union initialized with a runtime value" {
142 } };157 } };
143 try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);158 try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);
144}159}
160
161test "assigning to non-active field at comptime" {
162 comptime {
163 const FlagBits = packed union {
164 flags: packed struct {},
165 bits: packed struct {},
166 };
167
168 var test_bits: FlagBits = .{ .flags = .{} };
169 test_bits.bits = .{};
170 }
171}