Sema: rework @fieldParentPtr to accept a pointer type

There is no way to know the expected parent pointer attributes (most
notably alignment) from the type of the field pointer, so provide them
in the first argument.
This commit is contained in:
Jacob Young 2024-03-18 15:00:27 +01:00
parent 5a41704f7e
commit 9b2345e182
14 changed files with 2108 additions and 234 deletions

View File

@ -5163,28 +5163,36 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.ptr => |ptr| {
const ptr_type = ip.indexToKey(ptr.ty).ptr_type;
assert(ptr_type.flags.size != .Slice);
switch (ptr.addr) {
.decl => |decl| ip.items.appendAssumeCapacity(.{
ip.items.appendAssumeCapacity(switch (ptr.addr) {
.decl => |decl| .{
.tag = .ptr_decl,
.data = try ip.addExtra(gpa, PtrDecl{
.ty = ptr.ty,
.decl = decl,
}),
}),
.comptime_alloc => |alloc_index| ip.items.appendAssumeCapacity(.{
},
.comptime_alloc => |alloc_index| .{
.tag = .ptr_comptime_alloc,
.data = try ip.addExtra(gpa, PtrComptimeAlloc{
.ty = ptr.ty,
.index = alloc_index,
}),
}),
.anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{
},
.anon_decl => |anon_decl| if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) item: {
if (ptr.ty != anon_decl.orig_ty) {
_ = ip.map.pop();
var new_key = key;
new_key.ptr.addr.anon_decl.orig_ty = ptr.ty;
const new_gop = try ip.map.getOrPutAdapted(gpa, new_key, adapter);
if (new_gop.found_existing) return @enumFromInt(new_gop.index);
}
break :item .{
.tag = .ptr_anon_decl,
.data = try ip.addExtra(gpa, PtrAnonDecl{
.ty = ptr.ty,
.val = anon_decl.val,
}),
};
} else .{
.tag = .ptr_anon_decl_aligned,
.data = try ip.addExtra(gpa, PtrAnonDeclAligned{
@ -5193,18 +5201,17 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.orig_ty = anon_decl.orig_ty,
}),
},
),
.comptime_field => |field_val| {
.comptime_field => |field_val| item: {
assert(field_val != .none);
ip.items.appendAssumeCapacity(.{
break :item .{
.tag = .ptr_comptime_field,
.data = try ip.addExtra(gpa, PtrComptimeField{
.ty = ptr.ty,
.field_val = field_val,
}),
});
};
},
.int, .eu_payload, .opt_payload => |base| {
.int, .eu_payload, .opt_payload => |base| item: {
switch (ptr.addr) {
.int => assert(ip.typeOf(base) == .usize_type),
.eu_payload => assert(ip.indexToKey(
@ -5215,7 +5222,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
) == .opt_type),
else => unreachable,
}
ip.items.appendAssumeCapacity(.{
break :item .{
.tag = switch (ptr.addr) {
.int => .ptr_int,
.eu_payload => .ptr_eu_payload,
@ -5226,9 +5233,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.ty = ptr.ty,
.base = base,
}),
});
};
},
.elem, .field => |base_index| {
.elem, .field => |base_index| item: {
const base_ptr_type = ip.indexToKey(ip.typeOf(base_index.base)).ptr_type;
switch (ptr.addr) {
.elem => assert(base_ptr_type.flags.size == .Many),
@ -5265,7 +5272,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
} });
assert(!(try ip.map.getOrPutAdapted(gpa, key, adapter)).found_existing);
try ip.items.ensureUnusedCapacity(gpa, 1);
ip.items.appendAssumeCapacity(.{
break :item .{
.tag = switch (ptr.addr) {
.elem => .ptr_elem,
.field => .ptr_field,
@ -5276,9 +5283,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.base = base_index.base,
.index = index_index,
}),
});
};
},
}
});
},
.opt => |opt| {

View File

@ -17699,19 +17699,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = new_decl_ty.toIntern(),
.storage = .{ .elems = param_vals },
} });
const ptr_ty = (try sema.ptrType(.{
const slice_ty = (try sema.ptrType(.{
.child = param_info_ty.toIntern(),
.flags = .{
.size = .Slice,
.is_const = true,
},
})).toIntern();
const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern();
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.ty = slice_ty,
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.ty = manyptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.orig_ty = manyptr_ty,
.val = new_decl_val,
} },
} }),
@ -18031,12 +18032,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = array_errors_ty.toIntern(),
.storage = .{ .elems = vals },
} });
const manyptr_errors_ty = slice_errors_ty.slicePtrFieldType(mod).toIntern();
break :v try mod.intern(.{ .slice = .{
.ty = slice_errors_ty.toIntern(),
.ptr = try mod.intern(.{ .ptr = .{
.ty = slice_errors_ty.slicePtrFieldType(mod).toIntern(),
.ty = manyptr_errors_ty,
.addr = .{ .anon_decl = .{
.orig_ty = slice_errors_ty.toIntern(),
.orig_ty = manyptr_errors_ty,
.val = new_decl_val,
} },
} }),
@ -18155,20 +18157,21 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = fields_array_ty.toIntern(),
.storage = .{ .elems = enum_field_vals },
} });
const ptr_ty = (try sema.ptrType(.{
const slice_ty = (try sema.ptrType(.{
.child = enum_field_ty.toIntern(),
.flags = .{
.size = .Slice,
.is_const = true,
},
})).toIntern();
const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern();
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.ty = slice_ty,
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.ty = manyptr_ty,
.addr = .{ .anon_decl = .{
.val = new_decl_val,
.orig_ty = ptr_ty,
.orig_ty = manyptr_ty,
} },
} }),
.len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
@ -18296,19 +18299,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = array_fields_ty.toIntern(),
.storage = .{ .elems = union_field_vals },
} });
const ptr_ty = (try sema.ptrType(.{
const slice_ty = (try sema.ptrType(.{
.child = union_field_ty.toIntern(),
.flags = .{
.size = .Slice,
.is_const = true,
},
})).toIntern();
const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern();
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.ty = slice_ty,
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.ty = manyptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.orig_ty = manyptr_ty,
.val = new_decl_val,
} },
} }),
@ -18523,19 +18527,20 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.ty = array_fields_ty.toIntern(),
.storage = .{ .elems = struct_field_vals },
} });
const ptr_ty = (try sema.ptrType(.{
const slice_ty = (try sema.ptrType(.{
.child = struct_field_ty.toIntern(),
.flags = .{
.size = .Slice,
.is_const = true,
},
})).toIntern();
const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern();
break :v try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.ty = slice_ty,
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.ty = manyptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.orig_ty = manyptr_ty,
.val = new_decl_val,
} },
} }),
@ -18661,19 +18666,20 @@ fn typeInfoDecls(
.ty = array_decl_ty.toIntern(),
.storage = .{ .elems = decl_vals.items },
} });
const ptr_ty = (try sema.ptrType(.{
const slice_ty = (try sema.ptrType(.{
.child = declaration_ty.toIntern(),
.flags = .{
.size = .Slice,
.is_const = true,
},
})).toIntern();
const manyptr_ty = Type.fromInterned(slice_ty).slicePtrFieldType(mod).toIntern();
return try mod.intern(.{ .slice = .{
.ty = ptr_ty,
.ty = slice_ty,
.ptr = try mod.intern(.{ .ptr = .{
.ty = Type.fromInterned(ptr_ty).slicePtrFieldType(mod).toIntern(),
.ty = manyptr_ty,
.addr = .{ .anon_decl = .{
.orig_ty = ptr_ty,
.orig_ty = manyptr_ty,
.val = new_decl_val,
} },
} }),
@ -19803,8 +19809,18 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
break :blk @intCast(host_size);
} else 0;
if (host_size != 0 and bit_offset >= host_size * 8) {
return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
if (host_size != 0) {
if (bit_offset >= host_size * 8) {
return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} starts {} bits after the end of a {} byte host integer", .{
elem_ty.fmt(mod), bit_offset, bit_offset - host_size * 8, host_size,
});
}
const elem_bit_size = try elem_ty.bitSizeAdvanced(mod, sema);
if (elem_bit_size > host_size * 8 - bit_offset) {
return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{
elem_ty.fmt(mod), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,
});
}
}
if (elem_ty.zigTypeTag(mod) == .Fn) {
@ -24844,106 +24860,147 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data;
const src = inst_data.src();
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type);
const field_name = try sema.resolveConstStringIntern(block, name_src, extra.field_name, .{
.needed_comptime_reason = "field name must be comptime-known",
});
const field_ptr = try sema.resolveInst(extra.field_ptr);
const field_ptr_ty = sema.typeOf(field_ptr);
const mod = sema.mod;
const ip = &mod.intern_pool;
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
const extra = sema.code.extraData(Zir.Inst.FieldParentPtr, inst_data.payload_index).data;
const inst_src = inst_data.src();
const parent_ptr_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const field_ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const parent_ptr_ty = try sema.resolveType(block, parent_ptr_ty_src, extra.parent_type);
try sema.checkPtrType(block, parent_ptr_ty_src, parent_ptr_ty, false);
if (!parent_ptr_ty.isSinglePointer(mod)) {
return sema.fail(block, parent_ptr_ty_src, "expected single pointer type, found '{}'", .{parent_ptr_ty.fmt(sema.mod)});
}
const parent_ty = parent_ptr_ty.childType(mod);
if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) {
return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)});
return sema.fail(block, parent_ptr_ty_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(sema.mod)});
}
try sema.resolveTypeLayout(parent_ty);
const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{
.needed_comptime_reason = "field name must be comptime-known",
});
const field_index = switch (parent_ty.zigTypeTag(mod)) {
.Struct => blk: {
if (parent_ty.isTuple(mod)) {
if (ip.stringEqlSlice(field_name, "len")) {
return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
return sema.fail(block, inst_src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
}
break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src);
break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, field_name_src);
} else {
break :blk try sema.structFieldIndex(block, parent_ty, field_name, name_src);
break :blk try sema.structFieldIndex(block, parent_ty, field_name, field_name_src);
}
},
.Union => try sema.unionFieldIndex(block, parent_ty, field_name, name_src),
.Union => try sema.unionFieldIndex(block, parent_ty, field_name, field_name_src),
else => unreachable,
};
if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) {
return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{});
return sema.fail(block, field_name_src, "cannot get @fieldParentPtr of a comptime field", .{});
}
try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
const field_ptr_ty_info = field_ptr_ty.ptrInfo(mod);
const field_ptr = try sema.resolveInst(extra.field_ptr);
const field_ptr_ty = sema.typeOf(field_ptr);
try sema.checkPtrOperand(block, field_ptr_src, field_ptr_ty);
const field_ptr_info = field_ptr_ty.ptrInfo(mod);
var ptr_ty_data: InternPool.Key.PtrType = .{
.child = parent_ty.structFieldType(field_index, mod).toIntern(),
var actual_parent_ptr_info: InternPool.Key.PtrType = .{
.child = parent_ty.toIntern(),
.flags = .{
.address_space = field_ptr_ty_info.flags.address_space,
.is_const = field_ptr_ty_info.flags.is_const,
.alignment = try parent_ptr_ty.ptrAlignmentAdvanced(mod, sema),
.is_const = field_ptr_info.flags.is_const,
.is_volatile = field_ptr_info.flags.is_volatile,
.is_allowzero = field_ptr_info.flags.is_allowzero,
.address_space = field_ptr_info.flags.address_space,
},
.packed_offset = parent_ptr_ty.ptrInfo(mod).packed_offset,
};
const field_ty = parent_ty.structFieldType(field_index, mod);
var actual_field_ptr_info: InternPool.Key.PtrType = .{
.child = field_ty.toIntern(),
.flags = .{
.alignment = try field_ptr_ty.ptrAlignmentAdvanced(mod, sema),
.is_const = field_ptr_info.flags.is_const,
.is_volatile = field_ptr_info.flags.is_volatile,
.is_allowzero = field_ptr_info.flags.is_allowzero,
.address_space = field_ptr_info.flags.address_space,
},
.packed_offset = field_ptr_info.packed_offset,
};
switch (parent_ty.containerLayout(mod)) {
.auto => {
actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(
if (mod.typeToStruct(parent_ty)) |struct_obj| try sema.structFieldAlignment(
struct_obj.fieldAlign(ip, field_index),
field_ty,
struct_obj.layout,
) else if (mod.typeToUnion(parent_ty)) |union_obj|
try sema.unionFieldAlignment(union_obj, field_index)
else
actual_field_ptr_info.flags.alignment,
);
if (parent_ty.containerLayout(mod) == .@"packed") {
return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
} else {
ptr_ty_data.flags.alignment = blk: {
if (mod.typeToStruct(parent_ty)) |struct_type| {
break :blk struct_type.fieldAlign(ip, field_index);
} else if (mod.typeToUnion(parent_ty)) |union_obj| {
break :blk union_obj.fieldAlign(ip, field_index);
} else {
break :blk .none;
}
};
actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
},
.@"extern" => {
const field_offset = parent_ty.structFieldOffset(field_index, mod);
actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (field_offset > 0)
Alignment.fromLog2Units(@ctz(field_offset))
else
actual_field_ptr_info.flags.alignment);
actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
},
.@"packed" => {
const byte_offset = std.math.divExact(u32, @abs(@as(i32, actual_parent_ptr_info.packed_offset.bit_offset) +
(if (mod.typeToStruct(parent_ty)) |struct_obj| mod.structPackedFieldBitOffset(struct_obj, field_index) else 0) -
actual_field_ptr_info.packed_offset.bit_offset), 8) catch
return sema.fail(block, inst_src, "pointer bit-offset mismatch", .{});
actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(if (byte_offset > 0)
Alignment.fromLog2Units(@ctz(byte_offset))
else
actual_field_ptr_info.flags.alignment);
},
}
const actual_field_ptr_ty = try sema.ptrType(ptr_ty_data);
const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, ptr_src);
ptr_ty_data.child = parent_ty.toIntern();
const result_ptr = try sema.ptrType(ptr_ty_data);
if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info);
const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info);
const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {
const field = switch (ip.indexToKey(field_ptr_val.toIntern())) {
.ptr => |ptr| switch (ptr.addr) {
.field => |field| field,
else => null,
},
else => null,
} orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
} orelse return sema.fail(block, field_ptr_src, "pointer value not based on parent struct", .{});
if (field.index != field_index) {
return sema.fail(block, src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{
return sema.fail(block, inst_src, "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{
field_name.fmt(ip), field_index, field.index, parent_ty.fmt(sema.mod),
});
}
return Air.internedToRef(field.base);
}
try sema.requireRuntimeBlock(block, src, ptr_src);
try sema.queueFullTypeResolution(result_ptr);
return block.addInst(.{
break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src);
} else result: {
try sema.requireRuntimeBlock(block, inst_src, field_ptr_src);
try sema.queueFullTypeResolution(parent_ty);
break :result try block.addInst(.{
.tag = .field_parent_ptr,
.data = .{ .ty_pl = .{
.ty = Air.internedToRef(result_ptr.toIntern()),
.ty = Air.internedToRef(actual_parent_ptr_ty.toIntern()),
.payload = try block.sema.addExtra(Air.FieldParentPtr{
.field_ptr = casted_field_ptr,
.field_index = @intCast(field_index),
}),
} },
});
};
return sema.coerce(block, parent_ptr_ty, result, inst_src);
}
fn zirMinMax(

View File

@ -7920,17 +7920,14 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
const mod = self.bin_file.comp.module.?;
const ptr_field_ty = self.typeOfIndex(inst);
const ptr_container_ty = self.typeOf(operand);
const ptr_container_ty_info = ptr_container_ty.ptrInfo(mod);
const container_ty = ptr_container_ty.childType(mod);
const field_offset: i32 = if (mod.typeToPackedStruct(container_ty)) |struct_obj|
if (ptr_field_ty.ptrInfo(mod).packed_offset.host_size == 0)
@divExact(mod.structPackedFieldBitOffset(struct_obj, index) +
ptr_container_ty_info.packed_offset.bit_offset, 8)
else
0
else
@intCast(container_ty.structFieldOffset(index, mod));
const field_off: i32 = switch (container_ty.containerLayout(mod)) {
.auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, mod)),
.@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(mod).packed_offset.bit_offset) +
(if (mod.typeToStruct(container_ty)) |struct_obj| mod.structPackedFieldBitOffset(struct_obj, index) else 0) -
ptr_field_ty.ptrInfo(mod).packed_offset.bit_offset, 8),
};
const src_mcv = try self.resolveInst(operand);
const dst_mcv = if (switch (src_mcv) {
@ -7938,7 +7935,7 @@ fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32
.register, .register_offset => self.reuseOperand(inst, operand, 0, src_mcv),
else => false,
}) src_mcv else try self.copyToRegisterWithInstTracking(inst, ptr_field_ty, src_mcv);
return dst_mcv.offset(field_offset);
return dst_mcv.offset(field_off);
}
fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
@ -7958,11 +7955,8 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
const src_mcv = try self.resolveInst(operand);
const field_off: u32 = switch (container_ty.containerLayout(mod)) {
.auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, mod) * 8),
.@"packed" => if (mod.typeToStruct(container_ty)) |struct_type|
mod.structPackedFieldBitOffset(struct_type, index)
else
0,
.auto, .@"extern" => @intCast(container_ty.structFieldOffset(extra.field_index, mod) * 8),
.@"packed" => if (mod.typeToStruct(container_ty)) |struct_obj| mod.structPackedFieldBitOffset(struct_obj, extra.field_index) else 0,
};
switch (src_mcv) {
@ -8239,7 +8233,12 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
const inst_ty = self.typeOfIndex(inst);
const parent_ty = inst_ty.childType(mod);
const field_offset: i32 = @intCast(parent_ty.structFieldOffset(extra.field_index, mod));
const field_off: i32 = switch (parent_ty.containerLayout(mod)) {
.auto, .@"extern" => @intCast(parent_ty.structFieldOffset(extra.field_index, mod)),
.@"packed" => @divExact(@as(i32, inst_ty.ptrInfo(mod).packed_offset.bit_offset) +
(if (mod.typeToStruct(parent_ty)) |struct_obj| mod.structPackedFieldBitOffset(struct_obj, extra.field_index) else 0) -
self.typeOf(extra.field_ptr).ptrInfo(mod).packed_offset.bit_offset, 8),
};
const src_mcv = try self.resolveInst(extra.field_ptr);
const dst_mcv = if (src_mcv.isRegisterOffset() and
@ -8247,7 +8246,7 @@ fn airFieldParentPtr(self: *Self, inst: Air.Inst.Index) !void {
src_mcv
else
try self.copyToRegisterWithInstTracking(inst, inst_ty, src_mcv);
const result = dst_mcv.offset(-field_offset);
const result = dst_mcv.offset(-field_off);
return self.finishAir(inst, result, .{ extra.field_ptr, .none, .none });
}
@ -17950,7 +17949,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
.Struct => {
const frame_index = try self.allocFrameIndex(FrameAlloc.initSpill(result_ty, mod));
if (result_ty.containerLayout(mod) == .@"packed") {
const struct_type = mod.typeToStruct(result_ty).?;
const struct_obj = mod.typeToStruct(result_ty).?;
try self.genInlineMemset(
.{ .lea_frame = .{ .index = frame_index } },
.{ .immediate = 0 },
@ -17971,7 +17970,7 @@ fn airAggregateInit(self: *Self, inst: Air.Inst.Index) !void {
}
const elem_abi_size: u32 = @intCast(elem_ty.abiSize(mod));
const elem_abi_bits = elem_abi_size * 8;
const elem_off = mod.structPackedFieldBitOffset(struct_type, elem_i);
const elem_off = mod.structPackedFieldBitOffset(struct_obj, elem_i);
const elem_byte_off: i32 = @intCast(elem_off / elem_abi_bits * elem_abi_size);
const elem_bit_off = elem_off % elem_abi_bits;
const elem_mcv = try self.resolveInst(elem);

View File

@ -693,5 +693,5 @@ test "zero-bit fields in extern struct pad fields appropriately" {
try expect(@intFromPtr(&s) % 2 == 0);
try expect(@intFromPtr(&s.y) - @intFromPtr(&s.x) == 2);
try expect(@intFromPtr(&s.y) == @intFromPtr(&s.a));
try expect(@fieldParentPtr(S, "a", &s.a) == &s);
try expect(@fieldParentPtr(*S, "a", &s.a) == &s);
}

File diff suppressed because it is too large Load Diff

View File

@ -1392,13 +1392,13 @@ test "fieldParentPtr of a zero-bit field" {
{
const a = A{ .u = 0 };
const b_ptr = &a.b;
const a_ptr = @fieldParentPtr(A, "b", b_ptr);
const a_ptr = @fieldParentPtr(*const A, "b", b_ptr);
try std.testing.expectEqual(&a, a_ptr);
}
{
var a = A{ .u = 0 };
const b_ptr = &a.b;
const a_ptr = @fieldParentPtr(A, "b", b_ptr);
const a_ptr = @fieldParentPtr(*const A, "b", b_ptr);
try std.testing.expectEqual(&a, a_ptr);
}
}
@ -1406,17 +1406,17 @@ test "fieldParentPtr of a zero-bit field" {
{
const a = A{ .u = 0 };
const c_ptr = &a.b.c;
const b_ptr = @fieldParentPtr(@TypeOf(a.b), "c", c_ptr);
const b_ptr = @fieldParentPtr(*const @TypeOf(a.b), "c", c_ptr);
try std.testing.expectEqual(&a.b, b_ptr);
const a_ptr = @fieldParentPtr(A, "b", b_ptr);
const a_ptr = @fieldParentPtr(*const A, "b", b_ptr);
try std.testing.expectEqual(&a, a_ptr);
}
{
var a = A{ .u = 0 };
const c_ptr = &a.b.c;
const b_ptr = @fieldParentPtr(@TypeOf(a.b), "c", c_ptr);
const b_ptr = @fieldParentPtr(*const @TypeOf(a.b), "c", c_ptr);
try std.testing.expectEqual(&a.b, b_ptr);
const a_ptr = @fieldParentPtr(A, "b", b_ptr);
const a_ptr = @fieldParentPtr(*const A, "b", b_ptr);
try std.testing.expectEqual(&a, a_ptr);
}
}

View File

@ -222,7 +222,7 @@ test "fieldParentPtr of tuple" {
var x: u32 = 0;
_ = &x;
const tuple = .{ x, x };
try testing.expect(&tuple == @fieldParentPtr(@TypeOf(tuple), "1", &tuple[1]));
try testing.expect(&tuple == @fieldParentPtr(*const @TypeOf(tuple), "1", &tuple[1]));
}
test "fieldParentPtr of anon struct" {
@ -233,7 +233,7 @@ test "fieldParentPtr of anon struct" {
var x: u32 = 0;
_ = &x;
const anon_st = .{ .foo = x, .bar = x };
try testing.expect(&anon_st == @fieldParentPtr(@TypeOf(anon_st), "bar", &anon_st.bar));
try testing.expect(&anon_st == @fieldParentPtr(*const @TypeOf(anon_st), "bar", &anon_st.bar));
}
test "offsetOf tuple" {

View File

@ -2,12 +2,12 @@ const Foo = extern struct {
derp: i32,
};
export fn foo(a: *i32) *Foo {
return @fieldParentPtr(Foo, "a", a);
return @fieldParentPtr(*Foo, "a", a);
}
// error
// backend=stage2
// target=native
//
// :5:33: error: no field named 'a' in struct 'tmp.Foo'
// :5:34: error: no field named 'a' in struct 'tmp.Foo'
// :1:20: note: struct declared here

View File

@ -9,7 +9,7 @@ const foo = Foo{
comptime {
const field_ptr: *i32 = @ptrFromInt(0x1234);
const another_foo_ptr = @fieldParentPtr(Foo, "b", field_ptr);
const another_foo_ptr = @fieldParentPtr(*const Foo, "b", field_ptr);
_ = another_foo_ptr;
}
@ -17,4 +17,4 @@ comptime {
// backend=stage2
// target=native
//
// :12:55: error: pointer value not based on parent struct
// :12:62: error: pointer value not based on parent struct

View File

@ -8,7 +8,7 @@ const foo = Foo{
};
comptime {
const another_foo_ptr = @fieldParentPtr(Foo, "b", &foo.a);
const another_foo_ptr = @fieldParentPtr(*const Foo, "b", &foo.a);
_ = another_foo_ptr;
}

View File

@ -2,11 +2,11 @@ const Foo = extern struct {
a: i32,
};
export fn foo(a: i32) *Foo {
return @fieldParentPtr(Foo, "a", a);
return @fieldParentPtr(*const Foo, "a", a);
}
// error
// backend=stage2
// target=native
//
// :5:38: error: expected pointer type, found 'i32'
// :5:45: error: expected pointer type, found 'i32'

View File

@ -7,4 +7,4 @@ export fn foo(a: *i32) *Foo {
// backend=llvm
// target=native
//
// :3:28: error: expected struct or union type, found 'i32'
// :3:28: error: expected pointer type, found 'i32'

View File

@ -5,7 +5,7 @@ pub export fn entry1() void {
@offsetOf(T, "a");
}
pub export fn entry2() void {
@fieldParentPtr(T, "a", undefined);
@fieldParentPtr(*T, "a", undefined);
}
// error
@ -13,4 +13,4 @@ pub export fn entry2() void {
// target=native
//
// :5:5: error: no offset available for comptime field
// :8:5: error: cannot get @fieldParentPtr of a comptime field
// :8:25: error: cannot get @fieldParentPtr of a comptime field

View File

@ -0,0 +1,13 @@
comptime {
_ = *align(1:32:4) u8;
}
comptime {
_ = *align(1:25:4) u8;
}
// error
// backend=stage2
// target=native
//
// :2:18: error: packed type 'u8' at bit offset 32 starts 0 bits after the end of a 4 byte host integer
// :5:18: error: packed type 'u8' at bit offset 25 ends 1 bits after the end of a 4 byte host integer