From 4f70863a55e699c13731325f8c52870119479c02 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 29 May 2023 07:30:30 -0400 Subject: [PATCH] InternPool: fix various pointer issues --- src/InternPool.zig | 159 ++++++++++++++++++++++++--------------------- src/Module.zig | 4 ++ src/Sema.zig | 29 +++++---- src/value.zig | 4 +- 4 files changed, 109 insertions(+), 87 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index 90e0e2bd35b4242386215c3aafe68ebcab47c12a..7bfecf46b6c739f62b7f79a2171e1c9076c36d37 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1374,12 +1374,12 @@ pub const Index = enum(u32) { undef: DataIsIndex, runtime_value: DataIsIndex, simple_value: struct { data: SimpleValue }, - ptr_mut_decl: struct { data: *PtrMutDecl }, ptr_decl: struct { data: *PtrDecl }, - ptr_int: struct { data: *PtrAddr }, - ptr_eu_payload: DataIsIndex, - ptr_opt_payload: DataIsIndex, + ptr_mut_decl: struct { data: *PtrMutDecl }, ptr_comptime_field: struct { data: *PtrComptimeField }, + ptr_int: struct { data: *PtrBase }, + ptr_eu_payload: struct { data: *PtrBase }, + ptr_opt_payload: struct { data: *PtrBase }, ptr_elem: struct { data: *PtrBaseIndex }, ptr_field: struct { data: *PtrBaseIndex }, ptr_slice: struct { data: *PtrSlice }, @@ -1774,29 +1774,25 @@ pub const Tag = enum(u8) { /// A value that can be represented with only an enum tag. /// data is SimpleValue enum value. simple_value, - /// A pointer to a decl that can be mutated at comptime. - /// data is extra index of PtrMutDecl, which contains the type and address. - ptr_mut_decl, /// A pointer to a decl. - /// data is extra index of PtrDecl, which contains the type and address. + /// data is extra index of `PtrDecl`, which contains the type and address. ptr_decl, + /// A pointer to a decl that can be mutated at comptime. + /// data is extra index of `PtrMutDecl`, which contains the type and address. + ptr_mut_decl, + /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value. + ptr_comptime_field, /// A pointer with an integer value. - /// data is extra index of PtrAddr, which contains the type and address. + /// data is extra index of `PtrBase`, which contains the type and address. /// Only pointer types are allowed to have this encoding. Optional types must use /// `opt_payload` or `opt_null`. ptr_int, /// A pointer to the payload of an error union. - /// data is Index of a pointer value to the error union. - /// In order to use this encoding, one must ensure that the `InternPool` - /// already contains the payload pointer type corresponding to this payload. + /// data is extra index of `PtrBase`, which contains the type and base pointer. ptr_eu_payload, /// A pointer to the payload of an optional. - /// data is Index of a pointer value to the optional. - /// In order to use this encoding, one must ensure that the `InternPool` - /// already contains the payload pointer type corresponding to this payload. + /// data is extra index of `PtrBase`, which contains the type and base pointer. ptr_opt_payload, - /// data is extra index of PtrComptimeField, which contains the pointer type and field value. - ptr_comptime_field, /// A pointer to an array element. /// data is extra index of PtrBaseIndex, which contains the base array and element index. /// In order to use this encoding, one must ensure that the `InternPool` @@ -2224,16 +2220,16 @@ pub const PtrMutDecl = struct { runtime_index: RuntimeIndex, }; -pub const PtrAddr = struct { - ty: Index, - addr: Index, -}; - pub const PtrComptimeField = struct { ty: Index, field_val: Index, }; +pub const PtrBase = struct { + ty: Index, + base: Index, +}; + pub const PtrBaseIndex = struct { ty: Index, base: Index, @@ -2598,31 +2594,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { } }, } }; }, - .ptr_int => { - const info = ip.extraData(PtrAddr, data); - return .{ .ptr = .{ - .ty = info.ty, - .addr = .{ .int = info.addr }, - } }; - }, - .ptr_eu_payload => { - const ptr_eu_index = @intToEnum(Index, data); - var ptr_type = ip.indexToKey(ip.typeOf(ptr_eu_index)).ptr_type; - ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).error_union_type.payload_type; - return .{ .ptr = .{ - .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), - .addr = .{ .eu_payload = ptr_eu_index }, - } }; - }, - .ptr_opt_payload => { - const ptr_opt_index = @intToEnum(Index, data); - var ptr_type = ip.indexToKey(ip.typeOf(ptr_opt_index)).ptr_type; - ptr_type.elem_type = ip.indexToKey(ptr_type.elem_type).opt_type; - return .{ .ptr = .{ - .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }), - .addr = .{ .opt_payload = ptr_opt_index }, - } }; - }, .ptr_comptime_field => { const info = ip.extraData(PtrComptimeField, data); return .{ .ptr = .{ @@ -2630,6 +2601,18 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .addr = .{ .comptime_field = info.field_val }, } }; }, + .ptr_int, .ptr_eu_payload, .ptr_opt_payload => { + const info = ip.extraData(PtrBase, data); + return .{ .ptr = .{ + .ty = info.ty, + .addr = switch (item.tag) { + .ptr_int => .{ .int = info.base }, + .ptr_eu_payload => .{ .eu_payload = info.base }, + .ptr_opt_payload => .{ .opt_payload = info.base }, + else => unreachable, + }, + } }; + }, .ptr_elem => { const info = ip.extraData(PtrBaseIndex, data); return .{ .ptr = .{ @@ -3248,27 +3231,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .runtime_index = mut_decl.runtime_index, }), }), - .int => |int| { - assert(ip.typeOf(int) == .usize_type); - ip.items.appendAssumeCapacity(.{ - .tag = .ptr_int, - .data = try ip.addExtra(gpa, PtrAddr{ - .ty = ptr.ty, - .addr = int, - }), - }); - }, - .eu_payload, .opt_payload => |data| { - assert(data != .none); - ip.items.appendAssumeCapacity(.{ - .tag = switch (ptr.addr) { - .eu_payload => .ptr_eu_payload, - .opt_payload => .ptr_opt_payload, - else => unreachable, - }, - .data = @enumToInt(data), - }); - }, .comptime_field => |field_val| { assert(field_val != .none); ip.items.appendAssumeCapacity(.{ @@ -3279,8 +3241,57 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { }), }); }, + .int, .eu_payload, .opt_payload => |base| { + switch (ptr.addr) { + .int => assert(ip.typeOf(base) == .usize_type), + .eu_payload => assert(ip.indexToKey( + ip.indexToKey(ip.typeOf(base)).ptr_type.elem_type, + ) == .error_union_type), + .opt_payload => assert(ip.indexToKey( + ip.indexToKey(ip.typeOf(base)).ptr_type.elem_type, + ) == .opt_type), + else => unreachable, + } + ip.items.appendAssumeCapacity(.{ + .tag = switch (ptr.addr) { + .int => .ptr_int, + .eu_payload => .ptr_eu_payload, + .opt_payload => .ptr_opt_payload, + else => unreachable, + }, + .data = try ip.addExtra(gpa, PtrBase{ + .ty = ptr.ty, + .base = base, + }), + }); + }, .elem, .field => |base_index| { - assert(base_index.base != .none); + const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type; + switch (base_ptr_type.size) { + .One => switch (ip.indexToKey(base_ptr_type.elem_type)) { + .array_type, .vector_type => assert(ptr.addr == .elem), + .anon_struct_type => |anon_struct_type| { + assert(ptr.addr == .field); + assert(base_index.index < anon_struct_type.types.len); + }, + .struct_type => |struct_type| { + assert(ptr.addr == .field); + assert(base_index.index < ip.structPtrUnwrapConst(struct_type.index).?.fields.count()); + }, + .union_type => |union_type| { + assert(ptr.addr == .field); + assert(base_index.index < ip.unionPtrConst(union_type.index).fields.count()); + }, + .ptr_type => |slice_type| { + assert(ptr.addr == .field); + assert(slice_type.size == .Slice); + assert(base_index.index < 2); + }, + else => unreachable, + }, + .Many => assert(ptr.addr == .elem), + .Slice, .C => unreachable, + } _ = ip.map.pop(); const index_index = try ip.get(gpa, .{ .int = .{ .ty = .usize_type, @@ -4750,10 +4761,10 @@ fn dumpFallible(ip: InternPool, arena: Allocator) anyerror!void { .simple_value => 0, .ptr_decl => @sizeOf(PtrDecl), .ptr_mut_decl => @sizeOf(PtrMutDecl), - .ptr_int => @sizeOf(PtrAddr), - .ptr_eu_payload => 0, - .ptr_opt_payload => 0, .ptr_comptime_field => @sizeOf(PtrComptimeField), + .ptr_int => @sizeOf(PtrBase), + .ptr_eu_payload => @sizeOf(PtrBase), + .ptr_opt_payload => @sizeOf(PtrBase), .ptr_elem => @sizeOf(PtrBaseIndex), .ptr_field => @sizeOf(PtrBaseIndex), .ptr_slice => @sizeOf(PtrSlice), @@ -5281,12 +5292,12 @@ pub fn zigTypeTagOrPoison(ip: InternPool, index: Index) error{GenericPoison}!std .undef, .runtime_value, .simple_value, - .ptr_mut_decl, .ptr_decl, + .ptr_mut_decl, + .ptr_comptime_field, .ptr_int, .ptr_eu_payload, .ptr_opt_payload, - .ptr_comptime_field, .ptr_elem, .ptr_field, .ptr_slice, diff --git a/src/Module.zig b/src/Module.zig index 36037bb49c112fcd565a17bf27cb26863af57a31..49cf9387a944cb42522a22ea6e2717dc96a3c2c3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -6716,6 +6716,10 @@ pub fn singleConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { return ptrType(mod, .{ .elem_type = child_type.toIntern(), .is_const = true }); } +pub fn manyConstPtrType(mod: *Module, child_type: Type) Allocator.Error!Type { + return ptrType(mod, .{ .elem_type = child_type.toIntern(), .size = .Many, .is_const = true }); +} + pub fn adjustPtrTypeChild(mod: *Module, ptr_ty: Type, new_child: Type) Allocator.Error!Type { const info = Type.ptrInfoIp(mod.intern_pool, ptr_ty.toIntern()); return mod.ptrType(.{ diff --git a/src/Sema.zig b/src/Sema.zig index 87d66aad1f70d9e670d37799b96e0353fc08f483..bd3cfad50d29e086007a04b946ce94f272984b63 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25412,11 +25412,13 @@ fn elemVal( const indexable_val = maybe_indexable_val orelse break :rs indexable_src; const index_val = maybe_index_val orelse break :rs elem_index_src; const index = @intCast(usize, index_val.toUnsignedInt(mod)); - const elem_ptr_ty = try sema.elemPtrType(indexable_ty, index); - const elem_ptr_val = try indexable_val.elemPtr(elem_ptr_ty, index, mod); + const elem_ty = indexable_ty.elemType2(mod); + const many_ptr_ty = try mod.manyConstPtrType(elem_ty); + const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty); + const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); + const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod); if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| { - const result_ty = indexable_ty.elemType2(mod); - return sema.addConstant(result_ty, try mod.getCoerced(elem_val, result_ty)); + return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty)); } break :rs indexable_src; }; @@ -29906,7 +29908,7 @@ fn analyzeSlice( const ptr_ptr_ty = sema.typeOf(ptr_ptr); const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) { .Pointer => ptr_ptr_ty.childType(mod), - else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}), + else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}), }; var array_ty = ptr_ptr_child_ty; @@ -30111,7 +30113,10 @@ fn analyzeSlice( const end_int = end_val.getUnsignedInt(mod).?; const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int); - const elem_ptr = try ptr_val.elemPtr(try sema.elemPtrType(new_ptr_ty, sentinel_index), sentinel_index, sema.mod); + const many_ptr_ty = try mod.manyConstPtrType(elem_ty); + const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty); + const elem_ptr_ty = try mod.singleConstPtrType(elem_ty); + const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod); const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty); const actual_sentinel = switch (res) { .runtime_load => break :sentinel_check, @@ -30120,23 +30125,23 @@ fn analyzeSlice( block, src, "comptime dereference requires '{}' to have a well-defined layout, but it does not.", - .{ty.fmt(sema.mod)}, + .{ty.fmt(mod)}, ), .out_of_bounds => |ty| return sema.fail( block, end_src, "slice end index {d} exceeds bounds of containing decl of type '{}'", - .{ end_int, ty.fmt(sema.mod) }, + .{ end_int, ty.fmt(mod) }, ), }; - if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) { + if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) { const msg = msg: { const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{}); errdefer msg.destroy(sema.gpa); try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{ - expected_sentinel.fmtValue(elem_ty, sema.mod), - actual_sentinel.fmtValue(elem_ty, sema.mod), + expected_sentinel.fmtValue(elem_ty, mod), + actual_sentinel.fmtValue(elem_ty, mod), }); break :msg msg; @@ -30310,7 +30315,7 @@ fn cmpNumeric( const lhs_ty_tag = lhs_ty.zigTypeTag(mod); const rhs_ty_tag = rhs_ty.zigTypeTag(mod); - const target = sema.mod.getTarget(); + const target = mod.getTarget(); // One exception to heterogeneous comparison: comptime_float needs to // coerce to fixed-width float. diff --git a/src/value.zig b/src/value.zig index 0da562693756008d30642347a89d56324c886b42..a1f0f68187778953eb0e7ac694170271f37d682a 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1857,7 +1857,8 @@ pub const Value = struct { .decl => |decl| mod.declPtr(decl).val.elemValue(mod, index), .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) .toValue().elemValue(mod, index), - .int, .eu_payload, .opt_payload => unreachable, + .int, .eu_payload => unreachable, + .opt_payload => |base| base.toValue().elemValue(mod, index), .comptime_field => |field_val| field_val.toValue().elemValue(mod, index), .elem => |elem| elem.base.toValue().elemValue(mod, index + elem.index), .field => |field| if (field.base.toValue().pointerDecl(mod)) |decl_index| { @@ -1866,6 +1867,7 @@ pub const Value = struct { return field_val.elemValue(mod, index); } else unreachable, }, + .opt => |opt| opt.val.toValue().elemValue(mod, index), .aggregate => |aggregate| { const len = mod.intern_pool.aggregateTypeLen(aggregate.ty); if (index < len) return switch (aggregate.storage) { -- 2.54.0