authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-07-29 10:36:31+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-07-29 15:52:19+01:00
logb1dcf2b149c55cf8bc53cd9b9bdb707a0003e93f
tree13aae920d7eed832a2ddf99d037e43045d52250a
parenta8888afcc07479bf779105f977597b29aea3c28f
signaturelock-open Commit is signed but in an unrecognized format.

Sema: fix comptime-known union initialization with OPV field

The previous commit uncovered this existing OPV bug by triggering this logic more frequently.

1 files changed, 19 insertions(+), 5 deletions(-)

src/Sema.zig+19-5
...@@ -3922,7 +3922,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -3922,7 +3922,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
3922 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));3922 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
3923 const ptr_to_map = switch (store_inst.tag) {3923 const ptr_to_map = switch (store_inst.tag) {
3924 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.3924 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to.
3925 .set_union_tag => continue, // We can completely ignore these: we'll do it implicitly when we get the field pointer.3925 .set_union_tag => continue, // Ignore for now; handled after we map pointers
3926 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.3926 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself.
3927 else => unreachable,3927 else => unreachable,
3928 };3928 };
...@@ -4055,19 +4055,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4055,19 +4055,33 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4055 }4055 }
40564056
4057 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.4057 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime.
4058 // Any implicit stores performed by `optional_payload_ptr_set`, `errunion_payload_ptr_set`, or4058 // Any implicit stores performed by `optional_payload_ptr_set` or `errunion_payload_ptr_set`
4059 // `set_union_tag` instructions were already done above.4059 // instructions were already done above.
40604060
4061 for (stores) |store_inst_idx| {4061 for (stores) |store_inst_idx| {
4062 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));4062 const store_inst = sema.air_instructions.get(@intFromEnum(store_inst_idx));
4063 switch (store_inst.tag) {4063 switch (store_inst.tag) {
4064 .set_union_tag => {}, // Handled implicitly by field pointers above
4065 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above4064 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above
4065 .set_union_tag => {
4066 // Usually, we can ignore these, because the creation of the field pointer above
4067 // already did it for us. However, if the field is OPV, this is relevant, because
4068 // there is not going to be a store to the field. So we must initialize the union
4069 // tag if the field is OPV.
4070 const union_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
4071 const union_ptr_val: Value = .fromInterned(ptr_mapping.get(union_ptr_inst).?);
4072 const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);
4073 const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);
4074 const field_ty = union_ty.unionFieldType(tag_val, zcu).?;
4075 if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| {
4076 const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);
4077 try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);
4078 }
4079 },
4066 .store, .store_safe => {4080 .store, .store_safe => {
4067 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;4081 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?;
4068 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;4082 const store_val = (try sema.resolveValue(store_inst.data.bin_op.rhs)).?;
4069 const new_ptr = ptr_mapping.get(air_ptr_inst).?;4083 const new_ptr = ptr_mapping.get(air_ptr_inst).?;
4070 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(new_ptr), store_val, .fromInterned(zcu.intern_pool.typeOf(store_val.toIntern())));4084 try sema.storePtrVal(block, .unneeded, .fromInterned(new_ptr), store_val, store_val.typeOf(zcu));
4071 },4085 },
4072 else => unreachable,4086 else => unreachable,
4073 }4087 }