commit ac64c758761108ef7e07efea0936d7efc3eb2eca (tree)
parent 866989881927f256af1c495577007d715c6ae610
Author: Jacob Young <jacobly0@users.noreply.github.com>
Date: Sat, 3 Jan 2026 02:55:18 -0500
Dwarf: implement pointers to more comptime values
Closes #30600
Closes #30602
Diffstat:
3 files changed, 126 insertions(+), 16 deletions(-)
diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig
@@ -3618,7 +3618,7 @@ fn updateLazyType(
try wip_nav.strp(name);
if (array_type.sentinel != .none) try wip_nav.blockValue(src_loc, .fromInterned(array_type.sentinel));
try wip_nav.refType(array_child_type);
- try wip_nav.abbrevCode(.array_index);
+ try wip_nav.abbrevCode(.array_len);
try wip_nav.refType(.usize);
try diw.writeUleb128(array_type.len);
try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
@@ -3627,7 +3627,7 @@ fn updateLazyType(
try wip_nav.abbrevCode(.vector_type);
try wip_nav.strp(name);
try wip_nav.refType(.fromInterned(vector_type.child));
- try wip_nav.abbrevCode(.array_index);
+ try wip_nav.abbrevCode(.array_len);
try wip_nav.refType(.usize);
try diw.writeUleb128(vector_type.len);
try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
@@ -4177,24 +4177,38 @@ fn updateLazyValue(
try wip_nav.refType(.fromInterned(float.ty));
},
.ptr => |ptr| {
+ const Access = union(enum) {
+ index: u64,
+ field: InternPool.NullTerminatedString,
+ synthetic_field: []const u8,
+ tuple_index: u32,
+ };
+ var zero_bit_accesses: std.ArrayList(Access) = .empty;
+ defer zero_bit_accesses.deinit(dwarf.gpa);
location: {
var base_addr = ptr.base_addr;
var byte_offset = ptr.byte_offset;
const base_unit, const base_entry = while (true) {
- const base_ptr = base_ptr: switch (base_addr) {
+ const base_ptr, const access: Access = base_ptr_access: switch (base_addr) {
.nav => |nav_index| break try wip_nav.getNavEntry(nav_index),
.comptime_alloc, .comptime_field => unreachable,
.uav => |uav| {
const uav_ty: Type = .fromInterned(ip.typeOf(uav.val));
if (try uav_ty.onePossibleValue(pt)) |_| {
- try wip_nav.abbrevCode(.udata_comptime_value);
+ try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
+ .aggregate_udata_comptime_value
+ else
+ .udata_comptime_value);
try diw.writeUleb128(ip.indexToKey(uav.orig_ty).ptr_type.flags.alignment.toByteUnits() orelse
uav_ty.abiAlignment(zcu).toByteUnits().?);
break :location;
} else break try wip_nav.getValueEntry(.fromInterned(uav.val));
},
.int => {
- try wip_nav.abbrevCode(.udata_comptime_value);
+ try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
+ .aggregate_udata_comptime_value
+ else
+ .udata_comptime_value);
try diw.writeUleb128(byte_offset);
break :location;
},
@@ -4203,16 +4217,40 @@ fn updateLazyValue(
byte_offset += codegen.errUnionPayloadOffset(.fromInterned(ip.indexToKey(
ip.indexToKey(base_ptr.ty).ptr_type.child,
).error_union_type.payload_type), zcu);
- break :base_ptr base_ptr;
+ break :base_ptr_access .{ base_ptr, .{ .synthetic_field = "value" } };
+ },
+ .opt_payload => |opt_ptr| .{ ip.indexToKey(opt_ptr).ptr, .{ .synthetic_field = "?" } },
+ .field => |field| {
+ const base_ptr = ip.indexToKey(field.base).ptr;
+ const agg_ty: Type = .fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child);
+ break :base_ptr_access .{
+ base_ptr,
+ if (agg_ty.isSlice(zcu)) .{ .synthetic_field = switch (field.index) {
+ Value.slice_ptr_index => "ptr",
+ Value.slice_len_index => "len",
+ else => unreachable,
+ } } else if (agg_ty.structFieldName(@intCast(field.index), zcu).unwrap()) |field_name|
+ .{ .field = field_name }
+ else
+ .{ .tuple_index = @intCast(field.index) },
+ };
+ },
+ .arr_elem => |arr_elem| .{
+ ip.indexToKey(arr_elem.base).ptr,
+ .{ .index = arr_elem.index },
},
- .opt_payload => |opt_ptr| ip.indexToKey(opt_ptr).ptr,
- .field => unreachable,
- .arr_elem => unreachable,
};
base_addr = base_ptr.base_addr;
byte_offset += base_ptr.byte_offset;
+ if (Type.fromInterned(ip.indexToKey(base_ptr.ty).ptr_type.child).hasRuntimeBits(zcu))
+ assert(access != .index)
+ else
+ try zero_bit_accesses.append(dwarf.gpa, access);
};
- try wip_nav.abbrevCode(.location_comptime_value);
+ try wip_nav.abbrevCode(if (zero_bit_accesses.items.len > 0)
+ .aggregate_location_comptime_value
+ else
+ .location_comptime_value);
try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
.unit = base_unit,
.entry = base_entry,
@@ -4220,6 +4258,29 @@ fn updateLazyValue(
} });
}
try wip_nav.refType(.fromInterned(ptr.ty));
+ if (zero_bit_accesses.items.len > 0) {
+ for (zero_bit_accesses.items) |access| switch (access) {
+ .index => |index| {
+ try wip_nav.abbrevCode(.array_index);
+ try diw.writeUleb128(index);
+ },
+ .field => |field| {
+ try wip_nav.abbrevCode(.field);
+ try wip_nav.strp(field.toSlice(ip));
+ },
+ .synthetic_field => |field| {
+ try wip_nav.abbrevCode(.field);
+ try wip_nav.strp(field);
+ },
+ .tuple_index => |index| {
+ try wip_nav.abbrevCode(.field);
+ var field_name_buf: [std.fmt.count("{d}", .{std.math.maxInt(u32)})]u8 = undefined;
+ const field_name = std.fmt.bufPrint(&field_name_buf, "{d}", .{index}) catch unreachable;
+ try wip_nav.strp(field_name);
+ },
+ };
+ try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
+ }
},
.slice => |slice| {
try wip_nav.abbrevCode(.aggregate_comptime_value);
@@ -4387,12 +4448,7 @@ fn updateLazyValue(
try dwarf.debug_info.section.replaceEntry(wip_nav.unit, wip_nav.entry, dwarf, wip_nav.debug_info.written());
}
-fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum {
- unpacked,
- opv_null,
- error_set,
- pointer,
-} {
+fn optRepr(opt_child_type: Type, zcu: *const Zcu) enum { unpacked, opv_null, error_set, pointer } {
if (opt_child_type.isNoReturn(zcu)) return .opv_null;
return switch (opt_child_type.toIntern()) {
.anyerror_type => .error_set,
@@ -5233,6 +5289,7 @@ const AbbrevCode = enum {
module,
empty_file,
file,
+ field,
signed_enum_field,
unsigned_enum_field,
big_enum_field,
@@ -5261,6 +5318,7 @@ const AbbrevCode = enum {
array_sentinel_type,
vector_type,
array_index,
+ array_len,
nullary_func_type,
func_type,
func_type_param,
@@ -5308,10 +5366,12 @@ const AbbrevCode = enum {
data16_comptime_value,
sdata_comptime_value,
udata_comptime_value,
+ aggregate_udata_comptime_value,
block_comptime_value,
string_comptime_value,
location_comptime_value,
aggregate_comptime_value,
+ aggregate_location_comptime_value,
comptime_value_field_runtime_bits,
comptime_value_field_comptime_state,
comptime_value_elem_runtime_bits,
@@ -5721,6 +5781,12 @@ const AbbrevCode = enum {
.{ .alignment, .udata },
},
},
+ .field = .{
+ .tag = .member,
+ .attrs = &.{
+ .{ .name, .strp },
+ },
+ },
.signed_enum_field = .{
.tag = .enumerator,
.attrs = &.{
@@ -5938,6 +6004,12 @@ const AbbrevCode = enum {
.array_index = .{
.tag = .subrange_type,
.attrs = &.{
+ .{ .lower_bound, .udata },
+ },
+ },
+ .array_len = .{
+ .tag = .subrange_type,
+ .attrs = &.{
.{ .type, .ref_addr },
.{ .count, .udata },
},
@@ -6325,6 +6397,14 @@ const AbbrevCode = enum {
.{ .type, .ref_addr },
},
},
+ .aggregate_udata_comptime_value = .{
+ .tag = .ZIG_comptime_value,
+ .children = true,
+ .attrs = &.{
+ .{ .const_value, .udata },
+ .{ .type, .ref_addr },
+ },
+ },
.block_comptime_value = .{
.tag = .ZIG_comptime_value,
.attrs = &.{
@@ -6353,6 +6433,14 @@ const AbbrevCode = enum {
.{ .type, .ref_addr },
},
},
+ .aggregate_location_comptime_value = .{
+ .tag = .ZIG_comptime_value,
+ .children = true,
+ .attrs = &.{
+ .{ .location, .exprloc },
+ .{ .type, .ref_addr },
+ },
+ },
.comptime_value_field_runtime_bits = .{
.tag = .member,
.attrs = &.{
diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig
@@ -158,6 +158,18 @@ test "slice of type" {
}
}
+test "pass a slice of types to a function" {
+ const S = struct {
+ fn checkTypesSlice(types_slice: []const type) !void {
+ try expect(types_slice.len == 2);
+ try expect(types_slice[0] == anyerror);
+ try expect(types_slice[1] == bool);
+ }
+ };
+ const types_array = [_]type{ void, anyerror, bool };
+ try S.checkTypesSlice(types_array[1..]);
+}
+
test "generic malloc free" {
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig
@@ -2174,3 +2174,13 @@ test "avoid unused field function body compile error" {
try expect(Case.entry() == 1);
}
+
+test "pass a pointer to a comptime-only struct field to a function" {
+ const S = struct {
+ fn checkField(field_ptr: *const type) !void {
+ try expect(field_ptr.* == u42);
+ }
+ };
+ const s: struct { x: type } = .{ .x = u42 };
+ try S.checkField(&s.x);
+}