| author | |
| committer | |
| log | a479fd313248a55273a17de5f9af6b82abdb0be4 |
| tree | bef7ec6d1fd27407f18f19f3dde973ff639da507 |
| parent | f4f8036ec048daa072c7caa72edd320c85bf426c |
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); |
| 30343 | 30343 | ||
| 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; |
| 31375 | 31377 | ||
| 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 | val | 35315 | 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 | |||
| 1233 | test "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; |
| 10 | 10 | ||
| 11 | try testFlagsInPackedUnion(); | ||
| 12 | try comptime testFlagsInPackedUnion(); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn 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; |
| 47 | 52 | ||
| 53 | try testFlagsInPackedUnionAtOffset(); | ||
| 54 | try comptime testFlagsInPackedUnionAtOffset(); | ||
| 55 | } | ||
| 56 | |||
| 57 | fn 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/16581 | 100 | // 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; |
| 92 | 102 | ||
| 103 | try testPackedUnionInPackedStruct(); | ||
| 104 | try comptime testPackedUnionInPackedStruct(); | ||
| 105 | } | ||
| 106 | |||
| 107 | fn 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 | |||
| 161 | test "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 | } |