Commit 3d639481d9

Krzysztof Wolicki <der.teufel.mail@gmail.com>
2025-07-30 20:18:49
Sema: disallow tags on non-auto unions when reifying (#23488)
1 parent cf7a28f
src/Sema.zig
@@ -20630,6 +20630,16 @@ fn zirReify(
             }
             const layout = try sema.interpretBuiltinType(block, operand_src, layout_val, std.builtin.Type.ContainerLayout);
 
+            const has_tag = tag_type_val.optionalValue(zcu) != null;
+
+            if (has_tag) {
+                switch (layout) {
+                    .@"extern" => return sema.fail(block, src, "extern union does not support enum tag type", .{}),
+                    .@"packed" => return sema.fail(block, src, "packed union does not support enum tag type", .{}),
+                    .auto => {},
+                }
+            }
+
             const fields_arr = try sema.derefSliceAsArray(block, operand_src, fields_val, .{ .simple = .union_fields });
 
             return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_arr, name_strategy);
test/cases/compile_errors/reify_type_for_tagged_extern_union.zig
@@ -0,0 +1,34 @@
+const Tag = @Type(.{
+    .@"enum" = .{
+        .tag_type = u2,
+        .fields = &.{
+            .{ .name = "signed", .value = 0 },
+            .{ .name = "unsigned", .value = 1 },
+        },
+        .decls = &.{},
+        .is_exhaustive = true,
+    },
+});
+
+const Extern = @Type(.{
+    .@"union" = .{
+        .layout = .@"extern",
+        .tag_type = Tag,
+        .fields = &.{
+            .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
+            .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
+        },
+        .decls = &.{},
+    },
+});
+
+export fn entry() void {
+    const tagged: Extern = .{ .signed = -1 };
+    _ = tagged;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :13:16: error: extern union does not support enum tag type
test/cases/compile_errors/reify_type_for_tagged_packed_union.zig
@@ -0,0 +1,34 @@
+const Tag = @Type(.{
+    .@"enum" = .{
+        .tag_type = u2,
+        .fields = &.{
+            .{ .name = "signed", .value = 0 },
+            .{ .name = "unsigned", .value = 1 },
+        },
+        .decls = &.{},
+        .is_exhaustive = true,
+    },
+});
+
+const Packed = @Type(.{
+    .@"union" = .{
+        .layout = .@"packed",
+        .tag_type = Tag,
+        .fields = &.{
+            .{ .name = "signed", .type = i32, .alignment = @alignOf(i32) },
+            .{ .name = "unsigned", .type = u32, .alignment = @alignOf(u32) },
+        },
+        .decls = &.{},
+    },
+});
+
+export fn entry() void {
+    const tagged: Packed = .{ .signed = -1 };
+    _ = tagged;
+}
+
+// error
+// backend=stage2
+// target=native
+//
+// :13:16: error: packed union does not support enum tag type