From ac64c758761108ef7e07efea0936d7efc3eb2eca Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Sat, 3 Jan 2026 02:55:18 -0500 Subject: [PATCH] Dwarf: implement pointers to more comptime values Closes #30600 Closes #30602 --- src/link/Dwarf.zig | 120 +++++++++++++++++++++++++++++++++------ test/behavior/slice.zig | 12 ++++ test/behavior/struct.zig | 10 ++++ 3 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 0fda09e385..d3fff513f4 100644 --- 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 = &.{ @@ -5936,6 +6002,12 @@ const AbbrevCode = enum { }, }, .array_index = .{ + .tag = .subrange_type, + .attrs = &.{ + .{ .lower_bound, .udata }, + }, + }, + .array_len = .{ .tag = .subrange_type, .attrs = &.{ .{ .type, .ref_addr }, @@ -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 index 98760458ae..4de7b26d34 100644 --- 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 index b84ad4556c..08aca075d7 100644 --- 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); +}