diff options
| author | Jacob Young <jacobly0@users.noreply.github.com> | 2023-06-02 18:49:40 -0400 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2023-06-10 20:47:59 -0700 |
| commit | e23b0a01e6357252eb2c08a83eff9169ce49042c (patch) | |
| tree | 86742fd9ad29116eddc61c1e093ae8155a435fb4 /src | |
| parent | 6a15fc87ad62ec0509017c960f6983ce1493c31d (diff) | |
| download | zig-e23b0a01e6357252eb2c08a83eff9169ce49042c.tar.gz zig-e23b0a01e6357252eb2c08a83eff9169ce49042c.zip | |
InternPool: fix yet more key lifetime issues
Diffstat (limited to 'src')
| -rw-r--r-- | src/Module.zig | 15 | ||||
| -rw-r--r-- | src/Sema.zig | 61 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 8 | ||||
| -rw-r--r-- | src/codegen.zig | 2 | ||||
| -rw-r--r-- | src/type.zig | 5 | ||||
| -rw-r--r-- | src/value.zig | 5 |
6 files changed, 52 insertions, 44 deletions
diff --git a/src/Module.zig b/src/Module.zig index 9d58029cb5..c1d6b8157a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -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, diff --git a/src/Sema.zig b/src/Sema.zig index ca4e761cdc..4d9fc201a1 100644 --- a/src/Sema.zig +++ b/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(); }, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 2675d5350a..a1b57516ee 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -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); diff --git a/src/codegen.zig b/src/codegen.zig index 77359d78da..b39c3c5ec0 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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] }, diff --git a/src/type.zig b/src/type.zig index 43aaf3c786..d9ae710b2d 100644 --- a/src/type.zig +++ b/src/type.zig @@ -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(); }, diff --git a/src/value.zig b/src/value.zig index 3958615214..8ab98bc994 100644 --- a/src/value.zig +++ b/src/value.zig @@ -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(), |
