authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-02-26 08:19:01+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-26 08:19:01+01:00
log0474943ddfb12552262e3e13f74ecb3842b18019
treec46515f91973faaf597ab9758743bd2190652a2e
parentbf6540ce50f8613386be09aac7dc03604af12e1e
parente0f5627d4a9cb1b3a1361d70d40043c8c170b2af
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10991 from ziglang/macho-pointer-rebase


10 files changed, 141 insertions(+), 117 deletions(-)

src/arch/aarch64/CodeGen.zig+15
......@@ -786,6 +786,11 @@ fn allocMem(self: *Self, inst: Air.Inst.Index, abi_size: u32, abi_align: u32) !u
786786/// Use a pointer instruction as the basis for allocating stack memory.
787787fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
788788 const elem_ty = self.air.typeOfIndex(inst).elemType();
789
790 if (!elem_ty.hasRuntimeBits()) {
791 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
792 }
793
789794 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
790795 return self.fail("type '{}' too big to fit into stack frame", .{elem_ty});
791796 };
......@@ -3545,6 +3550,15 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
35453550fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
35463551 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
35473552 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
3553
3554 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
3555 if (tv.ty.zigTypeTag() == .Pointer) blk: {
3556 if (tv.ty.castPtrToFn()) |_| break :blk;
3557 if (!tv.ty.elemType2().hasRuntimeBits()) {
3558 return MCValue.none;
3559 }
3560 }
3561
35483562 decl.alive = true;
35493563 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
35503564 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
......@@ -3553,6 +3567,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
35533567 } else if (self.bin_file.cast(link.File.MachO)) |_| {
35543568 // Because MachO is PIE-always-on, we defer memory address resolution until
35553569 // the linker has enough info to perform relocations.
3570 assert(decl.link.macho.local_sym_index != 0);
35563571 return MCValue{ .got_load = decl.link.macho.local_sym_index };
35573572 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
35583573 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
src/arch/aarch64/Emit.zig+21-5
......@@ -208,8 +208,8 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
208208 }
209209
210210 switch (tag) {
211 .load_memory_direct => return 3 * 4,
211212 .load_memory_got,
212 .load_memory_direct,
213213 .load_memory_ptr_got,
214214 .load_memory_ptr_direct,
215215 => return 2 * 4,
......@@ -654,15 +654,31 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
654654 const data = emit.mir.extraData(Mir.LoadMemoryPie, payload).data;
655655 const reg = @intToEnum(Register, data.register);
656656
657 // PC-relative displacement to the entry in the GOT table.
657 // PC-relative displacement to the entry in memory.
658658 // adrp
659659 const offset = @intCast(u32, emit.code.items.len);
660660 try emit.writeInstruction(Instruction.adrp(reg, 0));
661661
662662 switch (tag) {
663 .load_memory_got,
664 .load_memory_direct,
665 => {
663 .load_memory_got => {
664 // ldr reg, reg, offset
665 try emit.writeInstruction(Instruction.ldr(
666 reg,
667 reg,
668 Instruction.LoadStoreOffset.imm(0),
669 ));
670 },
671 .load_memory_direct => {
672 // We cannot load the offset directly as it may not be aligned properly.
673 // For example, load for 64bit register will require the target address offset
674 // to be 8-byte aligned, while the value might have non-8-byte natural alignment,
675 // meaning the linker might have put it at a non-8-byte aligned address. To circumvent
676 // this, we use `adrp, add` to form the address value which we then dereference with
677 // `ldr`.
678 // Note that this can potentially be optimised out by the codegen/linker if the
679 // target address is appropriately aligned.
680 // add reg, reg, offset
681 try emit.writeInstruction(Instruction.add(reg, reg, 0, false));
666682 // ldr reg, reg, offset
667683 try emit.writeInstruction(Instruction.ldr(
668684 reg,
src/arch/x86_64/CodeGen.zig+10-1
......@@ -852,7 +852,7 @@ fn allocMemPtr(self: *Self, inst: Air.Inst.Index) !u32 {
852852 const elem_ty = ptr_ty.elemType();
853853
854854 if (!elem_ty.hasRuntimeBits()) {
855 return self.allocMem(inst, 8, 8);
855 return self.allocMem(inst, @sizeOf(usize), @alignOf(usize));
856856 }
857857
858858 const abi_size = math.cast(u32, elem_ty.abiSize(self.target.*)) catch {
......@@ -5333,6 +5333,14 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
53335333 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
53345334 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
53355335
5336 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
5337 if (tv.ty.zigTypeTag() == .Pointer) blk: {
5338 if (tv.ty.castPtrToFn()) |_| break :blk;
5339 if (!tv.ty.elemType2().hasRuntimeBits()) {
5340 return MCValue.none;
5341 }
5342 }
5343
53365344 decl.alive = true;
53375345 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
53385346 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
......@@ -5341,6 +5349,7 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
53415349 } else if (self.bin_file.cast(link.File.MachO)) |_| {
53425350 // Because MachO is PIE-always-on, we defer memory address resolution until
53435351 // the linker has enough info to perform relocations.
5352 assert(decl.link.macho.local_sym_index != 0);
53445353 return MCValue{ .got_load = decl.link.macho.local_sym_index };
53455354 } else if (self.bin_file.cast(link.File.Coff)) |coff_file| {
53465355 const got_addr = coff_file.offset_table_virtual_address + decl.link.coff.offset_table_index * ptr_bytes;
src/arch/x86_64/Emit.zig+1
......@@ -857,6 +857,7 @@ fn mirLeaPie(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
857857 else => return emit.fail("TODO unused LEA PIE variants 0b10 and 0b11", .{}),
858858 };
859859 const atom = macho_file.atom_by_index_table.get(load_reloc.atom_index).?;
860 log.debug("adding reloc of type {} to local @{d}", .{ reloc_type, load_reloc.sym_index });
860861 try atom.relocs.append(emit.bin_file.allocator, .{
861862 .offset = @intCast(u32, end_offset - 4),
862863 .target = .{ .local = load_reloc.sym_index },
src/link/MachO.zig+89-87
......@@ -3797,10 +3797,11 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl: *Module.De
37973797 atom.code.clearRetainingCapacity();
37983798 try atom.code.appendSlice(self.base.allocator, code);
37993799
3800 const match = try self.getMatchingSectionAtom(atom, typed_value.ty, typed_value.val);
3800 const match = try self.getMatchingSectionAtom(atom, decl_name, typed_value.ty, typed_value.val);
38013801 const addr = try self.allocateAtom(atom, code.len, required_alignment, match);
38023802
38033803 log.debug("allocated atom for {s} at 0x{x}", .{ name, addr });
3804 log.debug(" (required alignment 0x{x})", .{required_alignment});
38043805
38053806 errdefer self.freeAtom(atom, match, true);
38063807
......@@ -3903,28 +3904,60 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
39033904 try self.updateDeclExports(module, decl, decl_exports);
39043905}
39053906
3906fn isElemTyPointer(ty: Type) bool {
3907/// Checks if the value, or any of its embedded values stores a pointer, and thus requires
3908/// a rebase opcode for the dynamic linker.
3909fn needsPointerRebase(ty: Type, val: Value) bool {
3910 if (ty.zigTypeTag() == .Fn) {
3911 return false;
3912 }
3913 if (val.pointerDecl()) |_| {
3914 return true;
3915 }
3916
39073917 switch (ty.zigTypeTag()) {
3908 .Fn => return false,
3918 .Fn => unreachable,
39093919 .Pointer => return true,
3910 .Array => {
3911 const elem_ty = ty.elemType();
3912 return isElemTyPointer(elem_ty);
3920 .Array, .Vector => {
3921 if (ty.arrayLen() == 0) return false;
3922 const elem_ty = ty.childType();
3923 var elem_value_buf: Value.ElemValueBuffer = undefined;
3924 const elem_val = val.elemValueBuffer(0, &elem_value_buf);
3925 return needsPointerRebase(elem_ty, elem_val);
39133926 },
3914 .Struct, .Union => {
3915 const len = ty.structFieldCount();
3916 var i: usize = 0;
3917 while (i < len) : (i += 1) {
3918 const field_ty = ty.structFieldType(i);
3919 if (isElemTyPointer(field_ty)) return true;
3920 }
3921 return false;
3927 .Struct => {
3928 const fields = ty.structFields().values();
3929 if (fields.len == 0) return false;
3930 if (val.castTag(.@"struct")) |payload| {
3931 const field_values = payload.data;
3932 for (field_values) |field_val, i| {
3933 if (needsPointerRebase(fields[i].ty, field_val)) return true;
3934 } else return false;
3935 } else return false;
3936 },
3937 .Optional => {
3938 if (val.castTag(.opt_payload)) |payload| {
3939 const sub_val = payload.data;
3940 var buffer: Type.Payload.ElemType = undefined;
3941 const sub_ty = ty.optionalChild(&buffer);
3942 return needsPointerRebase(sub_ty, sub_val);
3943 } else return false;
3944 },
3945 .Union => {
3946 const union_obj = val.cast(Value.Payload.Union).?.data;
3947 const active_field_ty = ty.unionFieldType(union_obj.tag);
3948 return needsPointerRebase(active_field_ty, union_obj.val);
3949 },
3950 .ErrorUnion => {
3951 if (val.castTag(.eu_payload)) |payload| {
3952 const payload_ty = ty.errorUnionPayload();
3953 return needsPointerRebase(payload_ty, payload.data);
3954 } else return false;
39223955 },
39233956 else => return false,
39243957 }
39253958}
39263959
3927fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !MatchingSection {
3960fn getMatchingSectionAtom(self: *MachO, atom: *Atom, name: []const u8, ty: Type, val: Value) !MatchingSection {
39283961 const code = atom.code.items;
39293962 const alignment = ty.abiAlignment(self.base.options.target);
39303963 const align_log_2 = math.log2(alignment);
......@@ -3938,10 +3971,25 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
39383971 .seg = self.data_segment_cmd_index.?,
39393972 .sect = self.bss_section_index.?,
39403973 };
3974 } else {
3975 break :blk MatchingSection{
3976 .seg = self.data_segment_cmd_index.?,
3977 .sect = self.data_section_index.?,
3978 };
39413979 }
3980 }
3981
3982 if (val.castTag(.variable)) |_| {
3983 break :blk MatchingSection{
3984 .seg = self.data_segment_cmd_index.?,
3985 .sect = self.data_section_index.?,
3986 };
3987 }
3988
3989 if (needsPointerRebase(ty, val)) {
39423990 break :blk (try self.getMatchingSection(.{
3943 .segname = makeStaticString("__DATA"),
3944 .sectname = makeStaticString("__data"),
3991 .segname = makeStaticString("__DATA_CONST"),
3992 .sectname = makeStaticString("__const"),
39453993 .size = code.len,
39463994 .@"align" = align_log_2,
39473995 })).?;
......@@ -3954,8 +4002,8 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
39544002 .sect = self.text_section_index.?,
39554003 };
39564004 },
3957 .Array => switch (val.tag()) {
3958 .bytes => {
4005 .Array => {
4006 if (val.tag() == .bytes) {
39594007 switch (ty.tag()) {
39604008 .array_u8_sentinel_0,
39614009 .const_slice_u8_sentinel_0,
......@@ -3969,79 +4017,23 @@ fn getMatchingSectionAtom(self: *MachO, atom: *Atom, ty: Type, val: Value) !Matc
39694017 .@"align" = align_log_2,
39704018 })).?;
39714019 },
3972 else => {
3973 break :blk (try self.getMatchingSection(.{
3974 .segname = makeStaticString("__TEXT"),
3975 .sectname = makeStaticString("__const"),
3976 .size = code.len,
3977 .@"align" = align_log_2,
3978 })).?;
3979 },
3980 }
3981 },
3982 .array => {
3983 if (isElemTyPointer(ty)) {
3984 break :blk (try self.getMatchingSection(.{
3985 .segname = makeStaticString("__DATA_CONST"),
3986 .sectname = makeStaticString("__const"),
3987 .size = code.len,
3988 .@"align" = align_log_2,
3989 })).?;
3990 } else {
3991 break :blk (try self.getMatchingSection(.{
3992 .segname = makeStaticString("__TEXT"),
3993 .sectname = makeStaticString("__const"),
3994 .size = code.len,
3995 .@"align" = align_log_2,
3996 })).?;
4020 else => {},
39974021 }
3998 },
3999 else => {
4000 break :blk (try self.getMatchingSection(.{
4001 .segname = makeStaticString("__TEXT"),
4002 .sectname = makeStaticString("__const"),
4003 .size = code.len,
4004 .@"align" = align_log_2,
4005 })).?;
4006 },
4007 },
4008 .Pointer => {
4009 if (val.castTag(.variable)) |_| {
4010 break :blk MatchingSection{
4011 .seg = self.data_segment_cmd_index.?,
4012 .sect = self.data_section_index.?,
4013 };
4014 } else {
4015 break :blk (try self.getMatchingSection(.{
4016 .segname = makeStaticString("__DATA_CONST"),
4017 .sectname = makeStaticString("__const"),
4018 .size = code.len,
4019 .@"align" = align_log_2,
4020 })).?;
4021 }
4022 },
4023 else => {
4024 if (val.castTag(.variable)) |_| {
4025 break :blk MatchingSection{
4026 .seg = self.data_segment_cmd_index.?,
4027 .sect = self.data_section_index.?,
4028 };
4029 } else {
4030 break :blk (try self.getMatchingSection(.{
4031 .segname = makeStaticString("__TEXT"),
4032 .sectname = makeStaticString("__const"),
4033 .size = code.len,
4034 .@"align" = align_log_2,
4035 })).?;
40364022 }
40374023 },
4024 else => {},
40384025 }
4026 break :blk (try self.getMatchingSection(.{
4027 .segname = makeStaticString("__TEXT"),
4028 .sectname = makeStaticString("__const"),
4029 .size = code.len,
4030 .@"align" = align_log_2,
4031 })).?;
40394032 };
4040 const local = self.locals.items[atom.local_sym_index];
40414033 const seg = self.load_commands.items[match.seg].segment;
40424034 const sect = seg.sections.items[match.sect];
40434035 log.debug(" allocating atom '{s}' in '{s},{s}' ({d},{d})", .{
4044 self.getString(local.n_strx),
4036 name,
40454037 sect.segName(),
40464038 sect.sectName(),
40474039 match.seg,
......@@ -4055,13 +4047,14 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
40554047 assert(decl.link.macho.local_sym_index != 0); // Caller forgot to call allocateDeclIndexes()
40564048 const symbol = &self.locals.items[decl.link.macho.local_sym_index];
40574049
4050 const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
4051 defer self.base.allocator.free(sym_name);
4052
40584053 const decl_ptr = self.decls.getPtr(decl).?;
40594054 if (decl_ptr.* == null) {
4060 decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, decl.ty, decl.val);
4055 decl_ptr.* = try self.getMatchingSectionAtom(&decl.link.macho, sym_name, decl.ty, decl.val);
40614056 }
40624057 const match = decl_ptr.*.?;
4063 const sym_name = try decl.getFullyQualifiedName(self.base.allocator);
4064 defer self.base.allocator.free(sym_name);
40654058
40664059 if (decl.link.macho.size != 0) {
40674060 const capacity = decl.link.macho.capacity(self.*);
......@@ -4071,6 +4064,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
40714064 const vaddr = try self.growAtom(&decl.link.macho, code_len, required_alignment, match);
40724065
40734066 log.debug("growing {s} and moving from 0x{x} to 0x{x}", .{ sym_name, symbol.n_value, vaddr });
4067 log.debug(" (required alignment 0x{x})", .{required_alignment});
40744068
40754069 if (vaddr != symbol.n_value) {
40764070 log.debug(" (writing new GOT entry)", .{});
......@@ -4105,6 +4099,7 @@ fn placeDecl(self: *MachO, decl: *Module.Decl, code_len: usize) !*macho.nlist_64
41054099 const addr = try self.allocateAtom(&decl.link.macho, code_len, required_alignment, match);
41064100
41074101 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, addr });
4102 log.debug(" (required alignment 0x{x})", .{required_alignment});
41084103
41094104 errdefer self.freeAtom(&decl.link.macho, match, false);
41104105
......@@ -4291,6 +4286,7 @@ pub fn deleteExport(self: *MachO, exp: Export) void {
42914286}
42924287
42934288fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {
4289 log.debug("freeUnnamedConsts for decl {*}", .{decl});
42944290 const unnamed_consts = self.unnamed_const_atoms.getPtr(decl) orelse return;
42954291 for (unnamed_consts.items) |atom| {
42964292 self.freeAtom(atom, .{
......@@ -4300,6 +4296,7 @@ fn freeUnnamedConsts(self: *MachO, decl: *Module.Decl) void {
43004296 self.locals_free_list.append(self.base.allocator, atom.local_sym_index) catch {};
43014297 self.locals.items[atom.local_sym_index].n_type = 0;
43024298 _ = self.atom_by_index_table.remove(atom.local_sym_index);
4299 log.debug(" adding local symbol index {d} to free list", .{atom.local_sym_index});
43034300 atom.local_sym_index = 0;
43044301 }
43054302 unnamed_consts.clearAndFree(self.base.allocator);
......@@ -4324,10 +4321,15 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
43244321 self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};
43254322 self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };
43264323 _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });
4324 log.debug(" adding GOT index {d} to free list (target local@{d})", .{
4325 got_index,
4326 decl.link.macho.local_sym_index,
4327 });
43274328 }
43284329
43294330 self.locals.items[decl.link.macho.local_sym_index].n_type = 0;
43304331 _ = self.atom_by_index_table.remove(decl.link.macho.local_sym_index);
4332 log.debug(" adding local symbol index {d} to free list", .{decl.link.macho.local_sym_index});
43314333 decl.link.macho.local_sym_index = 0;
43324334 }
43334335 if (self.d_sym) |*d_sym| {
src/link/MachO/Atom.zig+5-5
......@@ -691,11 +691,11 @@ pub fn resolveRelocs(self: *Atom, macho_file: *MachO) !void {
691691
692692 if (is_via_got) {
693693 const got_index = macho_file.got_entries_table.get(rel.target) orelse {
694 const n_strx = switch (rel.target) {
695 .local => |sym_index| macho_file.locals.items[sym_index].n_strx,
696 .global => |n_strx| n_strx,
697 };
698 log.err("expected GOT entry for symbol '{s}'", .{macho_file.getString(n_strx)});
694 log.err("expected GOT entry for symbol", .{});
695 switch (rel.target) {
696 .local => |sym_index| log.err(" local @{d}", .{sym_index}),
697 .global => |n_strx| log.err(" global @'{s}'", .{macho_file.getString(n_strx)}),
698 }
699699 log.err(" this is an internal linker error", .{});
700700 return error.FailedToResolveRelocationTarget;
701701 };
test/behavior/align.zig-1
......@@ -7,7 +7,6 @@ var foo: u8 align(4) = 100;
77
88test "global variable alignment" {
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
1110
1211 comptime try expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
1312 comptime try expect(@TypeOf(&foo) == *align(4) u8);
test/behavior/basic.zig-5
......@@ -195,9 +195,6 @@ test "multiline string comments at multiple places" {
195195}
196196
197197test "string concatenation" {
198 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
199 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
200
201198 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
202199}
203200
......@@ -402,8 +399,6 @@ fn testTakeAddressOfParameter(f: f32) !void {
402399
403400test "pointer to void return type" {
404401 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
405 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
406 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
407402
408403 try testPointerToVoidReturnType();
409404}
test/behavior/struct.zig-2
......@@ -370,8 +370,6 @@ test "empty struct method call" {
370370 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
371371 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
372372 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
373 if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
374 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest; // TODO
375373
376374 const es = EmptyStruct{};
377375 try expect(es.method() == 1234);
test/behavior/union.zig-11
......@@ -44,7 +44,6 @@ fn setInt(foo: *Foo, x: i32) void {
4444
4545test "comptime union field access" {
4646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
4847
4948 comptime {
5049 var foo = Foo{ .int = 0 };
......@@ -77,14 +76,12 @@ const ExternPtrOrInt = extern union {
7776};
7877test "extern union size" {
7978 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
80 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8179
8280 comptime try expect(@sizeOf(ExternPtrOrInt) == 8);
8381}
8482
8583test "0-sized extern union definition" {
8684 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
8885
8986 const U = extern union {
9087 a: void,
......@@ -115,9 +112,7 @@ const err = @as(anyerror!Agg, Agg{
115112const array = [_]Value{ v1, v2, v1, v2 };
116113
117114test "unions embedded in aggregate types" {
118 if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .macos) return error.SkipZigTest;
119115 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
121116
122117 switch (array[1]) {
123118 Value.Array => |arr| try expect(arr[4] == 3),
......@@ -131,7 +126,6 @@ test "unions embedded in aggregate types" {
131126
132127test "access a member of tagged union with conflicting enum tag name" {
133128 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
134 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
135129
136130 const Bar = union(enum) {
137131 A: A,
......@@ -176,7 +170,6 @@ const TaggedUnionWithPayload = union(enum) {
176170
177171test "union alignment" {
178172 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
179 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
180173
181174 comptime {
182175 try expect(@alignOf(AlignTestTaggedUnion) >= @alignOf([9]u8));
......@@ -276,7 +269,6 @@ fn testCastUnionToTag() !void {
276269
277270test "union field access gives the enum values" {
278271 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
279 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
280272
281273 try expect(TheUnion.A == TheTag.A);
282274 try expect(TheUnion.B == TheTag.B);
......@@ -352,7 +344,6 @@ const PackedPtrOrInt = packed union {
352344};
353345test "packed union size" {
354346 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
356347
357348 comptime try expect(@sizeOf(PackedPtrOrInt) == 8);
358349}
......@@ -362,7 +353,6 @@ const ZeroBits = union {
362353};
363354test "union with only 1 field which is void should be zero bits" {
364355 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
365 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
366356
367357 comptime try expect(@sizeOf(ZeroBits) == 0);
368358}
......@@ -422,7 +412,6 @@ test "union with only 1 field casted to its enum type" {
422412
423413test "union with one member defaults to u0 tag type" {
424414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
425 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
426415
427416 const U0 = union(enum) {
428417 X: u32,