mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
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:
parent
5a41704f7e
commit
9b2345e182
@ -5163,48 +5163,55 @@ 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{
|
||||
.ty = ptr.ty,
|
||||
.val = anon_decl.val,
|
||||
.orig_ty = anon_decl.orig_ty,
|
||||
}),
|
||||
},
|
||||
),
|
||||
.comptime_field => |field_val| {
|
||||
};
|
||||
} else .{
|
||||
.tag = .ptr_anon_decl_aligned,
|
||||
.data = try ip.addExtra(gpa, PtrAnonDeclAligned{
|
||||
.ty = ptr.ty,
|
||||
.val = anon_decl.val,
|
||||
.orig_ty = anon_decl.orig_ty,
|
||||
}),
|
||||
},
|
||||
.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| {
|
||||
|
||||
229
src/Sema.zig
229
src/Sema.zig
@ -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(.{
|
||||
.tag = .field_parent_ptr,
|
||||
.data = .{ .ty_pl = .{
|
||||
.ty = Air.internedToRef(result_ptr.toIntern()),
|
||||
.payload = try block.sema.addExtra(Air.FieldParentPtr{
|
||||
.field_ptr = casted_field_ptr,
|
||||
.field_index = @intCast(field_index),
|
||||
}),
|
||||
} },
|
||||
});
|
||||
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(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(
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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" {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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'
|
||||
@ -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
|
||||
|
||||
13
test/cases/compile_errors/invalid_bit_pointer.zig
Normal file
13
test/cases/compile_errors/invalid_bit_pointer.zig
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user