Commit 9b2345e182
Changed files (14)
src
test
src/arch/x86_64/CodeGen.zig
@@ -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);
src/InternPool.zig
@@ -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| {
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;
- }
- };
- }
-
- 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);
+ 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);
- ptr_ty_data.child = parent_ty.toIntern();
- const result_ptr = try sema.ptrType(ptr_ty_data);
+ 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);
+ },
+ }
- 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(
test/behavior/align.zig
@@ -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);
}
test/behavior/field_parent_ptr.zig
@@ -1,126 +1,1924 @@
const expect = @import("std").testing.expect;
const builtin = @import("builtin");
-test "@fieldParentPtr non-first field" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+test "@fieldParentPtr struct" {
+ const C = struct {
+ a: bool = true,
+ b: f32 = 3.14,
+ c: struct { u8 } = .{42},
+ d: i32 = 12345,
+ };
- try testParentFieldPtr(&foo.c);
- try comptime testParentFieldPtr(&foo.c);
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
-test "@fieldParentPtr first field" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
+test "@fieldParentPtr extern struct" {
+ const C = extern struct {
+ a: bool = true,
+ b: f32 = 3.14,
+ c: extern struct { x: u8 } = .{ .x = 42 },
+ d: i32 = 12345,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
- try testParentFieldPtrFirst(&foo.a);
- try comptime testParentFieldPtrFirst(&foo.a);
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
-const Foo = struct {
- a: bool,
- b: f32,
- c: i32,
- d: i32,
-};
+test "@fieldParentPtr extern struct first zero-bit field" {
+ const C = extern struct {
+ a: u0 = 0,
+ b: f32 = 3.14,
+ c: i32 = 12345,
+ };
-const foo = Foo{
- .a = true,
- .b = 0.123,
- .c = 1234,
- .d = -10,
-};
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
-fn testParentFieldPtr(c: *const i32) !void {
- try expect(c == &foo.c);
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
- const base = @fieldParentPtr(Foo, "c", c);
- try expect(base == &foo);
- try expect(&base.c == c);
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
}
-fn testParentFieldPtrFirst(a: *const bool) !void {
- try expect(a == &foo.a);
+test "@fieldParentPtr extern struct middle zero-bit field" {
+ const C = extern struct {
+ a: f32 = 3.14,
+ b: u0 = 0,
+ c: i32 = 12345,
+ };
+
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
- const base = @fieldParentPtr(Foo, "a", a);
- try expect(base == &foo);
- try expect(&base.a == a);
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
}
-test "@fieldParentPtr untagged union" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+test "@fieldParentPtr extern struct last zero-bit field" {
+ const C = extern struct {
+ a: f32 = 3.14,
+ b: i32 = 12345,
+ c: u0 = 0,
+ };
+
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = 0 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = 0 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = 0 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = 0 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+}
+
+test "@fieldParentPtr unaligned packed struct" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed struct {
+ a: bool = true,
+ b: f32 = 3.14,
+ c: packed struct { x: u8 } = .{ .x = 42 },
+ d: i32 = 12345,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
- try testFieldParentPtrUnion(&bar.c);
- try comptime testFieldParentPtrUnion(&bar.c);
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
-const Bar = union(enum) {
- a: bool,
- b: f32,
- c: i32,
- d: i32,
-};
+test "@fieldParentPtr aligned packed struct" {
+ if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed struct {
+ a: f32 = 3.14,
+ b: i32 = 12345,
+ c: packed struct { x: u8 } = .{ .x = 42 },
+ d: bool = true,
+ };
+
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .d = false };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = false };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = false };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = false };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
+}
+
+test "@fieldParentPtr nested packed struct" {
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ {
+ const C = packed struct {
+ a: u8,
+ b: packed struct {
+ a: u8,
+ b: packed struct {
+ a: u8,
+ },
+ },
+ };
+
+ {
+ const c: C = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ const pcbba = &c.b.b.a;
+ const pcbb: @TypeOf(&c.b.b) = @alignCast(@fieldParentPtr(*align(1) const @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ const pcb: @TypeOf(&c.b) = @alignCast(@fieldParentPtr(*align(1) const @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcb));
+ try expect(pc == &c);
+ }
+
+ {
+ var c: C = undefined;
+ c = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ var pcbba: @TypeOf(&c.b.b.a) = undefined;
+ pcbba = &c.b.b.a;
+ var pcbb: @TypeOf(&c.b.b) = undefined;
+ pcbb = @alignCast(@fieldParentPtr(*align(1) @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ var pcb: @TypeOf(&c.b) = undefined;
+ pcb = @alignCast(@fieldParentPtr(*align(1) @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcb));
+ try expect(pc == &c);
+ }
+ }
+
+ {
+ const C = packed struct {
+ a: u8,
+ b: packed struct {
+ a: u9,
+ b: packed struct {
+ a: u8,
+ },
+ },
+ };
+
+ {
+ const c: C = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ const pcbba = &c.b.b.a;
+ const pcbb: @TypeOf(&c.b.b) = @alignCast(@fieldParentPtr(*align(1:17:4) const @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ const pcb: @TypeOf(&c.b) = @alignCast(@fieldParentPtr(*align(1:8:4) const @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcb));
+ try expect(pc == &c);
+ }
+
+ {
+ var c: C = undefined;
+ c = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ var pcbba: @TypeOf(&c.b.b.a) = undefined;
+ pcbba = &c.b.b.a;
+ var pcbb: @TypeOf(&c.b.b) = undefined;
+ pcbb = @alignCast(@fieldParentPtr(*align(1:17:4) @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ var pcb: @TypeOf(&c.b) = undefined;
+ pcb = @alignCast(@fieldParentPtr(*align(1:8:4) @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcb));
+ try expect(pc == &c);
+ }
+ }
+
+ {
+ const C = packed struct {
+ a: u9,
+ b: packed struct {
+ a: u7,
+ b: packed struct {
+ a: u8,
+ },
+ },
+ };
+
+ {
+ const c: C = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ const pcbba = &c.b.b.a;
+ const pcbb: @TypeOf(&c.b.b) = @alignCast(@fieldParentPtr(*align(1) const @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ const pcb: @TypeOf(&c.b) = @alignCast(@fieldParentPtr(*align(1:9:3) const @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcb));
+ try expect(pc == &c);
+ }
+
+ {
+ var c: C = undefined;
+ c = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ var pcbba: @TypeOf(&c.b.b.a) = undefined;
+ pcbba = &c.b.b.a;
+ var pcbb: @TypeOf(&c.b.b) = undefined;
+ pcbb = @alignCast(@fieldParentPtr(*align(1) @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ var pcb: @TypeOf(&c.b) = undefined;
+ pcb = @alignCast(@fieldParentPtr(*align(1:9:3) @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcb));
+ try expect(pc == &c);
+ }
+ }
-const bar = Bar{ .c = 42 };
+ {
+ const C = packed struct {
+ a: u9,
+ b: packed struct {
+ a: u8,
+ b: packed struct {
+ a: u8,
+ },
+ },
+ };
-fn testFieldParentPtrUnion(c: *const i32) !void {
- try expect(c == &bar.c);
+ {
+ const c: C = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ const pcbba = &c.b.b.a;
+ const pcbb: @TypeOf(&c.b.b) = @alignCast(@fieldParentPtr(*align(1:17:4) const @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ const pcb: @TypeOf(&c.b) = @alignCast(@fieldParentPtr(*align(1:9:4) const @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcb));
+ try expect(pc == &c);
+ }
- const base = @fieldParentPtr(Bar, "c", c);
- try expect(base == &bar);
- try expect(&base.c == c);
+ {
+ var c: C = undefined;
+ c = .{ .a = 0, .b = .{ .a = 0, .b = .{ .a = 0 } } };
+ var pcbba: @TypeOf(&c.b.b.a) = undefined;
+ pcbba = &c.b.b.a;
+ var pcbb: @TypeOf(&c.b.b) = undefined;
+ pcbb = @alignCast(@fieldParentPtr(*align(1:17:4) @TypeOf(c.b.b), "a", pcbba));
+ try expect(pcbb == &c.b.b);
+ var pcb: @TypeOf(&c.b) = undefined;
+ pcb = @alignCast(@fieldParentPtr(*align(1:9:4) @TypeOf(c.b), "b", pcbb));
+ try expect(pcb == &c.b);
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcb));
+ try expect(pc == &c);
+ }
+ }
+}
+
+test "@fieldParentPtr packed struct first zero-bit field" {
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed struct {
+ a: u0 = 0,
+ b: f32 = 3.14,
+ c: i32 = 12345,
+ };
+
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 666.667 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+}
+
+test "@fieldParentPtr packed struct middle zero-bit field" {
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed struct {
+ a: f32 = 3.14,
+ b: u0 = 0,
+ c: i32 = 12345,
+ };
+
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = -1111111111 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+}
+
+test "@fieldParentPtr packed struct last zero-bit field" {
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed struct {
+ a: f32 = 3.14,
+ b: i32 = 12345,
+ c: u0 = 0,
+ };
+
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 666.667 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = -1111111111 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = 0 };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = 0 };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = 0 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = 0 };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
}
test "@fieldParentPtr tagged union" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ const C = union(enum) {
+ a: bool,
+ b: f32,
+ c: struct { u8 },
+ d: i32,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
- try testFieldParentPtrTaggedUnion(&bar_tagged.c);
- try comptime testFieldParentPtrTaggedUnion(&bar_tagged.c);
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
-const BarTagged = union(enum) {
- a: bool,
- b: f32,
- c: i32,
- d: i32,
-};
+test "@fieldParentPtr untagged union" {
+ const C = union {
+ a: bool,
+ b: f32,
+ c: struct { u8 },
+ d: i32,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
-const bar_tagged = BarTagged{ .c = 42 };
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
-fn testFieldParentPtrTaggedUnion(c: *const i32) !void {
- try expect(c == &bar_tagged.c);
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{255} };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
- const base = @fieldParentPtr(BarTagged, "c", c);
- try expect(base == &bar_tagged);
- try expect(&base.c == c);
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
test "@fieldParentPtr extern union" {
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
- if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
+ const C = extern union {
+ a: bool,
+ b: f32,
+ c: extern struct { x: u8 },
+ d: i32,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
+}
+
+test "@fieldParentPtr packed union" {
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
+
+ const C = packed union {
+ a: bool,
+ b: f32,
+ c: packed struct { x: u8 },
+ d: i32,
+ };
+
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = false };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
+
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ const pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "c", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .c = .{ .x = 255 } };
+ var pcf: @TypeOf(&c.c) = undefined;
+ pcf = &c.c;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "c", pcf));
+ try expect(pc == &c);
+ }
- try testFieldParentPtrExternUnion(&bar_extern.c);
- try comptime testFieldParentPtrExternUnion(&bar_extern.c);
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ const pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "d", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .d = -1111111111 };
+ var pcf: @TypeOf(&c.d) = undefined;
+ pcf = &c.d;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "d", pcf));
+ try expect(pc == &c);
+ }
}
-const BarExtern = extern union {
- a: bool,
- b: f32,
- c: i32,
- d: i32,
-};
+test "@fieldParentPtr tagged union all zero-bit fields" {
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
-const bar_extern = BarExtern{ .c = 42 };
+ const C = union(enum) {
+ a: u0,
+ b: i0,
+ };
-fn testFieldParentPtrExternUnion(c: *const i32) !void {
- try expect(c == &bar_extern.c);
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ const pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "a", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .a = 0 };
+ var pcf: @TypeOf(&c.a) = undefined;
+ pcf = &c.a;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "a", pcf));
+ try expect(pc == &c);
+ }
- const base = @fieldParentPtr(BarExtern, "c", c);
- try expect(base == &bar_extern);
- try expect(&base.c == c);
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ const pc: *const C = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ const pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ const c: C = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *const C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) const C, "b", pcf));
+ try expect(pc == &c);
+ }
+ {
+ var c: C = undefined;
+ c = .{ .b = 0 };
+ var pcf: @TypeOf(&c.b) = undefined;
+ pcf = &c.b;
+ var pc: *C = undefined;
+ pc = @alignCast(@fieldParentPtr(*align(1) C, "b", pcf));
+ try expect(pc == &c);
+ }
}
test/behavior/struct.zig
@@ -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);
}
}
test/behavior/tuple.zig
@@ -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" {
test/cases/compile_errors/fieldParentPtr-bad_field_name.zig
@@ -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
test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig
@@ -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
test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig
@@ -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;
}
test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig
@@ -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'
test/cases/compile_errors/fieldParentPtr-non_struct.zig → test/cases/compile_errors/fieldParentPtr-non_pointer.zig
@@ -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'
test/cases/compile_errors/fieldParentPtr_on_comptime_field.zig
@@ -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
test/cases/compile_errors/invalid_bit_pointer.zig
@@ -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