Commit f41b9cdb6d

Andrew Kelley <andrew@ziglang.org>
2021-12-27 05:36:12
Sema: fix enum tag type not initialized when 0 fields
1 parent 629a54c
Changed files (3)
src/Sema.zig
@@ -1759,6 +1759,11 @@ fn zirEnumDecl(
     const body = sema.code.extra[extra_index..][0..body_len];
     if (fields_len == 0) {
         assert(body.len == 0);
+        if (tag_type_ref != .none) {
+            // TODO better source location
+            const ty = try sema.resolveType(block, src, tag_type_ref);
+            enum_obj.tag_ty = try ty.copy(new_decl_arena_allocator);
+        }
         try new_decl.finalizeNewArena(&new_decl_arena);
         return sema.analyzeDeclVal(block, src, new_decl);
     }
@@ -1810,7 +1815,8 @@ fn zirEnumDecl(
         const tag_ty = blk: {
             if (tag_type_ref != .none) {
                 // TODO better source location
-                break :blk try sema.resolveType(block, src, tag_type_ref);
+                const ty = try sema.resolveType(block, src, tag_type_ref);
+                break :blk try ty.copy(new_decl_arena_allocator);
             }
             const bits = std.math.log2_int_ceil(usize, fields_len);
             break :blk try Type.Tag.int_unsigned.create(new_decl_arena_allocator, bits);
test/behavior/enum.zig
@@ -646,3 +646,56 @@ test "non-exhaustive enum" {
     try S.doTheTest(52);
     comptime try S.doTheTest(52);
 }
+
+test "empty non-exhaustive enum" {
+    const S = struct {
+        const E = enum(u8) { _ };
+
+        fn doTheTest(y: u8) !void {
+            var e = @intToEnum(E, y);
+            try expect(switch (e) {
+                _ => true,
+            });
+            try expect(@enumToInt(e) == y);
+
+            try expect(@typeInfo(E).Enum.fields.len == 0);
+            try expect(@typeInfo(E).Enum.is_exhaustive == false);
+        }
+    };
+    try S.doTheTest(42);
+    comptime try S.doTheTest(42);
+}
+
+test "single field non-exhaustive enum" {
+    const S = struct {
+        const E = enum(u8) { a, _ };
+        fn doTheTest(y: u8) !void {
+            var e: E = .a;
+            try expect(switch (e) {
+                .a => true,
+                _ => false,
+            });
+            e = @intToEnum(E, 12);
+            try expect(switch (e) {
+                .a => false,
+                _ => true,
+            });
+
+            try expect(switch (e) {
+                .a => false,
+                else => true,
+            });
+            e = .a;
+            try expect(switch (e) {
+                .a => true,
+                else => false,
+            });
+
+            try expect(@enumToInt(@intToEnum(E, y)) == y);
+            try expect(@typeInfo(E).Enum.fields.len == 1);
+            try expect(@typeInfo(E).Enum.is_exhaustive == false);
+        }
+    };
+    try S.doTheTest(23);
+    comptime try S.doTheTest(23);
+}
test/behavior/enum_stage1.zig
@@ -2,64 +2,6 @@ const expect = @import("std").testing.expect;
 const mem = @import("std").mem;
 const Tag = @import("std").meta.Tag;
 
-test "empty non-exhaustive enum" {
-    const S = struct {
-        const E = enum(u8) {
-            _,
-        };
-        fn doTheTest(y: u8) !void {
-            var e = @intToEnum(E, y);
-            try expect(switch (e) {
-                _ => true,
-            });
-            try expect(@enumToInt(e) == y);
-
-            try expect(@typeInfo(E).Enum.fields.len == 0);
-            try expect(@typeInfo(E).Enum.is_exhaustive == false);
-        }
-    };
-    try S.doTheTest(42);
-    comptime try S.doTheTest(42);
-}
-
-test "single field non-exhaustive enum" {
-    const S = struct {
-        const E = enum(u8) { a, _ };
-        fn doTheTest(y: u8) !void {
-            var e: E = .a;
-            try expect(switch (e) {
-                .a => true,
-                _ => false,
-            });
-            e = @intToEnum(E, 12);
-            try expect(switch (e) {
-                .a => false,
-                _ => true,
-            });
-
-            try expect(switch (e) {
-                .a => false,
-                else => true,
-            });
-            e = .a;
-            try expect(switch (e) {
-                .a => true,
-                else => false,
-            });
-
-            try expect(@enumToInt(@intToEnum(E, y)) == y);
-            try expect(@typeInfo(E).Enum.fields.len == 1);
-            try expect(@typeInfo(E).Enum.is_exhaustive == false);
-        }
-    };
-    try S.doTheTest(23);
-    comptime try S.doTheTest(23);
-}
-
-const Bar = enum { A, B, C, D };
-
-const Number = enum { Zero, One, Two, Three, Four };
-
 test "@tagName" {
     try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
     comptime try expect(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
@@ -304,6 +246,8 @@ test "enum with one member and custom tag type" {
     try expect(@enumToInt(E2.One) == 2);
 }
 
+const Bar = enum { A, B, C, D };
+
 test "enum literal casting to optional" {
     var bar: ?Bar = undefined;
     bar = .B;