mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Fix some comptime packed struct issues
Co-authored-by: Veikka Tuominen <git@vexu.eu>
This commit is contained in:
parent
f4f8036ec0
commit
a479fd3132
10
src/Sema.zig
10
src/Sema.zig
@ -30341,6 +30341,7 @@ fn storePtrVal(
|
||||
var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
|
||||
try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);
|
||||
|
||||
try sema.resolveTypeLayout(operand_ty);
|
||||
switch (mut_kit.pointee) {
|
||||
.opv => {},
|
||||
.direct => |val_ptr| {
|
||||
@ -30355,6 +30356,7 @@ fn storePtrVal(
|
||||
val_ptr.* = Value.fromInterned((try operand_val.intern(operand_ty, mod)));
|
||||
},
|
||||
.reinterpret => |reinterpret| {
|
||||
try sema.resolveTypeLayout(mut_kit.ty);
|
||||
const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
|
||||
const buffer = try sema.gpa.alloc(u8, abi_size);
|
||||
defer sema.gpa.free(buffer);
|
||||
@ -31373,6 +31375,9 @@ fn bitCastUnionFieldVal(
|
||||
const mod = sema.mod;
|
||||
if (old_ty.eql(field_ty, mod)) return val;
|
||||
|
||||
// Bitcasting a union field value requires that that field's layout be known
|
||||
try sema.resolveTypeLayout(field_ty);
|
||||
|
||||
const old_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
|
||||
const field_size = try sema.usizeCast(block, src, field_ty.abiSize(mod));
|
||||
const endian = mod.getTarget().cpu.arch.endian();
|
||||
@ -35301,7 +35306,10 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
|
||||
},
|
||||
},
|
||||
.un => |un| {
|
||||
const resolved_tag = (try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern();
|
||||
const resolved_tag = if (un.tag == .none)
|
||||
.none
|
||||
else
|
||||
(try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern();
|
||||
const resolved_val = (try sema.resolveLazyValue(Value.fromInterned(un.val))).toIntern();
|
||||
return if (resolved_tag == un.tag and resolved_val == un.val)
|
||||
val
|
||||
|
||||
@ -1607,8 +1607,12 @@ pub const Type = struct {
|
||||
.type_info => unreachable,
|
||||
},
|
||||
.struct_type => |struct_type| {
|
||||
if (struct_type.layout == .Packed) {
|
||||
if (opt_sema) |sema| try sema.resolveTypeLayout(ty);
|
||||
const is_packed = struct_type.layout == .Packed;
|
||||
if (opt_sema) |sema| {
|
||||
try sema.resolveTypeFields(ty);
|
||||
if (is_packed) try sema.resolveTypeLayout(ty);
|
||||
}
|
||||
if (is_packed) {
|
||||
return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema);
|
||||
}
|
||||
return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
|
||||
|
||||
@ -847,16 +847,23 @@ pub const Value = struct {
|
||||
// and Extern is handled in non-packed writeToMemory.
|
||||
assert(struct_type.layout == .Packed);
|
||||
var bits: u16 = 0;
|
||||
const storage = ip.indexToKey(val.toIntern()).aggregate.storage;
|
||||
for (0..struct_type.field_types.len) |i| {
|
||||
const field_val = switch (val.ip_index) {
|
||||
.none => switch (val.tag()) {
|
||||
.bytes => unreachable,
|
||||
.aggregate => val.castTag(.aggregate).?.data[i],
|
||||
.repeated => val.castTag(.repeated).?.data,
|
||||
else => unreachable,
|
||||
},
|
||||
else => Value.fromInterned(switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
|
||||
.bytes => unreachable,
|
||||
.elems => |elems| elems[i],
|
||||
.repeated_elem => |elem| elem,
|
||||
}),
|
||||
};
|
||||
const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
|
||||
const field_bits: u16 = @intCast(field_ty.bitSize(mod));
|
||||
const field_val = switch (storage) {
|
||||
.bytes => unreachable,
|
||||
.elems => |elems| elems[i],
|
||||
.repeated_elem => |elem| elem,
|
||||
};
|
||||
try Value.fromInterned(field_val).writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
|
||||
try field_val.writeToPackedMemory(field_ty, mod, buffer, bit_offset + bits);
|
||||
bits += field_bits;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1229,3 +1229,22 @@ test "load flag from packed struct in union" {
|
||||
try X.b(&x);
|
||||
comptime if (@sizeOf(A) != 1) unreachable;
|
||||
}
|
||||
|
||||
test "bitcasting a packed struct at comptime and using the result" {
|
||||
comptime {
|
||||
const Struct = packed struct {
|
||||
x: packed union { a: u63, b: i32 },
|
||||
y: u1,
|
||||
|
||||
pub fn bitcast(fd: u64) @This() {
|
||||
return @bitCast(fd);
|
||||
}
|
||||
|
||||
pub fn cannotReach(_: @This()) i32 {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
_ = Struct.bitcast(@as(u64, 0)).cannotReach();
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,11 @@ test "flags in packed union" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
try testFlagsInPackedUnion();
|
||||
try comptime testFlagsInPackedUnion();
|
||||
}
|
||||
|
||||
fn testFlagsInPackedUnion() !void {
|
||||
const FlagBits = packed struct(u8) {
|
||||
enable_1: bool = false,
|
||||
enable_2: bool = false,
|
||||
@ -45,6 +50,11 @@ test "flags in packed union at offset" {
|
||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
try testFlagsInPackedUnionAtOffset();
|
||||
try comptime testFlagsInPackedUnionAtOffset();
|
||||
}
|
||||
|
||||
fn testFlagsInPackedUnionAtOffset() !void {
|
||||
const FlagBits = packed union {
|
||||
base_flags: packed union {
|
||||
flags: packed struct(u4) {
|
||||
@ -90,6 +100,11 @@ test "packed union in packed struct" {
|
||||
// Originally reported at https://github.com/ziglang/zig/issues/16581
|
||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||
|
||||
try testPackedUnionInPackedStruct();
|
||||
try comptime testPackedUnionInPackedStruct();
|
||||
}
|
||||
|
||||
fn testPackedUnionInPackedStruct() !void {
|
||||
const ReadRequest = packed struct { key: i32 };
|
||||
const RequestType = enum {
|
||||
read,
|
||||
@ -142,3 +157,15 @@ test "packed union initialized with a runtime value" {
|
||||
} };
|
||||
try std.testing.expect((ID{ .value = id.value }).fields.timestamp == timestamp);
|
||||
}
|
||||
|
||||
test "assigning to non-active field at comptime" {
|
||||
comptime {
|
||||
const FlagBits = packed union {
|
||||
flags: packed struct {},
|
||||
bits: packed struct {},
|
||||
};
|
||||
|
||||
var test_bits: FlagBits = .{ .flags = .{} };
|
||||
test_bits.bits = .{};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user