authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 17:29:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-21 17:29:34-07:00
log81b5df347a2b92566dc679fdd4e110812dfe27d0
tree2e2580b944374f490797ef3211eb752c7b1bc051
parentedfada4317760a152ad9c36b39f5a2e68eeaebf8

compiler: fix structFieldName crash for tuples

When struct types have no field names, the names are implicitly understood to be strings corresponding to the field indexes in declaration order. It used to be the case that a NullTerminatedString would be stored for each field in this case, however, now, callers must handle the possibility that there are no names stored at all. This commit introduces `legacyStructFieldName`, a function to fake the previous behavior. Probably something better could be done by reworking all the callsites of this function.

6 files changed, 66 insertions(+), 36 deletions(-)

src/InternPool.zig+11
...@@ -656,6 +656,17 @@ pub const Key = union(enum) {...@@ -656,6 +656,17 @@ pub const Key = union(enum) {
656 pub fn isTuple(self: AnonStructType) bool {656 pub fn isTuple(self: AnonStructType) bool {
657 return self.names.len == 0;657 return self.names.len == 0;
658 }658 }
659
660 pub fn fieldName(
661 self: AnonStructType,
662 ip: *const InternPool,
663 index: u32,
664 ) OptionalNullTerminatedString {
665 if (self.names.len == 0)
666 return .none;
667
668 return self.names.get(ip)[index].toOptional();
669 }
659 };670 };
660671
661 /// Serves two purposes:672 /// Serves two purposes:
src/Sema.zig+19-17
...@@ -4699,12 +4699,13 @@ fn validateStructInit(...@@ -4699,12 +4699,13 @@ fn validateStructInit(
4699 // In this case the only thing we need to do is evaluate the implicit4699 // In this case the only thing we need to do is evaluate the implicit
4700 // store instructions for default field values, and report any missing fields.4700 // store instructions for default field values, and report any missing fields.
4701 // Avoid the cost of the extra machinery for detecting a comptime struct init value.4701 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
4702 for (found_fields, 0..) |field_ptr, i| {4702 for (found_fields, 0..) |field_ptr, i_usize| {
4703 const i: u32 = @intCast(i_usize);
4703 if (field_ptr != 0) continue;4704 if (field_ptr != 0) continue;
47044705
4705 const default_val = struct_ty.structFieldDefaultValue(i, mod);4706 const default_val = struct_ty.structFieldDefaultValue(i, mod);
4706 if (default_val.toIntern() == .unreachable_value) {4707 if (default_val.toIntern() == .unreachable_value) {
4707 if (struct_ty.isTuple(mod)) {4708 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
4708 const template = "missing tuple field with index {d}";4709 const template = "missing tuple field with index {d}";
4709 if (root_msg) |msg| {4710 if (root_msg) |msg| {
4710 try sema.errNote(block, init_src, msg, template, .{i});4711 try sema.errNote(block, init_src, msg, template, .{i});
...@@ -4712,8 +4713,7 @@ fn validateStructInit(...@@ -4712,8 +4713,7 @@ fn validateStructInit(
4712 root_msg = try sema.errMsg(block, init_src, template, .{i});4713 root_msg = try sema.errMsg(block, init_src, template, .{i});
4713 }4714 }
4714 continue;4715 continue;
4715 }4716 };
4716 const field_name = struct_ty.structFieldName(i, mod);
4717 const template = "missing struct field: {}";4717 const template = "missing struct field: {}";
4718 const args = .{field_name.fmt(ip)};4718 const args = .{field_name.fmt(ip)};
4719 if (root_msg) |msg| {4719 if (root_msg) |msg| {
...@@ -4763,7 +4763,8 @@ fn validateStructInit(...@@ -4763,7 +4763,8 @@ fn validateStructInit(
4763 // ends up being comptime-known.4763 // ends up being comptime-known.
4764 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));4764 const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));
47654765
4766 field: for (found_fields, 0..) |field_ptr, i| {4766 field: for (found_fields, 0..) |field_ptr, i_usize| {
4767 const i: u32 = @intCast(i_usize);
4767 if (field_ptr != 0) {4768 if (field_ptr != 0) {
4768 // Determine whether the value stored to this pointer is comptime-known.4769 // Determine whether the value stored to this pointer is comptime-known.
4769 const field_ty = struct_ty.structFieldType(i, mod);4770 const field_ty = struct_ty.structFieldType(i, mod);
...@@ -4842,7 +4843,7 @@ fn validateStructInit(...@@ -4842,7 +4843,7 @@ fn validateStructInit(
48424843
4843 const default_val = struct_ty.structFieldDefaultValue(i, mod);4844 const default_val = struct_ty.structFieldDefaultValue(i, mod);
4844 if (default_val.toIntern() == .unreachable_value) {4845 if (default_val.toIntern() == .unreachable_value) {
4845 if (struct_ty.isTuple(mod)) {4846 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
4846 const template = "missing tuple field with index {d}";4847 const template = "missing tuple field with index {d}";
4847 if (root_msg) |msg| {4848 if (root_msg) |msg| {
4848 try sema.errNote(block, init_src, msg, template, .{i});4849 try sema.errNote(block, init_src, msg, template, .{i});
...@@ -4850,8 +4851,7 @@ fn validateStructInit(...@@ -4850,8 +4851,7 @@ fn validateStructInit(
4850 root_msg = try sema.errMsg(block, init_src, template, .{i});4851 root_msg = try sema.errMsg(block, init_src, template, .{i});
4851 }4852 }
4852 continue;4853 continue;
4853 }4854 };
4854 const field_name = struct_ty.structFieldName(i, mod);
4855 const template = "missing struct field: {}";4855 const template = "missing struct field: {}";
4856 const args = .{field_name.fmt(ip)};4856 const args = .{field_name.fmt(ip)};
4857 if (root_msg) |msg| {4857 if (root_msg) |msg| {
...@@ -21862,10 +21862,10 @@ fn ptrCastFull(...@@ -21862,10 +21862,10 @@ fn ptrCastFull(
21862 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});21862 const msg = try sema.errMsg(block, src, "cast increases pointer alignment", .{});
21863 errdefer msg.destroy(sema.gpa);21863 errdefer msg.destroy(sema.gpa);
21864 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{21864 try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
21865 operand_ty.fmt(mod), src_align,21865 operand_ty.fmt(mod), src_align.toByteUnits(0),
21866 });21866 });
21867 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{21867 try sema.errNote(block, src, msg, "'{}' has alignment '{d}'", .{
21868 dest_ty.fmt(mod), dest_align,21868 dest_ty.fmt(mod), dest_align.toByteUnits(0),
21869 });21869 });
21870 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});21870 try sema.errNote(block, src, msg, "use @alignCast to assert pointer alignment", .{});
21871 break :msg msg;21871 break :msg msg;
...@@ -26376,7 +26376,7 @@ fn fieldCallBind(...@@ -26376,7 +26376,7 @@ fn fieldCallBind(
26376 const max = concrete_ty.structFieldCount(mod);26376 const max = concrete_ty.structFieldCount(mod);
26377 for (0..max) |i_usize| {26377 for (0..max) |i_usize| {
26378 const i: u32 = @intCast(i_usize);26378 const i: u32 = @intCast(i_usize);
26379 if (field_name == concrete_ty.structFieldName(i, mod)) {26379 if (field_name == concrete_ty.structFieldName(i, mod).unwrap().?) {
26380 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr);26380 return sema.finishFieldCallBind(block, src, ptr_ty, concrete_ty.structFieldType(i, mod), i, object_ptr);
26381 }26381 }
26382 }26382 }
...@@ -31143,7 +31143,8 @@ fn coerceTupleToTuple(...@@ -31143,7 +31143,8 @@ fn coerceTupleToTuple(
31143 var root_msg: ?*Module.ErrorMsg = null;31143 var root_msg: ?*Module.ErrorMsg = null;
31144 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);31144 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
3114531145
31146 for (field_refs, 0..) |*field_ref, i| {31146 for (field_refs, 0..) |*field_ref, i_usize| {
31147 const i: u32 = @intCast(i_usize);
31147 if (field_ref.* != .none) continue;31148 if (field_ref.* != .none) continue;
3114831149
31149 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {31150 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
...@@ -31154,7 +31155,7 @@ fn coerceTupleToTuple(...@@ -31154,7 +31155,7 @@ fn coerceTupleToTuple(
3115431155
31155 const field_src = inst_src; // TODO better source location31156 const field_src = inst_src; // TODO better source location
31156 if (default_val == .none) {31157 if (default_val == .none) {
31157 if (tuple_ty.isTuple(mod)) {31158 const field_name = tuple_ty.structFieldName(i, mod).unwrap() orelse {
31158 const template = "missing tuple field: {d}";31159 const template = "missing tuple field: {d}";
31159 if (root_msg) |msg| {31160 if (root_msg) |msg| {
31160 try sema.errNote(block, field_src, msg, template, .{i});31161 try sema.errNote(block, field_src, msg, template, .{i});
...@@ -31162,9 +31163,9 @@ fn coerceTupleToTuple(...@@ -31162,9 +31163,9 @@ fn coerceTupleToTuple(
31162 root_msg = try sema.errMsg(block, field_src, template, .{i});31163 root_msg = try sema.errMsg(block, field_src, template, .{i});
31163 }31164 }
31164 continue;31165 continue;
31165 }31166 };
31166 const template = "missing struct field: {}";31167 const template = "missing struct field: {}";
31167 const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)};31168 const args = .{field_name.fmt(ip)};
31168 if (root_msg) |msg| {31169 if (root_msg) |msg| {
31169 try sema.errNote(block, field_src, msg, template, args);31170 try sema.errNote(block, field_src, msg, template, args);
31170 } else {31171 } else {
...@@ -33897,8 +33898,9 @@ fn resolvePeerTypesInner(...@@ -33897,8 +33898,9 @@ fn resolvePeerTypesInner(
33897 }33898 }
3389833899
33899 if (!is_tuple) {33900 if (!is_tuple) {
33900 for (field_names, 0..) |expected, field_idx| {33901 for (field_names, 0..) |expected, field_index_usize| {
33901 const actual = ty.structFieldName(field_idx, mod);33902 const field_index: u32 = @intCast(field_index_usize);
33903 const actual = ty.structFieldName(field_index, mod).unwrap().?;
33902 if (actual == expected) continue;33904 if (actual == expected) continue;
33903 return .{ .conflict = .{33905 return .{ .conflict = .{
33904 .peer_idx_a = first_idx,33906 .peer_idx_a = first_idx,
src/TypedValue.zig+3-3
...@@ -355,11 +355,11 @@ pub fn print(...@@ -355,11 +355,11 @@ pub fn print(
355 const container_ty = ptr_container_ty.childType(mod);355 const container_ty = ptr_container_ty.childType(mod);
356 switch (container_ty.zigTypeTag(mod)) {356 switch (container_ty.zigTypeTag(mod)) {
357 .Struct => {357 .Struct => {
358 if (container_ty.isTuple(mod)) {358 if (container_ty.structFieldName(@intCast(field.index), mod).unwrap()) |field_name| {
359 try writer.print(".{i}", .{field_name.fmt(ip)});
360 } else {
359 try writer.print("[{d}]", .{field.index});361 try writer.print("[{d}]", .{field.index});
360 }362 }
361 const field_name = container_ty.structFieldName(@as(usize, @intCast(field.index)), mod);
362 try writer.print(".{i}", .{field_name.fmt(ip)});
363 },363 },
364 .Union => {364 .Union => {
365 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];365 const field_name = mod.typeToUnion(container_ty).?.field_names.get(ip)[@intCast(field.index)];
src/codegen/c.zig+8-6
...@@ -5226,7 +5226,8 @@ fn fieldLocation(...@@ -5226,7 +5226,8 @@ fn fieldLocation(
5226 const container_ty = container_ptr_ty.childType(mod);5226 const container_ty = container_ptr_ty.childType(mod);
5227 return switch (container_ty.zigTypeTag(mod)) {5227 return switch (container_ty.zigTypeTag(mod)) {
5228 .Struct => switch (container_ty.containerLayout(mod)) {5228 .Struct => switch (container_ty.containerLayout(mod)) {
5229 .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index| {5229 .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index_usize| {
5230 const next_field_index: u32 = @intCast(next_field_index_usize);
5230 if (container_ty.structFieldIsComptime(next_field_index, mod)) continue;5231 if (container_ty.structFieldIsComptime(next_field_index, mod)) continue;
5231 const field_ty = container_ty.structFieldType(next_field_index, mod);5232 const field_ty = container_ty.structFieldType(next_field_index, mod);
5232 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;5233 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -5234,7 +5235,7 @@ fn fieldLocation(...@@ -5234,7 +5235,7 @@ fn fieldLocation(
5234 break .{ .field = if (container_ty.isSimpleTuple(mod))5235 break .{ .field = if (container_ty.isSimpleTuple(mod))
5235 .{ .field = next_field_index }5236 .{ .field = next_field_index }
5236 else5237 else
5237 .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } };5238 .{ .identifier = ip.stringToSlice(container_ty.legacyStructFieldName(next_field_index, mod)) } };
5238 } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin,5239 } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin,
5239 .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0)5240 .Packed => if (field_ptr_ty.ptrInfo(mod).packed_offset.host_size == 0)
5240 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) }5241 .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) + @divExact(container_ptr_ty.ptrInfo(mod).packed_offset.bit_offset, 8) }
...@@ -5421,7 +5422,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5421,7 +5422,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5421 .Auto, .Extern => if (struct_ty.isSimpleTuple(mod))5422 .Auto, .Extern => if (struct_ty.isSimpleTuple(mod))
5422 .{ .field = extra.field_index }5423 .{ .field = extra.field_index }
5423 else5424 else
5424 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },5425 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
5425 .Packed => {5426 .Packed => {
5426 const struct_type = mod.typeToStruct(struct_ty).?;5427 const struct_type = mod.typeToStruct(struct_ty).?;
5427 const int_info = struct_ty.intInfo(mod);5428 const int_info = struct_ty.intInfo(mod);
...@@ -5483,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -5483,7 +5484,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue {
5483 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)5484 .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0)
5484 .{ .field = extra.field_index }5485 .{ .field = extra.field_index }
5485 else5486 else
5486 .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) },5487 .{ .identifier = ip.stringToSlice(struct_ty.legacyStructFieldName(extra.field_index, mod)) },
54875488
5488 .union_type => |union_type| field_name: {5489 .union_type => |union_type| field_name: {
5489 const union_obj = ip.loadUnionType(union_type);5490 const union_obj = ip.loadUnionType(union_type);
...@@ -6816,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6816,7 +6817,8 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6816 }6817 }
6817 },6818 },
6818 .Struct => switch (inst_ty.containerLayout(mod)) {6819 .Struct => switch (inst_ty.containerLayout(mod)) {
6819 .Auto, .Extern => for (resolved_elements, 0..) |element, field_i| {6820 .Auto, .Extern => for (resolved_elements, 0..) |element, field_i_usize| {
6821 const field_i: u32 = @intCast(field_i_usize);
6820 if (inst_ty.structFieldIsComptime(field_i, mod)) continue;6822 if (inst_ty.structFieldIsComptime(field_i, mod)) continue;
6821 const field_ty = inst_ty.structFieldType(field_i, mod);6823 const field_ty = inst_ty.structFieldType(field_i, mod);
6822 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;6824 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -6825,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -6825,7 +6827,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue {
6825 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod))6827 try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod))
6826 .{ .field = field_i }6828 .{ .field = field_i }
6827 else6829 else
6828 .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) });6830 .{ .identifier = ip.stringToSlice(inst_ty.legacyStructFieldName(field_i, mod)) });
6829 try a.assign(f, writer);6831 try a.assign(f, writer);
6830 try f.writeCValue(writer, element, .Other);6832 try f.writeCValue(writer, element, .Other);
6831 try a.end(f, writer);6833 try a.end(f, writer);
src/codegen/c/type.zig+9-6
...@@ -1953,7 +1953,8 @@ pub const CType = extern union {...@@ -1953,7 +1953,8 @@ pub const CType = extern union {
19531953
1954 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);1954 const fields_pl = try arena.alloc(Payload.Fields.Field, c_fields_len);
1955 var c_field_i: usize = 0;1955 var c_field_i: usize = 0;
1956 for (0..fields_len) |field_i| {1956 for (0..fields_len) |field_i_usize| {
1957 const field_i: u32 = @intCast(field_i_usize);
1957 const field_ty = ty.structFieldType(field_i, mod);1958 const field_ty = ty.structFieldType(field_i, mod);
1958 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or1959 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
1959 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;1960 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -1964,7 +1965,7 @@ pub const CType = extern union {...@@ -1964,7 +1965,7 @@ pub const CType = extern union {
1964 std.fmt.allocPrintZ(arena, "f{}", .{field_i})1965 std.fmt.allocPrintZ(arena, "f{}", .{field_i})
1965 else1966 else
1966 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {1967 arena.dupeZ(u8, ip.stringToSlice(switch (zig_ty_tag) {
1967 .Struct => ty.structFieldName(field_i, mod),1968 .Struct => ty.legacyStructFieldName(field_i, mod),
1968 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],1969 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
1969 else => unreachable,1970 else => unreachable,
1970 })),1971 })),
...@@ -2097,7 +2098,8 @@ pub const CType = extern union {...@@ -2097,7 +2098,8 @@ pub const CType = extern union {
2097 .Struct => ty.structFieldCount(mod),2098 .Struct => ty.structFieldCount(mod),
2098 .Union => mod.typeToUnion(ty).?.field_names.len,2099 .Union => mod.typeToUnion(ty).?.field_names.len,
2099 else => unreachable,2100 else => unreachable,
2100 }) |field_i| {2101 }) |field_i_usize| {
2102 const field_i: u32 = @intCast(field_i_usize);
2101 const field_ty = ty.structFieldType(field_i, mod);2103 const field_ty = ty.structFieldType(field_i, mod);
2102 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or2104 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
2103 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2105 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -2116,7 +2118,7 @@ pub const CType = extern union {...@@ -2116,7 +2118,7 @@ pub const CType = extern union {
2116 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable2118 std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable
2117 else2119 else
2118 ip.stringToSlice(switch (zig_ty_tag) {2120 ip.stringToSlice(switch (zig_ty_tag) {
2119 .Struct => ty.structFieldName(field_i, mod),2121 .Struct => ty.legacyStructFieldName(field_i, mod),
2120 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],2122 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2121 else => unreachable,2123 else => unreachable,
2122 }),2124 }),
...@@ -2225,7 +2227,8 @@ pub const CType = extern union {...@@ -2225,7 +2227,8 @@ pub const CType = extern union {
2225 .Struct => ty.structFieldCount(mod),2227 .Struct => ty.structFieldCount(mod),
2226 .Union => mod.typeToUnion(ty).?.field_names.len,2228 .Union => mod.typeToUnion(ty).?.field_names.len,
2227 else => unreachable,2229 else => unreachable,
2228 }) |field_i| {2230 }) |field_i_usize| {
2231 const field_i: u32 = @intCast(field_i_usize);
2229 const field_ty = ty.structFieldType(field_i, mod);2232 const field_ty = ty.structFieldType(field_i, mod);
2230 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or2233 if ((zig_ty_tag == .Struct and ty.structFieldIsComptime(field_i, mod)) or
2231 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;2234 !field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
...@@ -2240,7 +2243,7 @@ pub const CType = extern union {...@@ -2240,7 +2243,7 @@ pub const CType = extern union {
2240 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable2243 std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable
2241 else2244 else
2242 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {2245 mod.intern_pool.stringToSlice(switch (zig_ty_tag) {
2243 .Struct => ty.structFieldName(field_i, mod),2246 .Struct => ty.legacyStructFieldName(field_i, mod),
2244 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],2247 .Union => mod.typeToUnion(ty).?.field_names.get(ip)[field_i],
2245 else => unreachable,2248 else => unreachable,
2246 }));2249 }));
src/type.zig+16-4
...@@ -2907,16 +2907,28 @@ pub const Type = struct {...@@ -2907,16 +2907,28 @@ pub const Type = struct {
2907 return enum_type.tagValueIndex(ip, int_tag);2907 return enum_type.tagValueIndex(ip, int_tag);
2908 }2908 }
29092909
2910 pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {2910 /// Returns none in the case of a tuple which uses the integer index as the field name.
2911 pub fn structFieldName(ty: Type, field_index: u32, mod: *Module) InternPool.OptionalNullTerminatedString {
2911 const ip = &mod.intern_pool;2912 const ip = &mod.intern_pool;
2912 return switch (ip.indexToKey(ty.toIntern())) {2913 return switch (ip.indexToKey(ty.toIntern())) {
2913 .struct_type => |struct_type| struct_type.field_names.get(ip)[field_index],2914 .struct_type => |struct_type| struct_type.fieldName(ip, field_index),
2914 .anon_struct_type => |anon_struct| anon_struct.names.get(ip)[field_index],2915 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, field_index),
2915 else => unreachable,2916 else => unreachable,
2916 };2917 };
2917 }2918 }
29182919
2919 pub fn structFieldCount(ty: Type, mod: *Module) usize {2920 /// When struct types have no field names, the names are implicitly understood to be
2921 /// strings corresponding to the field indexes in declaration order. It used to be the
2922 /// case that a NullTerminatedString would be stored for each field in this case, however,
2923 /// now, callers must handle the possibility that there are no names stored at all.
2924 /// Here we fake the previous behavior. Probably something better could be done by examining
2925 /// all the callsites of this function.
2926 pub fn legacyStructFieldName(ty: Type, i: u32, mod: *Module) InternPool.NullTerminatedString {
2927 return ty.structFieldName(i, mod).unwrap() orelse
2928 mod.intern_pool.getOrPutStringFmt(mod.gpa, "{d}", .{i}) catch @panic("OOM");
2929 }
2930
2931 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
2920 const ip = &mod.intern_pool;2932 const ip = &mod.intern_pool;
2921 return switch (ip.indexToKey(ty.toIntern())) {2933 return switch (ip.indexToKey(ty.toIntern())) {
2922 .struct_type => |struct_type| struct_type.field_types.len,2934 .struct_type => |struct_type| struct_type.field_types.len,