Commit c467f6693e

Andrew Kelley <andrew@ziglang.org>
2022-03-07 21:36:58
stage2: fix union layout returning non-zero for zero-sized tag
1 parent f59cbd8
Changed files (2)
src
test
behavior
src/Module.zig
@@ -1278,7 +1278,8 @@ pub const Union = struct {
         var biggest_field: u32 = undefined;
         var payload_size: u64 = 0;
         var payload_align: u32 = 0;
-        for (u.fields.values()) |field, i| {
+        const fields = u.fields.values();
+        for (fields) |field, i| {
             if (!field.ty.hasRuntimeBits()) continue;
 
             const field_align = a: {
@@ -1300,7 +1301,7 @@ pub const Union = struct {
             }
         }
         payload_align = @maximum(payload_align, 1);
-        if (!have_tag) return .{
+        if (!have_tag or fields.len <= 1) return .{
             .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
             .abi_align = payload_align,
             .most_aligned_field = most_aligned_field,
test/behavior/union.zig
@@ -1011,7 +1011,9 @@ test "cast from pointer to anonymous struct to pointer to union" {
 }
 
 test "switching on non exhaustive union" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage1) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
 
     const S = struct {
         const E = enum(u8) {
@@ -1027,7 +1029,8 @@ test "switching on non exhaustive union" {
             var a = U{ .a = 2 };
             switch (a) {
                 .a => |val| try expect(val == 2),
-                .b => unreachable,
+                .b => return error.Fail,
+                _ => return error.Fail,
             }
         }
     };
@@ -1036,7 +1039,9 @@ test "switching on non exhaustive union" {
 }
 
 test "containers with single-field enums" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
 
     const S = struct {
         const A = union(enum) { f1 };
@@ -1061,8 +1066,10 @@ test "containers with single-field enums" {
     comptime try S.doTheTest();
 }
 
-test "@unionInit on union w/ tag but no fields" {
-    if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
+test "@unionInit on union with tag but no fields" {
+    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
+    if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
 
     const S = struct {
         const Type = enum(u8) { no_op = 105 };
@@ -1077,7 +1084,11 @@ test "@unionInit on union w/ tag but no fields" {
         };
 
         comptime {
-            std.debug.assert(@sizeOf(Data) != 0);
+            if (builtin.zig_backend == .stage1) {
+                // stage1 gets the wrong answer here
+            } else {
+                std.debug.assert(@sizeOf(Data) == 0);
+            }
         }
 
         fn doTheTest() !void {