Commit 9ced27dace

Jacob Young <jacobly0@users.noreply.github.com>
2023-11-06 13:27:55
x86_64: fix passing register-sized payload as non-reigster-sized union
Closes #17885
1 parent 62e67a2
Changed files (3)
src
test
behavior
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;
         }
 
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,
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 });
+}