InternPool: fix various pointer issues
This commit is contained in:
committed by
Andrew Kelley
parent
3269256965
commit
4f70863a55
@@ -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,
|
||||
|
||||
@@ -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(.{
|
||||
|
||||
29
src/Sema.zig
29
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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user