InternPool: fix enough crashes to run build-obj on a simple program

This commit is contained in:
Jacob Young 2023-05-25 23:48:39 -04:00 committed by Andrew Kelley
parent 9a738c0be5
commit 9afa974183
7 changed files with 228 additions and 115 deletions

View file

@ -2298,7 +2298,7 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
ip.* = undefined;
}
pub fn indexToKey(ip: InternPool, index: Index) Key {
pub fn indexToKey(ip: *const InternPool, index: Index) Key {
assert(index != .none);
const item = ip.items.get(@enumToInt(index));
const data = item.data;
@ -2361,7 +2361,7 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.type_slice => {
const ptr_type_index = @intToEnum(Index, data);
var result = indexToKey(ip, ptr_type_index).ptr_type;
var result = ip.indexToKey(ptr_type_index).ptr_type;
result.size = .Slice;
return .{ .ptr_type = result };
},
@ -2454,9 +2454,9 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.values_map = .none,
} };
},
.type_enum_explicit => indexToKeyEnum(ip, data, .explicit),
.type_enum_nonexhaustive => indexToKeyEnum(ip, data, .nonexhaustive),
.type_function => .{ .func_type = indexToKeyFuncType(ip, data) },
.type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
.type_enum_nonexhaustive => ip.indexToKeyEnum(data, .nonexhaustive),
.type_function => .{ .func_type = ip.indexToKeyFuncType(data) },
.undef => .{ .undef = @intToEnum(Index, data) },
.runtime_value => {
@ -2591,8 +2591,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.ty = .comptime_int_type,
.storage = .{ .i64 = @bitCast(i32, data) },
} },
.int_positive => indexToKeyBigInt(ip, data, true),
.int_negative => indexToKeyBigInt(ip, data, false),
.int_positive => ip.indexToKeyBigInt(data, true),
.int_negative => ip.indexToKeyBigInt(data, false),
.int_small => {
const info = ip.extraData(IntSmall, data);
return .{ .int = .{
@ -3430,22 +3430,25 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.data = try ip.addExtra(gpa, err),
}),
.error_union => |error_union| ip.items.appendAssumeCapacity(switch (error_union.val) {
.err_name => |err_name| .{
.tag = .error_union_error,
.data = try ip.addExtra(gpa, Key.Error{
.ty = error_union.ty,
.name = err_name,
}),
},
.payload => |payload| .{
.tag = .error_union_payload,
.data = try ip.addExtra(gpa, TypeValue{
.ty = error_union.ty,
.val = payload,
}),
},
}),
.error_union => |error_union| {
assert(ip.indexToKey(error_union.ty) == .error_union_type);
ip.items.appendAssumeCapacity(switch (error_union.val) {
.err_name => |err_name| .{
.tag = .error_union_error,
.data = try ip.addExtra(gpa, Key.Error{
.ty = error_union.ty,
.name = err_name,
}),
},
.payload => |payload| .{
.tag = .error_union_payload,
.data = try ip.addExtra(gpa, TypeValue{
.ty = error_union.ty,
.val = payload,
}),
},
});
},
.enum_literal => |enum_literal| ip.items.appendAssumeCapacity(.{
.tag = .enum_literal,
@ -4191,6 +4194,7 @@ pub fn sliceLen(ip: InternPool, i: Index) Index {
/// * ptr <=> ptr
/// * null_value => opt
/// * payload => opt
/// * error set <=> error set
pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Allocator.Error!Index {
const old_ty = ip.typeOf(val);
if (old_ty == new_ty) return val;
@ -4230,6 +4234,13 @@ pub fn getCoerced(ip: *InternPool, gpa: Allocator, val: Index, new_ty: Index) Al
} }),
else => {},
},
.err => |err| switch (ip.indexToKey(new_ty)) {
.error_set_type, .inferred_error_set_type => return ip.get(gpa, .{ .err = .{
.ty = new_ty,
.name = err.name,
} }),
else => {},
},
else => {},
}
switch (ip.indexToKey(new_ty)) {

View file

@ -61,10 +61,10 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.work_item_id,
.work_group_size,
.work_group_id,
=> try self.verifyInst(inst, .{ .none, .none, .none }),
=> try self.verifyInstOperands(inst, .{ .none, .none, .none }),
.trap, .unreach => {
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInstOperands(inst, .{ .none, .none, .none });
// This instruction terminates the function, so everything should be dead
if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
},
@ -113,7 +113,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.c_va_copy,
=> {
const ty_op = data[inst].ty_op;
try self.verifyInst(inst, .{ ty_op.operand, .none, .none });
try self.verifyInstOperands(inst, .{ ty_op.operand, .none, .none });
},
.is_null,
.is_non_null,
@ -149,13 +149,13 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.c_va_end,
=> {
const un_op = data[inst].un_op;
try self.verifyInst(inst, .{ un_op, .none, .none });
try self.verifyInstOperands(inst, .{ un_op, .none, .none });
},
.ret,
.ret_load,
=> {
const un_op = data[inst].un_op;
try self.verifyInst(inst, .{ un_op, .none, .none });
try self.verifyInstOperands(inst, .{ un_op, .none, .none });
// This instruction terminates the function, so everything should be dead
if (self.live.count() > 0) return invalid("%{}: instructions still alive", .{inst});
},
@ -164,36 +164,36 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.wasm_memory_grow,
=> {
const pl_op = data[inst].pl_op;
try self.verifyInst(inst, .{ pl_op.operand, .none, .none });
try self.verifyInstOperands(inst, .{ pl_op.operand, .none, .none });
},
.prefetch => {
const prefetch = data[inst].prefetch;
try self.verifyInst(inst, .{ prefetch.ptr, .none, .none });
try self.verifyInstOperands(inst, .{ prefetch.ptr, .none, .none });
},
.reduce,
.reduce_optimized,
=> {
const reduce = data[inst].reduce;
try self.verifyInst(inst, .{ reduce.operand, .none, .none });
try self.verifyInstOperands(inst, .{ reduce.operand, .none, .none });
},
.union_init => {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.UnionInit, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.init, .none, .none });
try self.verifyInstOperands(inst, .{ extra.init, .none, .none });
},
.struct_field_ptr, .struct_field_val => {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.struct_operand, .none, .none });
try self.verifyInstOperands(inst, .{ extra.struct_operand, .none, .none });
},
.field_parent_ptr => {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.field_ptr, .none, .none });
try self.verifyInstOperands(inst, .{ extra.field_ptr, .none, .none });
},
.atomic_load => {
const atomic_load = data[inst].atomic_load;
try self.verifyInst(inst, .{ atomic_load.ptr, .none, .none });
try self.verifyInstOperands(inst, .{ atomic_load.ptr, .none, .none });
},
// binary
@ -263,7 +263,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
.memcpy,
=> {
const bin_op = data[inst].bin_op;
try self.verifyInst(inst, .{ bin_op.lhs, bin_op.rhs, .none });
try self.verifyInstOperands(inst, .{ bin_op.lhs, bin_op.rhs, .none });
},
.add_with_overflow,
.sub_with_overflow,
@ -277,48 +277,48 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
=> {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none });
},
.shuffle => {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.Shuffle, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.a, extra.b, .none });
try self.verifyInstOperands(inst, .{ extra.a, extra.b, .none });
},
.cmp_vector,
.cmp_vector_optimized,
=> {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.VectorCmp, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, .none });
try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, .none });
},
.atomic_rmw => {
const pl_op = data[inst].pl_op;
const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
try self.verifyInst(inst, .{ pl_op.operand, extra.operand, .none });
try self.verifyInstOperands(inst, .{ pl_op.operand, extra.operand, .none });
},
// ternary
.select => {
const pl_op = data[inst].pl_op;
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
try self.verifyInst(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
try self.verifyInstOperands(inst, .{ pl_op.operand, extra.lhs, extra.rhs });
},
.mul_add => {
const pl_op = data[inst].pl_op;
const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
try self.verifyInst(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
try self.verifyInstOperands(inst, .{ extra.lhs, extra.rhs, pl_op.operand });
},
.vector_store_elem => {
const vector_store_elem = data[inst].vector_store_elem;
const extra = self.air.extraData(Air.Bin, vector_store_elem.payload).data;
try self.verifyInst(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
try self.verifyInstOperands(inst, .{ vector_store_elem.vector_ptr, extra.lhs, extra.rhs });
},
.cmpxchg_strong,
.cmpxchg_weak,
=> {
const ty_pl = data[inst].ty_pl;
const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
try self.verifyInst(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
try self.verifyInstOperands(inst, .{ extra.ptr, extra.expected_value, extra.new_value });
},
// big tombs
@ -332,7 +332,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (elements) |element| {
try self.verifyOperand(inst, element, bt.feed());
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.call, .call_always_tail, .call_never_tail, .call_never_inline => {
const pl_op = data[inst].pl_op;
@ -347,7 +347,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (args) |arg| {
try self.verifyOperand(inst, arg, bt.feed());
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.assembly => {
const ty_pl = data[inst].ty_pl;
@ -373,7 +373,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (inputs) |input| {
try self.verifyOperand(inst, input, bt.feed());
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
// control flow
@ -397,7 +397,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.try_ptr => {
const ty_pl = data[inst].ty_pl;
@ -419,7 +419,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (cond_br_liveness.then_deaths) |death| try self.verifyDeath(inst, death);
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.br => {
const br = data[inst].br;
@ -431,7 +431,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
} else {
gop.value_ptr.* = try self.live.clone(self.gpa);
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.block => {
const ty_pl = data[inst].ty_pl;
@ -462,7 +462,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
try self.verifyMatchingLiveness(inst, live);
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInstOperands(inst, .{ .none, .none, .none });
},
.loop => {
const ty_pl = data[inst].ty_pl;
@ -477,7 +477,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
// The same stuff should be alive after the loop as before it
try self.verifyMatchingLiveness(inst, live);
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInstOperands(inst, .{ .none, .none, .none });
},
.cond_br => {
const pl_op = data[inst].pl_op;
@ -500,7 +500,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
for (cond_br_liveness.else_deaths) |death| try self.verifyDeath(inst, death);
try self.verifyBody(else_body);
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
.switch_br => {
const pl_op = data[inst].pl_op;
@ -544,7 +544,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
try self.verifyBody(else_body);
}
try self.verifyInst(inst, .{ .none, .none, .none });
try self.verifyInst(inst);
},
}
}
@ -570,7 +570,7 @@ fn verifyOperand(self: *Verify, inst: Air.Inst.Index, op_ref: Air.Inst.Ref, dies
}
}
fn verifyInst(
fn verifyInstOperands(
self: *Verify,
inst: Air.Inst.Index,
operands: [Liveness.bpi - 1]Air.Inst.Ref,
@ -579,6 +579,10 @@ fn verifyInst(
const dies = self.liveness.operandDies(inst, @intCast(Liveness.OperandInt, operand_index));
try self.verifyOperand(inst, operand, dies);
}
try self.verifyInst(inst);
}
fn verifyInst(self: *Verify, inst: Air.Inst.Index) Error!void {
if (self.air.instructions.items(.tag)[inst] == .interned) return;
if (self.liveness.isUnused(inst)) {
assert(!self.live.contains(inst));

View file

@ -16687,7 +16687,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const new_decl_ty = try mod.arrayType(.{
.len = bytes.len,
.child = .u8_type,
.sentinel = .zero_u8,
});
const new_decl = try anon_decl.finish(
new_decl_ty,
@ -16698,7 +16697,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
0, // default alignment
);
break :v try mod.intern(.{ .ptr = .{
.ty = .slice_const_u8_sentinel_0_type,
.ty = .slice_const_u8_type,
.addr = .{ .decl = new_decl },
.len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
} });
@ -23991,7 +23990,6 @@ fn panicWithMsg(
msg_inst: Air.Inst.Ref,
) !void {
const mod = sema.mod;
const arena = sema.arena;
if (!mod.backendSupportsFeature(.panic_fn)) {
_ = try block.addNoOp(.trap);
@ -24001,16 +23999,22 @@ fn panicWithMsg(
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
const target = mod.getTarget();
const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{
.pointee_type = stack_trace_ty,
.@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
const ptr_stack_trace_ty = try mod.ptrType(.{
.elem_type = stack_trace_ty.toIntern(),
.address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
});
const null_stack_trace = try sema.addConstant(
try Type.optional(arena, ptr_stack_trace_ty, mod),
Value.null,
);
const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };
try sema.callBuiltin(block, panic_fn, .auto, &args);
const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
.ty = opt_ptr_stack_trace_ty.toIntern(),
.val = .none,
} })).toValue());
const opt_usize_ty = try mod.optionalType(.usize_type);
const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{
.ty = opt_usize_ty.toIntern(),
.val = .none,
} })).toValue());
try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr });
}
fn panicUnwrapError(
@ -29395,13 +29399,10 @@ fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
const mod = sema.mod;
const val = opt_val orelse return Value.null;
const ptr_val = try sema.refValue(block, ty, val);
const result = try mod.intern(.{ .opt = .{
.ty = (try mod.optionalType((try mod.singleConstPtrType(ty)).toIntern())).toIntern(),
.val = ptr_val.toIntern(),
} });
return result.toValue();
return (try mod.intern(.{ .opt = .{
.ty = (try mod.optionalType((try mod.singleConstPtrType(Type.anyopaque)).toIntern())).toIntern(),
.val = if (opt_val) |val| (try sema.refValue(block, ty, val)).toIntern() else .none,
} })).toValue();
}
fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
@ -30603,7 +30604,7 @@ fn wrapErrorUnionPayload(
if (try sema.resolveMaybeUndefVal(coerced)) |val| {
return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
.ty = dest_ty.toIntern(),
.val = .{ .payload = val.toIntern() },
.val = .{ .payload = try val.intern(dest_payload_ty, mod) },
} })).toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
@ -30647,7 +30648,12 @@ fn wrapErrorUnionSet(
else => unreachable,
},
}
return sema.addConstant(dest_ty, val);
return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
.ty = dest_ty.toIntern(),
.val = .{
.err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name,
},
} })).toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
@ -33325,7 +33331,7 @@ fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
}
fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
return sema.addConstant(ty, Value.undef);
return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue());
}
pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {

View file

@ -3267,21 +3267,28 @@ pub const DeclGen = struct {
return llvm_ty.constInt(kv.value, .False);
},
.error_union => |error_union| {
const err_tv: TypedValue = switch (error_union.val) {
.err_name => |err_name| .{
.ty = tv.ty.errorUnionSet(mod),
.val = (try mod.intern(.{ .err = .{
.ty = tv.ty.errorUnionSet(mod).toIntern(),
.name = err_name,
} })).toValue(),
},
.payload => .{
.ty = Type.err_int,
.val = try mod.intValue(Type.err_int, 0),
},
};
const payload_type = tv.ty.errorUnionPayload(mod);
const is_pl = tv.val.errorUnionIsPayload(mod);
if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
// We use the error type directly as the type.
const err_val = if (!is_pl) tv.val else try mod.intValue(Type.err_int, 0);
return dg.lowerValue(.{ .ty = Type.anyerror, .val = err_val });
return dg.lowerValue(err_tv);
}
const payload_align = payload_type.abiAlignment(mod);
const error_align = Type.anyerror.abiAlignment(mod);
const llvm_error_value = try dg.lowerValue(.{
.ty = Type.anyerror,
.val = if (is_pl) try mod.intValue(Type.err_int, 0) else tv.val,
});
const error_align = err_tv.ty.abiAlignment(mod);
const llvm_error_value = try dg.lowerValue(err_tv);
const llvm_payload_value = try dg.lowerValue(.{
.ty = payload_type,
.val = switch (error_union.val) {

View file

@ -703,7 +703,7 @@ const Writer = struct {
const pl_op = w.air.instructions.items(.data)[inst].pl_op;
try w.writeOperand(s, inst, 0, pl_op.operand);
const name = w.air.nullTerminatedString(pl_op.payload);
try s.print(", {s}", .{name});
try s.print(", \"{}\"", .{std.zig.fmtEscapes(name)});
}
fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {

View file

@ -347,6 +347,43 @@ pub const Value = struct {
pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index {
if (val.ip_index != .none) return mod.intern_pool.getCoerced(mod.gpa, val.toIntern(), ty.toIntern());
switch (val.tag()) {
.eu_payload => {
const pl = val.castTag(.eu_payload).?.data;
return mod.intern(.{ .error_union = .{
.ty = ty.toIntern(),
.val = .{ .payload = try pl.intern(ty.errorUnionPayload(mod), mod) },
} });
},
.opt_payload => {
const pl = val.castTag(.opt_payload).?.data;
return mod.intern(.{ .opt = .{
.ty = ty.toIntern(),
.val = try pl.intern(ty.optionalChild(mod), mod),
} });
},
.slice => {
const pl = val.castTag(.slice).?.data;
const ptr = try pl.ptr.intern(ty.optionalChild(mod), mod);
var ptr_key = mod.intern_pool.indexToKey(ptr).ptr;
assert(ptr_key.len == .none);
ptr_key.ty = ty.toIntern();
ptr_key.len = try pl.len.intern(Type.usize, mod);
return mod.intern(.{ .ptr = ptr_key });
},
.bytes => {
const pl = val.castTag(.bytes).?.data;
return mod.intern(.{ .aggregate = .{
.ty = ty.toIntern(),
.storage = .{ .bytes = pl },
} });
},
.repeated => {
const pl = val.castTag(.repeated).?.data;
return mod.intern(.{ .aggregate = .{
.ty = ty.toIntern(),
.storage = .{ .repeated_elem = try pl.intern(ty.childType(mod), mod) },
} });
},
.aggregate => {
const old_elems = val.castTag(.aggregate).?.data;
const new_elems = try mod.gpa.alloc(InternPool.Index, old_elems.len);
@ -372,24 +409,74 @@ pub const Value = struct {
.val = try pl.val.intern(ty.unionFieldType(pl.tag, mod), mod),
} });
},
else => unreachable,
}
}
pub fn unintern(val: Value, arena: Allocator, mod: *Module) Allocator.Error!Value {
if (val.ip_index == .none) return val;
switch (mod.intern_pool.indexToKey(val.toIntern())) {
return if (val.ip_index == .none) val else switch (mod.intern_pool.indexToKey(val.toIntern())) {
.int_type,
.ptr_type,
.array_type,
.vector_type,
.opt_type,
.anyframe_type,
.error_union_type,
.simple_type,
.struct_type,
.anon_struct_type,
.union_type,
.opaque_type,
.enum_type,
.func_type,
.error_set_type,
.inferred_error_set_type,
.undef,
.runtime_value,
.simple_value,
.variable,
.extern_func,
.func,
.int,
.err,
.enum_literal,
.enum_tag,
.float,
=> val,
.error_union => |error_union| switch (error_union.val) {
.err_name => val,
.payload => |payload| Tag.eu_payload.create(arena, payload.toValue()),
},
.ptr => |ptr| switch (ptr.len) {
.none => val,
else => |len| Tag.slice.create(arena, .{
.ptr = val.slicePtr(mod),
.len = len.toValue(),
}),
},
.opt => |opt| switch (opt.val) {
.none => val,
else => |payload| Tag.opt_payload.create(arena, payload.toValue()),
},
.aggregate => |aggregate| switch (aggregate.storage) {
.bytes => |bytes| return Tag.bytes.create(arena, try arena.dupe(u8, bytes)),
.bytes => |bytes| Tag.bytes.create(arena, try arena.dupe(u8, bytes)),
.elems => |old_elems| {
const new_elems = try arena.alloc(Value, old_elems.len);
for (new_elems, old_elems) |*new_elem, old_elem| new_elem.* = old_elem.toValue();
return Tag.aggregate.create(arena, new_elems);
},
.repeated_elem => |elem| return Tag.repeated.create(arena, elem.toValue()),
.repeated_elem => |elem| Tag.repeated.create(arena, elem.toValue()),
},
else => return val,
}
.un => |un| Tag.@"union".create(arena, .{
.tag = un.tag.toValue(),
.val = un.val.toValue(),
}),
};
}
pub fn toIntern(val: Value) InternPool.Index {
@ -1896,7 +1983,7 @@ pub const Value = struct {
/// Returns true if a Value is backed by a variable
pub fn isVariable(val: Value, mod: *Module) bool {
return switch (mod.intern_pool.indexToKey(val.toIntern())) {
return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => true,
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl_index| {
@ -1919,28 +2006,25 @@ pub const Value = struct {
}
pub fn isPtrToThreadLocal(val: Value, mod: *Module) bool {
return switch (val.ip_index) {
.none => false,
else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => |variable| variable.is_threadlocal,
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl_index| {
const decl = mod.declPtr(decl_index);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
},
.mut_decl => |mut_decl| {
const decl = mod.declPtr(mut_decl.decl);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
},
.int => false,
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
return val.ip_index != .none and switch (mod.intern_pool.indexToKey(val.toIntern())) {
.variable => |variable| variable.is_threadlocal,
.ptr => |ptr| switch (ptr.addr) {
.decl => |decl_index| {
const decl = mod.declPtr(decl_index);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
},
else => false,
.mut_decl => |mut_decl| {
const decl = mod.declPtr(mut_decl.decl);
assert(decl.has_tv);
return decl.val.isPtrToThreadLocal(mod);
},
.int => false,
.eu_payload, .opt_payload => |base_ptr| base_ptr.toValue().isPtrToThreadLocal(mod),
.comptime_field => |comptime_field| comptime_field.toValue().isPtrToThreadLocal(mod),
.elem, .field => |base_index| base_index.base.toValue().isPtrToThreadLocal(mod),
},
else => false,
};
}

View file

@ -681,6 +681,7 @@ def __lldb_init_module(debugger, _=None):
add(debugger, category='zig.stage2', regex=True, type=MultiArrayList_Entry('Air\\.Inst'), identifier='TagAndPayload', synth=True, inline_children=True, summary=True)
add(debugger, category='zig.stage2', regex=True, type='^Air\\.Inst\\.Data\\.Data__struct_[1-9][0-9]*$', inline_children=True, summary=True)
add(debugger, category='zig.stage2', type='Module.Decl::Module.Decl.Index', synth=True)
add(debugger, category='zig.stage2', type='Module.LazySrcLoc', identifier='zig_TaggedUnion', synth=True)
add(debugger, category='zig.stage2', type='InternPool.Index', synth=True)
add(debugger, category='zig.stage2', type='InternPool.Key', identifier='zig_TaggedUnion', synth=True)
add(debugger, category='zig.stage2', type='InternPool.Key.Int.Storage', identifier='zig_TaggedUnion', synth=True)