compiler,std: various little fixes

This commit is contained in:
Matthew Lugg 2026-03-02 17:35:02 +00:00
parent e8e80cfa47
commit 7561f1e004
No known key found for this signature in database
GPG key ID: 3F5B7DCCBF4AF02E
10 changed files with 174 additions and 76 deletions

View file

@ -1526,9 +1526,9 @@ pub fn HashMapUnmanaged(
}
comptime {
if (!builtin.strip_debug_info) _ = switch (builtin.zig_backend) {
.stage2_llvm => &dbHelper,
.stage2_x86_64 => KV,
if (!builtin.strip_debug_info) switch (builtin.zig_backend) {
.stage2_llvm => _ = &dbHelper,
.stage2_x86_64 => _ = @as(KV, undefined),
else => {},
};
}

View file

@ -3334,11 +3334,17 @@ pub const LoadedStructType = struct {
field_defaults: Index.Slice,
field_aligns: Alignment.Slice,
field_is_comptime_bits: ComptimeBits,
/// If `layout` is `.@"packed"`, this is `.empty`.
field_runtime_order: RuntimeOrder.Slice,
/// If `layout` is `.@"packed"`, this is `.empty`.
field_offsets: Offsets,
/// Only valid if `layout` is `.@"packed"`.
packed_backing_int_type: Index,
/// Only valid if `layout` is *not* `.@"packed"`.
class: TypeClass,
/// Only valid if `layout` is *not* `.@"packed"`.
size: u32,
/// Only valid if `layout` is *not* `.@"packed"`.
alignment: Alignment,
pub const ComptimeBits = struct {
@ -3516,15 +3522,21 @@ pub const LoadedUnionType = struct {
tag_usage: TagUsage,
/// While `tag_usage` indicates whether the union should logically contain a tag, it may be
/// omitted if the union layout is resolved as OPV or NPV. This field is `true` iff there is an
/// actual runtime tag in the union layout.
/// actual runtime tag, with one or more runtime bits, in the union layout. It is always `false`
/// if `layout` is not `.auto`.
has_runtime_tag: bool,
/// Even if `tag_usage == .none` and `has_runtime_tag == false`, this is still populated with
/// the union's "hypothetical" tag type.
enum_tag_type: Index,
/// Only valid if `layout` is `.@"packed"`.
packed_backing_int_type: Index,
/// Not valid if `layout` is `.@"packed"`.
class: TypeClass,
/// Not valid if `layout` is `.@"packed"`.
size: u32,
/// Not valid if `layout` is `.@"packed"`.
padding: u32,
/// Not valid if `layout` is `.@"packed"`.
alignment: Alignment,
pub const TagUsage = enum(u2) {
@ -3898,7 +3910,7 @@ pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
.want_layout = extra.data.bits.want_layout,
.field_types = field_types,
.field_aligns = .empty,
.has_runtime_tag = undefined,
.has_runtime_tag = false,
.class = undefined,
.size = undefined,
.padding = undefined,

View file

@ -13777,45 +13777,44 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
// lhs_dest_slice = dest[0..lhs.len]
const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
const lhs_len_ref = try pt.intRef(.usize, lhs_len);
const lhs_dest_slice = try block.addInst(.{
.tag = .slice,
.data = .{ .ty_pl = .{
.ty = slice_ty_ref,
.payload = try sema.addExtra(Air.Bin{
.lhs = many_alloc,
.rhs = lhs_len_ref,
}),
} },
});
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
if (lhs_len > 0) {
const lhs_dest_slice = try block.addInst(.{
.tag = .slice,
.data = .{ .ty_pl = .{
.ty = .fromType(slice_ty),
.payload = try sema.addExtra(Air.Bin{
.lhs = many_alloc,
.rhs = try pt.intRef(.usize, lhs_len),
}),
} },
});
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
}
// rhs_dest_slice = dest[lhs.len..][0..rhs.len]
const rhs_len_ref = try pt.intRef(.usize, rhs_len);
const rhs_dest_offset = try block.addInst(.{
.tag = .ptr_add,
.data = .{ .ty_pl = .{
.ty = Air.internedToRef(many_ty.toIntern()),
.payload = try sema.addExtra(Air.Bin{
.lhs = many_alloc,
.rhs = lhs_len_ref,
}),
} },
});
const rhs_dest_slice = try block.addInst(.{
.tag = .slice,
.data = .{ .ty_pl = .{
.ty = slice_ty_ref,
.payload = try sema.addExtra(Air.Bin{
.lhs = rhs_dest_offset,
.rhs = rhs_len_ref,
}),
} },
});
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
if (rhs_len > 0) {
const rhs_dest_offset = try block.addInst(.{
.tag = .ptr_add,
.data = .{ .ty_pl = .{
.ty = Air.internedToRef(many_ty.toIntern()),
.payload = try sema.addExtra(Air.Bin{
.lhs = many_alloc,
.rhs = try pt.intRef(.usize, lhs_len),
}),
} },
});
const rhs_dest_slice = try block.addInst(.{
.tag = .slice,
.data = .{ .ty_pl = .{
.ty = .fromType(slice_ty),
.payload = try sema.addExtra(Air.Bin{
.lhs = rhs_dest_offset,
.rhs = try pt.intRef(.usize, rhs_len),
}),
} },
});
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
}
if (res_sent_val) |sent_val| {
const elem_index = try pt.intRef(.usize, result_len);
@ -18829,7 +18828,7 @@ fn finishStructInit(
return sema.addConstantMaybeRef(sema.resolveValue(final_val_ref).?, is_ref);
},
.@"packed" => {
const buf = try sema.arena.alloc(u8, (struct_ty.bitSize(zcu) + 7) / 8);
const buf = try sema.arena.alloc(u8, @intCast((struct_ty.bitSize(zcu) + 7) / 8));
var bit_offset: u16 = 0;
for (field_inits) |field_init| {
const field_val = sema.resolveValue(field_init).?;

View file

@ -895,7 +895,7 @@ pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value {
// Avoid hitting gpa for accesses to small packed structs
var sfba_state = std.heap.stackFallback(128, zcu.comp.gpa);
const sfba = sfba_state.get();
const buf = try sfba.alloc(u8, (ty.bitSize(zcu) + 7) / 8);
const buf = try sfba.alloc(u8, @intCast((ty.bitSize(zcu) + 7) / 8));
defer sfba.free(buf);
int_val.writeToPackedMemory(pt, buf, 0) catch |err| switch (err) {
error.ReinterpretDeclRef => unreachable, // it's an integer
@ -2419,7 +2419,7 @@ pub fn uninterpret(val: anytype, ty: Type, pt: Zcu.PerThread) error{ OutOfMemory
}
for (field_vals, 0..) |*field_val, field_idx| {
if (field_val.* == .none) {
const default_init = struct_obj.field_inits.get(ip)[field_idx];
const default_init = struct_obj.field_defaults.get(ip)[field_idx];
if (default_init == .none) return error.TypeMismatch;
field_val.* = default_init;
}

View file

@ -3686,6 +3686,11 @@ pub const ImportResult = struct {
pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
const gpa = zcu.comp.gpa;
if (!dev.env.supports(.incremental)) {
// This is the first time `unit` is being analyzed, so there is no stale data to clear.
return;
}
// Compile errors
if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
kv.value.destroy(gpa);

View file

@ -1075,7 +1075,6 @@ pub fn ensureMemoizedStateUpToDate(
const prev_failed = zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit);
if (was_outdated) {
dev.check(.incremental);
zcu.resetUnit(unit);
} else {
if (prev_failed) return error.AnalysisFail;
@ -1193,10 +1192,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
const was_outdated = zcu.clearOutdatedState(anal_unit);
if (was_outdated) {
// `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
if (dev.env.supports(.incremental)) {
zcu.resetUnit(anal_unit);
}
zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
@ -1366,10 +1362,7 @@ pub fn ensureTypeLayoutUpToDate(
};
if (was_outdated) {
// `was_outdated` is true in the initial update, so this isn't a `dev.check`.
if (dev.env.supports(.incremental)) {
zcu.resetUnit(anal_unit);
}
zcu.resetUnit(anal_unit);
// For types, we already know that we have to invalidate all dependees.
// TODO: we actually *could* detect whether everything was the same. should we bother?
try zcu.markDependeeOutdated(.marked_po, .{ .type_layout = ty.toIntern() });
@ -1492,10 +1485,7 @@ pub fn ensureStructDefaultsUpToDate(
};
if (was_outdated) {
// `was_outdated` is true in the initial update, so this isn't a `dev.check`.
if (dev.env.supports(.incremental)) {
zcu.resetUnit(anal_unit);
}
zcu.resetUnit(anal_unit);
// For types, we already know that we have to invalidate all dependees.
// TODO: we actually *could* detect whether everything was the same. should we bother?
try zcu.markDependeeOutdated(.marked_po, .{ .struct_defaults = ty.toIntern() });
@ -1609,7 +1599,6 @@ pub fn ensureNavValUpToDate(
zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
dev.check(.incremental);
zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
@ -1973,7 +1962,6 @@ pub fn ensureNavTypeUpToDate(
zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
dev.check(.incremental);
zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this unit.
@ -2210,7 +2198,6 @@ pub fn ensureFuncBodyUpToDate(
const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit);
if (was_outdated) {
dev.check(.incremental);
zcu.resetUnit(anal_unit);
} else {
// We can trust the current information about this function.
@ -2292,7 +2279,7 @@ fn analyzeFuncBody(
var air = try pt.analyzeFuncBodyInner(func_index, reason);
var air_owned = true;
errdefer if (air_owned) air.deinit(gpa);
defer if (air_owned) air.deinit(gpa);
const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
func.resolvedErrorSetUnordered(ip) != old_resolved_ies;

View file

@ -7132,9 +7132,9 @@ fn formatIntLiteral(data: FormatIntLiteralContext, w: *Writer) Writer.Error!void
var limb_buf: [std.math.big.int.calcTwosCompLimbCount(65535)]std.math.big.Limb = undefined;
for (0..big.limbs_len) |limb_index| {
if (limb_index != 0) try w.writeAll(", ");
const limb_bit_offset: u64 = switch (target.cpu.arch.endian()) {
.little => limb_index * big.limb_size.bits(),
.big => (big.limbs_len - limb_index - 1) * big.limb_size.bits(),
const limb_bit_offset: u16 = switch (target.cpu.arch.endian()) {
.little => @intCast(limb_index * big.limb_size.bits()),
.big => @intCast((big.limbs_len - limb_index - 1) * big.limb_size.bits()),
};
var limb_bigint: std.math.big.int.Mutable = .{
.limbs = &limb_buf,

View file

@ -2432,7 +2432,7 @@ pub const Object = struct {
const debug_payload_type = try o.builder.debugUnionType(
payload_name: {
if (layout.tag_size == 0) break :payload_name name;
break :payload_name try o.builder.metadataStringFmt("{s}:Payload", .{name.slice(&o.builder)});
break :payload_name try o.builder.metadataStringFmt("{f}:Payload", .{ty.fmt(pt)});
},
file,
scope,

View file

@ -1557,7 +1557,10 @@ pub fn doZcuTask(comp: *Compilation, tid: Zcu.PerThread.Id, task: ZcuTask) void
.link_func => |codegen_task| nav: {
timer.pause(io);
const func, var mir = codegen_task.wait(&zcu.codegen_task_pool, io) catch |err| switch (err) {
error.Canceled, error.AlreadyReported => return,
error.Canceled, error.AlreadyReported => {
comp.link_prog_node.completeOne();
return;
},
};
defer mir.deinit(zcu);
timer.@"resume"(io);

View file

@ -3344,6 +3344,7 @@ pub fn updateConstIncomplete(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index
}
fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.ConstPool.Index, value_index: InternPool.Index) !void {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
const val: Value = .fromInterned(value_index);
@ -3383,20 +3384,109 @@ fn updateConstIncompleteInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_inde
.debug_loclists = .init(dwarf.gpa),
};
defer wip_nav.deinit();
switch (val.typeOf(zcu).toIntern()) {
.type_type => {
try wip_nav.abbrevCode(.generated_empty_struct_type);
try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
switch (ip.indexToKey(value_index)) {
// Container types still need to be valid namespaces.
.struct_type => {
const loaded_struct = ip.loadStructType(value_index);
const root_of_file: ?Zcu.File.Index = if (loaded_struct.zir_index.resolveFull(ip)) |r| f: {
if (r.inst != .main_struct_inst) break :f null;
break :f r.file;
} else null;
if (root_of_file) |file_index| {
assert(loaded_struct.name_nav == .none);
const file_gop = try dwarf.getModInfo(unit).files.getOrPut(dwarf.gpa, file_index);
try wip_nav.abbrevCode(.empty_file);
try wip_nav.debug_info.writer.writeUleb128(file_gop.index);
try wip_nav.strp(loaded_struct.name.toSlice(ip));
} else {
try dwarf.emitIncompleteContainerType(
&wip_nav,
loaded_struct.zir_index,
loaded_struct.name,
loaded_struct.name_nav,
);
}
},
else => |ty| {
try wip_nav.abbrevCode(.undefined_comptime_value);
try wip_nav.refType(.fromInterned(ty));
.union_type => {
const loaded_union = ip.loadUnionType(value_index);
try dwarf.emitIncompleteContainerType(
&wip_nav,
loaded_union.zir_index,
loaded_union.name,
loaded_union.name_nav,
);
},
.enum_type => {
const loaded_enum = ip.loadEnumType(value_index);
if (loaded_enum.zir_index.unwrap()) |zir_index| {
try dwarf.emitIncompleteContainerType(
&wip_nav,
zir_index,
loaded_enum.name,
loaded_enum.name_nav,
);
} else {
try wip_nav.abbrevCode(.generated_empty_struct_type);
try wip_nav.strp(loaded_enum.name.toSlice(ip));
try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
}
},
.opaque_type => {
const loaded_opaque = ip.loadOpaqueType(value_index);
try dwarf.emitIncompleteContainerType(
&wip_nav,
loaded_opaque.zir_index,
loaded_opaque.name,
loaded_opaque.name_nav,
);
},
// Not a container type, so just emit a dummy entry. If `val` happens to be a type, we'll
// emit it as if it were an opaque type so that we can name it.
else => |val_key| switch (val_key.typeOf()) {
.type_type => {
try wip_nav.abbrevCode(.generated_empty_struct_type);
try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
},
else => |ty| {
try wip_nav.abbrevCode(.undefined_comptime_value);
try wip_nav.refType(.fromInterned(ty));
},
},
}
try dwarf.debug_info.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_info.written());
try dwarf.debug_loclists.section.replaceEntry(unit, entry, dwarf, wip_nav.debug_loclists.written());
}
fn emitIncompleteContainerType(
dwarf: *Dwarf,
wip_nav: *WipNav,
zir_index: InternPool.TrackedInst.Index,
name: InternPool.NullTerminatedString,
name_nav: InternPool.Nav.Index.Optional,
) !void {
const zcu = wip_nav.pt.zcu;
const ip = &zcu.intern_pool;
const file = zir_index.resolveFile(ip);
if (name_nav.unwrap()) |nav_index| {
const nav = ip.getNav(nav_index);
const decl_inst = nav.srcInst(ip).resolve(ip).?;
const decl = zcu.fileByIndex(file).zir.?.getDeclaration(decl_inst);
try wip_nav.declCommon(.{
.decl = .decl_namespace_struct,
.generic_decl = .generic_decl_const,
.decl_instance = .decl_instance_namespace_struct,
}, &nav, file, &decl);
try wip_nav.debug_info.writer.writeByte(@intFromBool(true));
} else {
const diw = &wip_nav.debug_info.writer;
const file_gop = try dwarf.getModInfo(wip_nav.unit).files.getOrPut(dwarf.gpa, file);
try wip_nav.abbrevCode(.empty_struct_type);
try diw.writeUleb128(file_gop.index);
try wip_nav.strp(name.toSlice(ip));
try diw.writeByte(@intFromBool(true));
}
}
/// Should only be called by the `link.ConstPool` implementation.
///
/// Emits a DIE for the given comptime-only value (which may be a type).
@ -3418,6 +3508,8 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
val.typeOf(zcu).assertHasLayout(zcu);
}
if (value_index == .anyerror_type) return; // handled in `flush` instead
const value_ip_key = ip.indexToKey(value_index);
switch (value_ip_key) {
.func => return, // populated by the Nav instead (`updateComptimeNav` or `initWipNav`)
@ -3746,7 +3838,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
try wip_nav.abbrevCode(.void_type);
try wip_nav.strpFmt("{f}", .{val.toType().fmt(pt)});
},
.anyerror => return, // delay until flush
.anyerror => unreachable, // already did early return above
.adhoc_inferred_error_set => unreachable,
},
.tuple_type => |tuple_type| if (tuple_type.types.len == 0) {