diff options
| -rw-r--r-- | src/InternPool.zig | 59 | ||||
| -rw-r--r-- | src/Sema.zig | 229 | ||||
| -rw-r--r-- | src/arch/x86_64/CodeGen.zig | 37 | ||||
| -rw-r--r-- | test/behavior/align.zig | 2 | ||||
| -rw-r--r-- | test/behavior/field_parent_ptr.zig | 1966 | ||||
| -rw-r--r-- | test/behavior/struct.zig | 12 | ||||
| -rw-r--r-- | test/behavior/tuple.zig | 4 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr-bad_field_name.zig | 4 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig | 4 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig | 2 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig | 4 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr-non_pointer.zig (renamed from test/cases/compile_errors/fieldParentPtr-non_struct.zig) | 2 | ||||
| -rw-r--r-- | test/cases/compile_errors/fieldParentPtr_on_comptime_field.zig | 4 | ||||
| -rw-r--r-- | test/cases/compile_errors/invalid_bit_pointer.zig | 13 |
14 files changed, 2108 insertions, 234 deletions
diff --git a/src/InternPool.zig b/src/InternPool.zig index 67368e1195..4edc32e86c 100644 --- a/src/InternPool.zig +++ b/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| { diff --git a/src/Sema.zig b/src/Sema.zig index 74991d5769..189a9c4d11 100644 --- a/src/Sema.zig +++ b/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( diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b20a322033..7a90eacf54 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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); diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 2714612682..411579fef0 100644 --- a/test/behavior/align.zig +++ b/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); } diff --git a/test/behavior/field_parent_ptr.zig b/test/behavior/field_parent_ptr.zig index adb0e66ed6..896fa3ab59 100644 --- a/test/behavior/field_parent_ptr.zig +++ b/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); + } } diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index f85e783342..cbf7493b86 100644 --- a/test/behavior/struct.zig +++ b/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); } } diff --git a/test/behavior/tuple.zig b/test/behavior/tuple.zig index bfd913774f..7cc157653a 100644 --- a/test/behavior/tuple.zig +++ b/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" { diff --git a/test/cases/compile_errors/fieldParentPtr-bad_field_name.zig b/test/cases/compile_errors/fieldParentPtr-bad_field_name.zig index d3e487d3ce..10a2bf384d 100644 --- a/test/cases/compile_errors/fieldParentPtr-bad_field_name.zig +++ b/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 diff --git a/test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig b/test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig index 2147fb8aed..751dc6681e 100644 --- a/test/cases/compile_errors/fieldParentPtr-comptime_field_ptr_not_based_on_struct.zig +++ b/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 diff --git a/test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig b/test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig index 7a37eb2adc..3f459c66ee 100644 --- a/test/cases/compile_errors/fieldParentPtr-comptime_wrong_field_index.zig +++ b/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; } diff --git a/test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig b/test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig index 8a57d08c3b..b2a7768611 100644 --- a/test/cases/compile_errors/fieldParentPtr-field_pointer_is_not_pointer.zig +++ b/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' diff --git a/test/cases/compile_errors/fieldParentPtr-non_struct.zig b/test/cases/compile_errors/fieldParentPtr-non_pointer.zig index 7950c88537..27d8ad9c20 100644 --- a/test/cases/compile_errors/fieldParentPtr-non_struct.zig +++ b/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' diff --git a/test/cases/compile_errors/fieldParentPtr_on_comptime_field.zig b/test/cases/compile_errors/fieldParentPtr_on_comptime_field.zig index fb95ea691c..1b26bfcff9 100644 --- a/test/cases/compile_errors/fieldParentPtr_on_comptime_field.zig +++ b/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 diff --git a/test/cases/compile_errors/invalid_bit_pointer.zig b/test/cases/compile_errors/invalid_bit_pointer.zig new file mode 100644 index 0000000000..e05aaad07a --- /dev/null +++ b/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 |
