InternPool: fix yet more key lifetime issues
This commit is contained in:
committed by
Andrew Kelley
parent
6a15fc87ad
commit
e23b0a01e6
@@ -5448,7 +5448,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||
defer comptime_mutable_decls.deinit();
|
||||
|
||||
const fn_ty = decl.ty;
|
||||
const fn_ty_info = mod.typeToFunc(fn_ty).?;
|
||||
|
||||
var sema: Sema = .{
|
||||
.mod = mod,
|
||||
@@ -5459,7 +5458,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||
.owner_decl_index = decl_index,
|
||||
.func = func,
|
||||
.func_index = func_index.toOptional(),
|
||||
.fn_ret_ty = fn_ty_info.return_type.toType(),
|
||||
.fn_ret_ty = mod.typeToFunc(fn_ty).?.return_type.toType(),
|
||||
.owner_func = func,
|
||||
.owner_func_index = func_index.toOptional(),
|
||||
.branch_quota = @max(func.branch_quota, Sema.default_branch_quota),
|
||||
@@ -5499,7 +5498,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||
// This could be a generic function instantiation, however, in which case we need to
|
||||
// map the comptime parameters to constant values and only emit arg AIR instructions
|
||||
// for the runtime ones.
|
||||
const runtime_params_len = @intCast(u32, fn_ty_info.param_types.len);
|
||||
const runtime_params_len = @intCast(u32, mod.typeToFunc(fn_ty).?.param_types.len);
|
||||
try inner_block.instructions.ensureTotalCapacityPrecise(gpa, runtime_params_len);
|
||||
try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
|
||||
try sema.inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
|
||||
@@ -5525,7 +5524,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||
sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
|
||||
total_param_index += 1;
|
||||
continue;
|
||||
} else fn_ty_info.param_types[runtime_param_index].toType();
|
||||
} else mod.typeToFunc(fn_ty).?.param_types[runtime_param_index].toType();
|
||||
|
||||
const opt_opv = sema.typeHasOnePossibleValue(param_ty) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => unreachable,
|
||||
@@ -5623,7 +5622,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE
|
||||
// Crucially, this happens *after* we set the function state to success above,
|
||||
// so that dependencies on the function body will now be satisfied rather than
|
||||
// result in circular dependency errors.
|
||||
sema.resolveFnTypes(mod.typeToFunc(fn_ty).?) catch |err| switch (err) {
|
||||
sema.resolveFnTypes(fn_ty) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => unreachable,
|
||||
error.GenericPoison => unreachable,
|
||||
error.ComptimeReturn => unreachable,
|
||||
@@ -6378,9 +6377,9 @@ pub fn populateTestFunctions(
|
||||
|
||||
for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| {
|
||||
const test_decl = mod.declPtr(test_decl_index);
|
||||
// Protects test_decl_name from being invalidated during call to intern() below.
|
||||
try ip.string_bytes.ensureUnusedCapacity(gpa, ip.stringToSlice(test_decl.name).len + 10);
|
||||
const test_decl_name = ip.stringToSlice(test_decl.name);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const test_decl_name = try gpa.dupe(u8, ip.stringToSlice(test_decl.name));
|
||||
defer gpa.free(test_decl_name);
|
||||
const test_name_decl_index = n: {
|
||||
const test_name_decl_ty = try mod.arrayType(.{
|
||||
.len = test_decl_name.len,
|
||||
|
||||
61
src/Sema.zig
61
src/Sema.zig
@@ -5227,6 +5227,8 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
|
||||
fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref {
|
||||
const mod = sema.mod;
|
||||
const gpa = sema.gpa;
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const duped_bytes = try sema.arena.dupe(u8, bytes);
|
||||
const ty = try mod.arrayType(.{
|
||||
.len = bytes.len,
|
||||
.child = .u8_type,
|
||||
@@ -5234,7 +5236,7 @@ fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Ins
|
||||
});
|
||||
const val = try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .bytes = bytes },
|
||||
.storage = .{ .bytes = duped_bytes },
|
||||
} });
|
||||
const gop = try mod.memoized_decls.getOrPut(gpa, val);
|
||||
if (!gop.found_existing) {
|
||||
@@ -11478,7 +11480,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
operand_ty.fmt(mod),
|
||||
});
|
||||
}
|
||||
for (operand_ty.errorSetNames(mod)) |error_name_ip| {
|
||||
for (0..operand_ty.errorSetNames(mod).len) |i| {
|
||||
const error_name_ip = operand_ty.errorSetNames(mod)[i];
|
||||
const error_name = mod.intern_pool.stringToSlice(error_name_ip);
|
||||
if (seen_errors.contains(error_name)) continue;
|
||||
cases_len += 1;
|
||||
@@ -15851,7 +15854,8 @@ fn zirBuiltinSrc(
|
||||
const func_name_val = blk: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
const name = mod.intern_pool.stringToSlice(fn_owner_decl.name);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, mod.intern_pool.stringToSlice(fn_owner_decl.name));
|
||||
const new_decl_ty = try mod.arrayType(.{
|
||||
.len = name.len,
|
||||
.child = .u8_type,
|
||||
@@ -16287,7 +16291,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
const error_field_vals = if (ty.isAnyError(mod)) null else blk: {
|
||||
const vals = try sema.arena.alloc(InternPool.Index, ty.errorSetNames(mod).len);
|
||||
for (vals, 0..) |*field_val, i| {
|
||||
const name = ip.stringToSlice(ty.errorSetNames(mod)[i]);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(ty.errorSetNames(mod)[i]));
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
@@ -16417,8 +16422,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
|
||||
const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_type.names.len);
|
||||
for (enum_field_vals, 0..) |*field_val, i| {
|
||||
const name_ip = ip.indexToKey(ty.toIntern()).enum_type.names[i];
|
||||
const name = ip.stringToSlice(name_ip);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(ty.toIntern()).enum_type.names[i]));
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
@@ -16556,7 +16561,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
|
||||
for (union_field_vals, 0..) |*field_val, i| {
|
||||
const field = union_fields.values()[i];
|
||||
const name = ip.stringToSlice(union_fields.keys()[i]);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(union_fields.keys()[i]));
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
@@ -16714,9 +16720,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const bytes = if (tuple.names.len != 0)
|
||||
// https://github.com/ziglang/zig/issues/15709
|
||||
@as([]const u8, ip.stringToSlice(tuple.names[i]))
|
||||
try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(struct_ty.toIntern()).anon_struct_type.names[i]))
|
||||
else
|
||||
try std.fmt.allocPrint(sema.arena, "{d}", .{i});
|
||||
const new_decl_ty = try mod.arrayType(.{
|
||||
@@ -16771,7 +16778,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
|
||||
struct_obj.fields.keys(),
|
||||
struct_obj.fields.values(),
|
||||
) |*field_val, name_nts, field| {
|
||||
const name = ip.stringToSlice(name_nts);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts));
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
@@ -17020,9 +17028,8 @@ fn typeInfoNamespaceDecls(
|
||||
const name_val = v: {
|
||||
var anon_decl = try block.startAnonDecl();
|
||||
defer anon_decl.deinit();
|
||||
// Protects the decl name slice from being invalidated at the call to intern().
|
||||
try ip.string_bytes.ensureUnusedCapacity(sema.gpa, ip.stringToSlice(decl.name).len + 1);
|
||||
const name = ip.stringToSlice(decl.name);
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const name = try sema.arena.dupe(u8, ip.stringToSlice(decl.name));
|
||||
const new_decl_ty = try mod.arrayType(.{
|
||||
.len = name.len,
|
||||
.child = .u8_type,
|
||||
@@ -19060,6 +19067,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
|
||||
};
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
};
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const field_name = enum_ty.enumFieldName(field_index, mod);
|
||||
return sema.addStrLit(block, ip.stringToSlice(field_name));
|
||||
}
|
||||
@@ -19601,7 +19609,6 @@ fn zirReify(
|
||||
// Tag type
|
||||
const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
|
||||
var explicit_tags_seen: []bool = &.{};
|
||||
var explicit_enum_info: ?InternPool.Key.EnumType = null;
|
||||
var enum_field_names: []InternPool.NullTerminatedString = &.{};
|
||||
if (tag_type_val.optionalValue(mod)) |payload_val| {
|
||||
union_obj.tag_ty = payload_val.toType();
|
||||
@@ -19611,7 +19618,6 @@ fn zirReify(
|
||||
else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
|
||||
};
|
||||
|
||||
explicit_enum_info = enum_type;
|
||||
explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
|
||||
@memset(explicit_tags_seen, false);
|
||||
} else {
|
||||
@@ -19640,7 +19646,8 @@ fn zirReify(
|
||||
enum_field_names[i] = field_name;
|
||||
}
|
||||
|
||||
if (explicit_enum_info) |tag_info| {
|
||||
if (explicit_tags_seen.len > 0) {
|
||||
const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
|
||||
const enum_index = tag_info.nameIndex(ip, field_name) orelse {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ ip.stringToSlice(field_name), union_obj.tag_ty.fmt(mod) });
|
||||
@@ -19705,7 +19712,8 @@ fn zirReify(
|
||||
}
|
||||
}
|
||||
|
||||
if (explicit_enum_info) |tag_info| {
|
||||
if (explicit_tags_seen.len > 0) {
|
||||
const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
|
||||
if (tag_info.names.len > fields_len) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
|
||||
@@ -31625,17 +31633,17 @@ fn resolvePeerTypes(
|
||||
return chosen_ty;
|
||||
}
|
||||
|
||||
pub fn resolveFnTypes(sema: *Sema, fn_info: InternPool.Key.FuncType) CompileError!void {
|
||||
pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void {
|
||||
const mod = sema.mod;
|
||||
try sema.resolveTypeFully(fn_info.return_type.toType());
|
||||
try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.return_type.toType());
|
||||
|
||||
if (mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.toType().isError(mod)) {
|
||||
if (mod.comp.bin_file.options.error_return_tracing and mod.typeToFunc(fn_ty).?.return_type.toType().isError(mod)) {
|
||||
// Ensure the type exists so that backends can assume that.
|
||||
_ = try sema.getBuiltinType("StackTrace");
|
||||
}
|
||||
|
||||
for (fn_info.param_types) |param_ty| {
|
||||
try sema.resolveTypeFully(param_ty.toType());
|
||||
for (0..mod.typeToFunc(fn_ty).?.param_types.len) |i| {
|
||||
try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.param_types[i].toType());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33077,7 +33085,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
var enum_field_names: []InternPool.NullTerminatedString = &.{};
|
||||
var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
|
||||
var explicit_tags_seen: []bool = &.{};
|
||||
var explicit_enum_info: ?InternPool.Key.EnumType = null;
|
||||
if (tag_type_ref != .none) {
|
||||
const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
|
||||
const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
|
||||
@@ -33114,7 +33121,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
};
|
||||
// The fields of the union must match the enum exactly.
|
||||
// A flag per field is used to check for missing and extraneous fields.
|
||||
explicit_enum_info = enum_type;
|
||||
explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
|
||||
@memset(explicit_tags_seen, false);
|
||||
}
|
||||
@@ -33256,7 +33262,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
return sema.failWithOwnedErrorMsg(msg);
|
||||
}
|
||||
|
||||
if (explicit_enum_info) |tag_info| {
|
||||
if (explicit_tags_seen.len > 0) {
|
||||
const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
|
||||
const enum_index = tag_info.nameIndex(ip, field_name) orelse {
|
||||
const msg = msg: {
|
||||
const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
|
||||
@@ -33346,7 +33353,8 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
|
||||
}
|
||||
}
|
||||
|
||||
if (explicit_enum_info) |tag_info| {
|
||||
if (explicit_tags_seen.len > 0) {
|
||||
const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
|
||||
if (tag_info.names.len > fields_len) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
|
||||
@@ -33706,9 +33714,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
}
|
||||
// In this case the struct has all comptime-known fields and
|
||||
// therefore has one possible value.
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = tuple.values },
|
||||
.storage = .{ .elems = try sema.arena.dupe(InternPool.Index, tuple.values) },
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
|
||||
@@ -2026,13 +2026,9 @@ fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void {
|
||||
try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty });
|
||||
|
||||
var data_off: i32 = 0;
|
||||
for (
|
||||
exitlude_jump_relocs,
|
||||
enum_ty.enumFields(mod),
|
||||
0..,
|
||||
) |*exitlude_jump_reloc, tag_name_ip, index_usize| {
|
||||
for (exitlude_jump_relocs, 0..) |*exitlude_jump_reloc, index_usize| {
|
||||
const index = @intCast(u32, index_usize);
|
||||
const tag_name = mod.intern_pool.stringToSlice(tag_name_ip);
|
||||
const tag_name = mod.intern_pool.stringToSlice(enum_ty.enumFields(mod)[index_usize]);
|
||||
const tag_val = try mod.enumValueFieldIndex(enum_ty, index);
|
||||
const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val });
|
||||
try self.genBinOpMir(.{ ._, .cmp }, enum_ty, enum_mcv, tag_mcv);
|
||||
|
||||
@@ -517,7 +517,7 @@ pub fn generateSymbol(
|
||||
const field_ty = field.ty;
|
||||
if (!field_ty.hasRuntimeBits(mod)) continue;
|
||||
|
||||
const field_val = switch (aggregate.storage) {
|
||||
const field_val = switch (mod.intern_pool.indexToKey(typed_value.val.toIntern()).aggregate.storage) {
|
||||
.bytes => |bytes| try mod.intern_pool.get(mod.gpa, .{ .int = .{
|
||||
.ty = field_ty.toIntern(),
|
||||
.storage = .{ .u64 = bytes[index] },
|
||||
|
||||
@@ -2576,9 +2576,12 @@ pub const Type = struct {
|
||||
}
|
||||
// In this case the struct has all comptime-known fields and
|
||||
// therefore has one possible value.
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
const duped_values = try mod.gpa.dupe(InternPool.Index, tuple.values);
|
||||
defer mod.gpa.free(duped_values);
|
||||
return (try mod.intern(.{ .aggregate = .{
|
||||
.ty = ty.toIntern(),
|
||||
.storage = .{ .elems = tuple.values },
|
||||
.storage = .{ .elems = duped_values },
|
||||
} })).toValue();
|
||||
},
|
||||
|
||||
|
||||
@@ -1904,6 +1904,7 @@ pub const Value = struct {
|
||||
start: usize,
|
||||
end: usize,
|
||||
) error{OutOfMemory}!Value {
|
||||
// TODO: write something like getCoercedInts to avoid needing to dupe
|
||||
return switch (val.ip_index) {
|
||||
.none => switch (val.tag()) {
|
||||
.slice => val.castTag(.slice).?.data.ptr.sliceArray(mod, arena, start, end),
|
||||
@@ -1937,8 +1938,8 @@ pub const Value = struct {
|
||||
else => unreachable,
|
||||
}.toIntern(),
|
||||
.storage = switch (aggregate.storage) {
|
||||
.bytes => |bytes| .{ .bytes = bytes[start..end] },
|
||||
.elems => |elems| .{ .elems = elems[start..end] },
|
||||
.bytes => .{ .bytes = try arena.dupe(u8, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.bytes[start..end]) },
|
||||
.elems => .{ .elems = try arena.dupe(InternPool.Index, mod.intern_pool.indexToKey(val.toIntern()).aggregate.storage.elems[start..end]) },
|
||||
.repeated_elem => |elem| .{ .repeated_elem = elem },
|
||||
},
|
||||
} })).toValue(),
|
||||
|
||||
Reference in New Issue
Block a user