authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-04 10:51:45+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:15+00:00
logea7e34224a8c3c0551e17a60fd849efee82447f7
tree96379f798486f191a84fac86c91cfb6cd2daf934
parent0f3c883245f27870472978f738d6e81958e15c52
signaturelock-open Commit is signed but in an unrecognized format.

compiler: don't call `getUnionLayout` on packed unions


4 files changed, 168 insertions(+), 172 deletions(-)

src/Type.zig+4
...@@ -1571,6 +1571,7 @@ pub fn externUnionBackingType(ty: Type, pt: Zcu.PerThread) !Type {...@@ -1571,6 +1571,7 @@ pub fn externUnionBackingType(ty: Type, pt: Zcu.PerThread) !Type {
1571 }1571 }
1572}1572}
15731573
1574/// Asserts that `ty` is a non-packed union type.
1574pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {1575pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
1575 assertHasLayout(ty, zcu);1576 assertHasLayout(ty, zcu);
1576 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());1577 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
...@@ -2689,7 +2690,10 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {...@@ -2689,7 +2690,10 @@ pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
2689 return .{ cur_ty, cur_len };2690 return .{ cur_ty, cur_len };
2690}2691}
26912692
2693/// Asserts that `loaded_union.layout` is not `.@"packed"`.
2692pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {2694pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {
2695 assert(loaded_union.layout != .@"packed");
2696
2693 const ip = &zcu.intern_pool;2697 const ip = &zcu.intern_pool;
2694 var most_aligned_field: u32 = 0;2698 var most_aligned_field: u32 = 0;
2695 var most_aligned_field_align: InternPool.Alignment = .@"1";2699 var most_aligned_field_align: InternPool.Alignment = .@"1";
src/codegen/llvm.zig+63-68
...@@ -2369,6 +2369,30 @@ pub const Object = struct {...@@ -2369,6 +2369,30 @@ pub const Object = struct {
2369 const line = ty.typeDeclSrcLine(zcu).? + 1;2369 const line = ty.typeDeclSrcLine(zcu).? + 1;
23702370
2371 const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);2371 const enum_tag_ty: Type = .fromInterned(union_type.enum_tag_type);
2372
2373 if (union_type.layout == .@"packed") {
2374 const bitpack_field = try o.builder.debugMemberType(
2375 try o.builder.metadataString("bits"),
2376 null, // file
2377 ty_fwd_ref,
2378 0, // line
2379 try o.getDebugType(pt, .fromInterned(union_type.packed_backing_int_type)),
2380 ty.abiSize(zcu) * 8,
2381 ty.abiAlignment(zcu).toByteUnits().? * 8,
2382 0, // offset
2383 );
2384 return o.builder.debugStructType(
2385 name,
2386 file,
2387 scope,
2388 line,
2389 null, // underlying type
2390 ty.abiSize(zcu) * 8,
2391 ty.abiAlignment(zcu).toByteUnits().? * 8,
2392 try o.builder.metadataTuple(&.{bitpack_field}),
2393 );
2394 }
2395
2372 const layout = Type.getUnionLayout(union_type, zcu);2396 const layout = Type.getUnionLayout(union_type, zcu);
23732397
2374 if (layout.payload_size == 0) {2398 if (layout.payload_size == 0) {
...@@ -2411,10 +2435,7 @@ pub const Object = struct {...@@ -2411,10 +2435,7 @@ pub const Object = struct {
2411 const field_ty = union_type.field_types.get(ip)[field_index];2435 const field_ty = union_type.field_types.get(ip)[field_index];
24122436
2413 const field_size = Type.fromInterned(field_ty).abiSize(zcu);2437 const field_size = Type.fromInterned(field_ty).abiSize(zcu);
2414 const field_align: InternPool.Alignment = switch (union_type.layout) {2438 const field_align: InternPool.Alignment = ty.explicitFieldAlignment(field_index, zcu);
2415 .@"packed" => .none,
2416 .auto, .@"extern" => ty.explicitFieldAlignment(field_index, zcu),
2417 };
24182439
2419 const field_name = enum_tag_ty.enumFieldName(field_index, zcu);2440 const field_name = enum_tag_ty.enumFieldName(field_index, zcu);
2420 fields.appendAssumeCapacity(try o.builder.debugMemberType(2441 fields.appendAssumeCapacity(try o.builder.debugMemberType(
...@@ -3318,7 +3339,6 @@ pub const Object = struct {...@@ -3318,7 +3339,6 @@ pub const Object = struct {
3318 if (o.type_map.get(t.toIntern())) |value| return value;3339 if (o.type_map.get(t.toIntern())) |value| return value;
33193340
3320 const union_obj = ip.loadUnionType(t.toIntern());3341 const union_obj = ip.loadUnionType(t.toIntern());
3321 const layout = Type.getUnionLayout(union_obj, zcu);
33223342
3323 if (union_obj.layout == .@"packed") {3343 if (union_obj.layout == .@"packed") {
3324 const int_ty = try o.lowerType(pt, .fromInterned(union_obj.packed_backing_int_type));3344 const int_ty = try o.lowerType(pt, .fromInterned(union_obj.packed_backing_int_type));
...@@ -3326,6 +3346,8 @@ pub const Object = struct {...@@ -3326,6 +3346,8 @@ pub const Object = struct {
3326 return int_ty;3346 return int_ty;
3327 }3347 }
33283348
3349 const layout = Type.getUnionLayout(union_obj, zcu);
3350
3329 if (layout.payload_size == 0) {3351 if (layout.payload_size == 0) {
3330 const enum_tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));3352 const enum_tag_ty = try o.lowerType(pt, .fromInterned(union_obj.enum_tag_type));
3331 try o.type_map.put(o.gpa, t.toIntern(), enum_tag_ty);3353 try o.type_map.put(o.gpa, t.toIntern(), enum_tag_ty);
...@@ -6760,7 +6782,7 @@ pub const FuncGen = struct {...@@ -6760,7 +6782,7 @@ pub const FuncGen = struct {
6760 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;6782 const struct_field = self.air.extraData(Air.StructField, ty_pl.payload).data;
6761 const struct_ptr = try self.resolveInst(struct_field.struct_operand);6783 const struct_ptr = try self.resolveInst(struct_field.struct_operand);
6762 const struct_ptr_ty = self.typeOf(struct_field.struct_operand);6784 const struct_ptr_ty = self.typeOf(struct_field.struct_operand);
6763 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, struct_field.field_index);6785 return self.fieldPtr(struct_ptr, struct_ptr_ty, struct_field.field_index);
6764 }6786 }
67656787
6766 fn airStructFieldPtrIndex(6788 fn airStructFieldPtrIndex(
...@@ -6771,7 +6793,7 @@ pub const FuncGen = struct {...@@ -6771,7 +6793,7 @@ pub const FuncGen = struct {
6771 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6793 const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6772 const struct_ptr = try self.resolveInst(ty_op.operand);6794 const struct_ptr = try self.resolveInst(ty_op.operand);
6773 const struct_ptr_ty = self.typeOf(ty_op.operand);6795 const struct_ptr_ty = self.typeOf(ty_op.operand);
6774 return self.fieldPtr(inst, struct_ptr, struct_ptr_ty, field_index);6796 return self.fieldPtr(struct_ptr, struct_ptr_ty, field_index);
6775 }6797 }
67766798
6777 fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {6799 fn airStructFieldVal(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
...@@ -10704,18 +10726,11 @@ pub const FuncGen = struct {...@@ -10704,18 +10726,11 @@ pub const FuncGen = struct {
10704 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;10726 const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
10705 const union_ty = self.typeOfIndex(inst);10727 const union_ty = self.typeOfIndex(inst);
10706 const union_llvm_ty = try o.lowerType(pt, union_ty);10728 const union_llvm_ty = try o.lowerType(pt, union_ty);
10707 const layout = union_ty.unionGetLayout(zcu);
10708 const union_obj = zcu.typeToUnion(union_ty).?;10729 const union_obj = zcu.typeToUnion(union_ty).?;
1070910730
10710 if (union_obj.layout == .@"packed") {10731 assert(union_obj.layout != .@"packed");
10711 const big_bits = union_ty.bitSize(zcu);10732
10712 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));10733 const layout = Type.getUnionLayout(union_obj, zcu);
10713 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[extra.field_index]);
10714 const non_int_val = try self.resolveInst(extra.init);
10715 const small_int_ty = try o.builder.intType(@intCast(field_ty.bitSize(zcu)));
10716 const small_int_val = try self.wip.cast(.bitcast, non_int_val, small_int_ty, "");
10717 return self.wip.conv(.unsigned, small_int_val, int_llvm_ty, "");
10718 }
1071910734
10720 const tag_int_val = blk: {10735 const tag_int_val = blk: {
10721 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);10736 const tag_ty = union_ty.unionTagTypeHypothetical(zcu);
...@@ -11051,65 +11066,45 @@ pub const FuncGen = struct {...@@ -11051,65 +11066,45 @@ pub const FuncGen = struct {
1105111066
11052 fn fieldPtr(11067 fn fieldPtr(
11053 self: *FuncGen,11068 self: *FuncGen,
11054 inst: Air.Inst.Index,11069 aggregate_ptr: Builder.Value,
11055 struct_ptr: Builder.Value,11070 aggregate_ptr_ty: Type,
11056 struct_ptr_ty: Type,
11057 field_index: u32,11071 field_index: u32,
11058 ) !Builder.Value {11072 ) !Builder.Value {
11059 const o = self.ng.object;11073 const o = self.ng.object;
11060 const pt = self.ng.pt;11074 const pt = self.ng.pt;
11061 const zcu = pt.zcu;11075 const zcu = pt.zcu;
11062 const struct_ty = struct_ptr_ty.childType(zcu);11076 const aggregate_ty = aggregate_ptr_ty.childType(zcu);
11063 switch (struct_ty.zigTypeTag(zcu)) {11077 if (aggregate_ty.containerLayout(zcu) == .@"packed") {
11064 .@"struct" => switch (struct_ty.containerLayout(zcu)) {11078 // A pointer to a bitpack field is equivalent to a pointer to the whole bitpack; the
11065 .@"packed" => {11079 // bit offset is represented in the pointer *type*.
11066 const result_ty = self.typeOfIndex(inst);11080 return aggregate_ptr;
11067 const result_ty_info = result_ty.ptrInfo(zcu);11081 }
11068 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);11082 switch (aggregate_ty.zigTypeTag(zcu)) {
11069 const struct_type = zcu.typeToStruct(struct_ty).?;11083 .@"struct" => {
1107011084 if (!aggregate_ty.hasRuntimeBits(zcu)) {
11071 if (result_ty_info.packed_offset.host_size != 0) {11085 return aggregate_ptr;
11072 // From LLVM's perspective, a pointer to a packed struct and a pointer11086 }
11073 // to a field of a packed struct are the same. The difference is in the11087 const struct_llvm_ty = try o.lowerType(pt, aggregate_ty);
11074 // Zig pointer type which provides information for how to mask and shift11088 if (o.llvmFieldIndex(aggregate_ty, field_index)) |llvm_field_index| {
11075 // out the relevant bits when accessing the pointee.11089 return self.wip.gepStruct(struct_llvm_ty, aggregate_ptr, llvm_field_index, "");
11076 return struct_ptr;11090 } else {
11077 }11091 // If we found no index then this means this is a zero sized field at the
1107811092 // end of the struct. Treat our struct pointer as an array of two and get
11079 // We have a pointer to a packed struct field that happens to be byte-aligned.11093 // the index to the element at index `1` to get a pointer to the end of
11080 // Offset our operand pointer by the correct number of bytes.11094 // the struct.
11081 const byte_offset = @divExact(zcu.structPackedFieldBitOffset(struct_type, field_index) + struct_ptr_ty_info.packed_offset.bit_offset, 8);11095 const llvm_index = try o.builder.intValue(
11082 if (byte_offset == 0) return struct_ptr;11096 try o.lowerType(pt, Type.usize),
11083 const usize_ty = try o.lowerType(pt, Type.usize);11097 @intFromBool(aggregate_ty.hasRuntimeBits(zcu)),
11084 const llvm_index = try o.builder.intValue(usize_ty, byte_offset);11098 );
11085 return self.wip.gep(.inbounds, .i8, struct_ptr, &.{llvm_index}, "");11099 return self.wip.gep(.inbounds, struct_llvm_ty, aggregate_ptr, &.{llvm_index}, "");
11086 },11100 }
11087 else => {
11088 if (!struct_ty.hasRuntimeBits(zcu)) {
11089 return struct_ptr;
11090 }
11091 const struct_llvm_ty = try o.lowerType(pt, struct_ty);
11092 if (o.llvmFieldIndex(struct_ty, field_index)) |llvm_field_index| {
11093 return self.wip.gepStruct(struct_llvm_ty, struct_ptr, llvm_field_index, "");
11094 } else {
11095 // If we found no index then this means this is a zero sized field at the
11096 // end of the struct. Treat our struct pointer as an array of two and get
11097 // the index to the element at index `1` to get a pointer to the end of
11098 // the struct.
11099 const llvm_index = try o.builder.intValue(
11100 try o.lowerType(pt, Type.usize),
11101 @intFromBool(struct_ty.hasRuntimeBits(zcu)),
11102 );
11103 return self.wip.gep(.inbounds, struct_llvm_ty, struct_ptr, &.{llvm_index}, "");
11104 }
11105 },
11106 },11101 },
11107 .@"union" => {11102 .@"union" => {
11108 const layout = struct_ty.unionGetLayout(zcu);11103 const layout = aggregate_ty.unionGetLayout(zcu);
11109 if (layout.payload_size == 0 or struct_ty.containerLayout(zcu) == .@"packed") return struct_ptr;11104 if (layout.payload_size == 0) return aggregate_ptr;
11110 const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align));11105 const payload_index = @intFromBool(layout.tag_size > 0 and layout.tag_align.compare(.gte, layout.payload_align));
11111 const union_llvm_ty = try o.lowerType(pt, struct_ty);11106 const union_llvm_ty = try o.lowerType(pt, aggregate_ty);
11112 return self.wip.gepStruct(union_llvm_ty, struct_ptr, payload_index, "");11107 return self.wip.gepStruct(union_llvm_ty, aggregate_ptr, payload_index, "");
11113 },11108 },
11114 else => unreachable,11109 else => unreachable,
11115 }11110 }
src/codegen/spirv/CodeGen.zig+26-46
...@@ -4519,30 +4519,7 @@ fn unionInit(...@@ -4519,30 +4519,7 @@ fn unionInit(
4519 const layout = cg.unionLayout(ty);4519 const layout = cg.unionLayout(ty);
4520 const payload_ty: Type = .fromInterned(union_ty.field_types.get(ip)[active_field]);4520 const payload_ty: Type = .fromInterned(union_ty.field_types.get(ip)[active_field]);
45214521
4522 if (union_ty.layout == .@"packed") {4522 assert(union_ty.layout != .@"packed");
4523 if (!payload_ty.hasRuntimeBits(zcu)) {
4524 const int_ty = try pt.intType(.unsigned, @intCast(ty.bitSize(zcu)));
4525 return cg.constInt(int_ty, 0);
4526 }
4527
4528 assert(payload != null);
4529 if (payload_ty.isInt(zcu)) {
4530 if (ty.bitSize(zcu) == payload_ty.bitSize(zcu)) {
4531 return cg.bitCast(ty, payload_ty, payload.?);
4532 }
4533
4534 const trunc = try cg.buildConvert(ty, .{ .ty = payload_ty, .value = .{ .singleton = payload.? } });
4535 return try trunc.materialize(cg);
4536 }
4537
4538 const payload_int_ty = try pt.intType(.unsigned, @intCast(payload_ty.bitSize(zcu)));
4539 const payload_int = if (payload_ty.ip_index == .bool_type)
4540 try cg.convertToIndirect(payload_ty, payload.?)
4541 else
4542 try cg.bitCast(payload_int_ty, payload_ty, payload.?);
4543 const trunc = try cg.buildConvert(ty, .{ .ty = payload_int_ty, .value = .{ .singleton = payload_int } });
4544 return try trunc.materialize(cg);
4545 }
45464523
4547 const tag_int = if (layout.tag_size != 0) blk: {4524 const tag_int = if (layout.tag_size != 0) blk: {
4548 const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field);4525 const tag_val = try pt.enumValueFieldIndex(tag_ty, active_field);
...@@ -4761,33 +4738,36 @@ fn structFieldPtr(...@@ -4761,33 +4738,36 @@ fn structFieldPtr(
4761 },4738 },
4762 .@"struct" => switch (object_ty.containerLayout(zcu)) {4739 .@"struct" => switch (object_ty.containerLayout(zcu)) {
4763 .@"packed" => return cg.todo("implement field access for packed structs", .{}),4740 .@"packed" => return cg.todo("implement field access for packed structs", .{}),
4764 else => {4741 .auto, .@"extern" => {
4765 return try cg.accessChain(result_ty_id, object_ptr, &.{field_index});4742 return try cg.accessChain(result_ty_id, object_ptr, &.{field_index});
4766 },4743 },
4767 },4744 },
4768 .@"union" => {4745 .@"union" => switch (object_ty.containerLayout(zcu)) {
4769 const layout = cg.unionLayout(object_ty);4746 .@"packed" => return cg.todo("implement field access for packed unions", .{}),
4770 if (!layout.has_payload) {4747 .auto, .@"extern" => {
4771 // Asked to get a pointer to a zero-sized field. Just lower this4748 const layout = cg.unionLayout(object_ty);
4772 // to undefined, there is no reason to make it be a valid pointer.4749 if (!layout.has_payload) {
4773 return try cg.module.constUndef(result_ty_id);4750 // Asked to get a pointer to a zero-sized field. Just lower this
4774 }4751 // to undefined, there is no reason to make it be a valid pointer.
4752 return try cg.module.constUndef(result_ty_id);
4753 }
47754754
4776 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));4755 const storage_class = cg.module.storageClass(object_ptr_ty.ptrAddressSpace(zcu));
4777 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);4756 const layout_payload_ty_id = try cg.resolveType(layout.payload_ty, .indirect);
4778 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);4757 const pl_ptr_ty_id = try cg.module.ptrType(layout_payload_ty_id, storage_class);
4779 const pl_ptr_id = blk: {4758 const pl_ptr_id = blk: {
4780 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;4759 if (object_ty.containerLayout(zcu) == .@"packed") break :blk object_ptr;
4781 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});4760 break :blk try cg.accessChain(pl_ptr_ty_id, object_ptr, &.{layout.payload_index});
4782 };4761 };
47834762
4784 const active_pl_ptr_id = cg.module.allocId();4763 const active_pl_ptr_id = cg.module.allocId();
4785 try cg.body.emit(cg.module.gpa, .OpBitcast, .{4764 try cg.body.emit(cg.module.gpa, .OpBitcast, .{
4786 .id_result_type = result_ty_id,4765 .id_result_type = result_ty_id,
4787 .id_result = active_pl_ptr_id,4766 .id_result = active_pl_ptr_id,
4788 .operand = pl_ptr_id,4767 .operand = pl_ptr_id,
4789 });4768 });
4790 return active_pl_ptr_id;4769 return active_pl_ptr_id;
4770 },
4791 },4771 },
4792 else => unreachable,4772 else => unreachable,
4793 }4773 }
src/link/Dwarf.zig+75-58
...@@ -4009,69 +4009,86 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4009,69 +4009,86 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4009 .union_type => {4009 .union_type => {
4010 const loaded_union = ip.loadUnionType(value_index);4010 const loaded_union = ip.loadUnionType(value_index);
4011 const file = loaded_union.zir_index.resolveFile(ip);4011 const file = loaded_union.zir_index.resolveFile(ip);
4012 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {4012 switch (loaded_union.layout) {
4013 const nav = ip.getNav(nav_index);4013 .auto, .@"extern" => {
4014 const decl_inst = nav.srcInst(ip).resolve(ip).?;4014 const need_terminator: bool = if (loaded_union.name_nav.unwrap()) |nav_index| t: {
4015 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);4015 const nav = ip.getNav(nav_index);
4016 try wip_nav.declCommon(.{4016 const decl_inst = nav.srcInst(ip).resolve(ip).?;
4017 .decl = .decl_union,4017 const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
4018 .generic_decl = .generic_decl_const,4018 try wip_nav.declCommon(.{
4019 .decl_instance = .decl_instance_union,4019 .decl = .decl_union,
4020 }, &nav, file, &decl);4020 .generic_decl = .generic_decl_const,
4021 break :t true;4021 .decl_instance = .decl_instance_union,
4022 } else t: {4022 }, &nav, file, &decl);
4023 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);4023 break :t true;
4024 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);4024 } else t: {
4025 try diw.writeUleb128(file_gop.index);4025 const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file);
4026 try wip_nav.strp(loaded_union.name.toSlice(ip));4026 try wip_nav.abbrevCode(if (loaded_union.field_types.len > 0) .union_type else .empty_union_type);
4027 break :t loaded_union.field_types.len > 0;4027 try diw.writeUleb128(file_gop.index);
4028 };4028 try wip_nav.strp(loaded_union.name.toSlice(ip));
4029 const union_layout = Type.getUnionLayout(loaded_union, zcu);4029 break :t loaded_union.field_types.len > 0;
4030 try diw.writeUleb128(union_layout.abi_size);4030 };
4031 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);4031 const union_layout = Type.getUnionLayout(loaded_union, zcu);
4032 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);4032 try diw.writeUleb128(union_layout.abi_size);
4033 if (loaded_union.has_runtime_tag) {4033 try diw.writeUleb128(union_layout.abi_align.toByteUnits().?);
4034 try wip_nav.abbrevCode(.tagged_union);4034 const loaded_tag = ip.loadEnumType(loaded_union.enum_tag_type);
4035 try wip_nav.infoSectionOffset(4035 if (loaded_union.has_runtime_tag) {
4036 .debug_info,4036 try wip_nav.abbrevCode(.tagged_union);
4037 wip_nav.unit,4037 try wip_nav.infoSectionOffset(
4038 wip_nav.entry,4038 .debug_info,
4039 @intCast(diw.end + dwarf.sectionOffsetBytes()),4039 wip_nav.unit,
4040 );4040 wip_nav.entry,
4041 {4041 @intCast(diw.end + dwarf.sectionOffsetBytes()),
4042 try wip_nav.abbrevCode(.generated_field);4042 );
4043 try wip_nav.strp("tag");
4044 try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
4045 try diw.writeUleb128(union_layout.tagOffset());
4046
4047 for (0..loaded_union.field_types.len) |field_index| {
4048 try wip_nav.enumConstValue(loaded_tag, .{
4049 .sdata = .signed_tagged_union_field,
4050 .udata = .unsigned_tagged_union_field,
4051 .block = .big_tagged_union_field,
4052 }, field_index);
4053 {4043 {
4054 try wip_nav.abbrevCode(.struct_field);4044 try wip_nav.abbrevCode(.generated_field);
4055 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));4045 try wip_nav.strp("tag");
4056 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);4046 try wip_nav.refType(.fromInterned(loaded_union.enum_tag_type));
4057 try wip_nav.refType(field_type);4047 try diw.writeUleb128(union_layout.tagOffset());
4058 try diw.writeUleb128(union_layout.payloadOffset());4048
4059 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse4049 for (0..loaded_union.field_types.len) |field_index| {
4060 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);4050 try wip_nav.enumConstValue(loaded_tag, .{
4051 .sdata = .signed_tagged_union_field,
4052 .udata = .unsigned_tagged_union_field,
4053 .block = .big_tagged_union_field,
4054 }, field_index);
4055 {
4056 try wip_nav.abbrevCode(.struct_field);
4057 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4058 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4059 try wip_nav.refType(field_type);
4060 try diw.writeUleb128(union_layout.payloadOffset());
4061 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
4062 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4063 }
4064 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4065 }
4061 }4066 }
4062 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));4067 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4068 } else for (0..loaded_union.field_types.len) |field_index| {
4069 try wip_nav.abbrevCode(.untagged_union_field);
4070 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));
4071 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);
4072 try wip_nav.refType(field_type);
4073 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse
4074 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);
4063 }4075 }
4064 }4076 if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4065 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));4077 },
4066 } else for (0..loaded_union.field_types.len) |field_index| {4078 .@"packed" => {
4067 try wip_nav.abbrevCode(.untagged_union_field);4079 // TODO: debug info for packed unions
4068 try wip_nav.strp(loaded_tag.field_names.get(ip)[field_index].toSlice(ip));4080 try wip_nav.abbrevCode(.numeric_type);
4069 const field_type: Type = .fromInterned(loaded_union.field_types.get(ip)[field_index]);4081 try wip_nav.strp(loaded_union.name.toSlice(ip));
4070 try wip_nav.refType(field_type);4082 const backing_int_ty: Type = .fromInterned(loaded_union.packed_backing_int_type);
4071 try diw.writeUleb128(loaded_union.field_aligns.getOrNone(ip, field_index).toByteUnits() orelse4083 const int_info = backing_int_ty.intInfo(zcu);
4072 if (field_type.isNoReturn(zcu)) 1 else field_type.abiAlignment(zcu).toByteUnits().?);4084 try diw.writeByte(switch (int_info.signedness) {
4085 inline .signed, .unsigned => |signedness| @field(DW.ATE, @tagName(signedness)),
4086 });
4087 try diw.writeUleb128(int_info.bits);
4088 try diw.writeUleb128(backing_int_ty.abiSize(zcu));
4089 try diw.writeUleb128(backing_int_ty.abiAlignment(zcu).toByteUnits().?);
4090 },
4073 }4091 }
4074 if (need_terminator) try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
4075 },4092 },
4076 .enum_type => {4093 .enum_type => {
4077 const loaded_enum = ip.loadEnumType(value_index);4094 const loaded_enum = ip.loadEnumType(value_index);