From 9ced27dace99da1f2bc704b4d5a7fabe9a62eca4 Mon Sep 17 00:00:00 2001 From: Jacob Young Date: Mon, 6 Nov 2023 07:27:55 -0500 Subject: [PATCH] x86_64: fix passing register-sized payload as non-reigster-sized union Closes #17885 --- src/InternPool.zig | 2 +- src/arch/x86_64/CodeGen.zig | 5 +++-- test/behavior/union.zig | 21 +++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/InternPool.zig b/src/InternPool.zig index 700c5859b8..b70034641e 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1887,7 +1887,7 @@ pub fn loadUnionType(ip: *InternPool, key: Key.UnionType) UnionType { .namespace = type_union.data.namespace, .enum_tag_ty = enum_ty, .int_tag_ty = enum_info.tag_ty, - .size = type_union.data.padding, + .size = type_union.data.size, .padding = type_union.data.padding, .field_names = enum_info.names, .names_map = enum_info.names_map, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 9d4ee182c4..16a4b4a7f4 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -15323,10 +15323,11 @@ fn airUnionInit(self: *Self, inst: Air.Inst.Index) !void { const src_ty = self.typeOf(extra.init); const src_mcv = try self.resolveInst(extra.init); if (layout.tag_size == 0) { - if (self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; + if (layout.abi_size <= src_ty.abiSize(mod) and + self.reuseOperand(inst, extra.init, 0, src_mcv)) break :result src_mcv; const dst_mcv = try self.allocRegOrMem(inst, true); - try self.genCopy(union_ty, dst_mcv, src_mcv); + try self.genCopy(src_ty, dst_mcv, src_mcv); break :result dst_mcv; } diff --git a/test/behavior/union.zig b/test/behavior/union.zig index da36a34d1d..26e213fb16 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1881,3 +1881,24 @@ test "union field is a pointer to an aligned version of itself" { try expect(&e == e.next); } + +test "pass register-sized field as non-register-sized union" { + const S = struct { + fn taggedUnion(u: union(enum) { x: usize, y: [2]usize }) !void { + try expectEqual(@as(usize, 42), u.x); + } + + fn untaggedUnion(u: union { x: usize, y: [2]usize }) !void { + try expectEqual(@as(usize, 42), u.x); + } + + fn externUnion(u: extern union { x: usize, y: [2]usize }) !void { + try expectEqual(@as(usize, 42), u.x); + } + }; + + var x: usize = 42; + try S.taggedUnion(.{ .x = x }); + try S.untaggedUnion(.{ .x = x }); + try S.externUnion(.{ .x = x }); +}