diff --git a/src/Sema.zig b/src/Sema.zig index c6cb1a8b2f1a..2b020b405bac 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -20888,7 +20888,7 @@ fn zirReify( enum_field_names[i] = field_name; } - if (explicit_tags_seen.len > 0) { + if (enum_tag_ty != .none) { const tag_info = ip.indexToKey(enum_tag_ty).enum_type; const enum_index = tag_info.nameIndex(ip, field_name) orelse { const msg = msg: { @@ -20902,6 +20902,7 @@ fn zirReify( }; return sema.failWithOwnedErrorMsg(block, msg); }; + assert(explicit_tags_seen.len == tag_info.names.len); // No check for duplicate because the check already happened in order // to create the enum type in the first place. assert(!explicit_tags_seen[enum_index]); @@ -20967,13 +20968,14 @@ fn zirReify( } } - if (explicit_tags_seen.len > 0) { + if (enum_tag_ty != .none) { const tag_info = ip.indexToKey(enum_tag_ty).enum_type; if (tag_info.names.len > fields_len) { const msg = msg: { const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{}); errdefer msg.destroy(gpa); + assert(explicit_tags_seen.len == tag_info.names.len); for (tag_info.names.get(ip), 0..) |field_name, field_index| { if (explicit_tags_seen[field_index]) continue; try sema.addFieldErrNote(Type.fromInterned(enum_tag_ty), field_index, msg, "field '{}' missing, declared here", .{ diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 49ab54f48f99..f27823d2eb11 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -482,6 +482,39 @@ test "Type.Union from regular enum" { _ = @typeInfo(T).Union; } +test "Type.Union from empty regular enum" { + const E = enum {}; + const U = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = E, + .fields = &.{}, + .decls = &.{}, + }, + }); + try testing.expectEqual(@sizeOf(U), 0); +} + +test "Type.Union from empty Type.Enum" { + const E = @Type(.{ + .Enum = .{ + .tag_type = u0, + .fields = &.{}, + .decls = &.{}, + .is_exhaustive = true, + }, + }); + const U = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = E, + .fields = &.{}, + .decls = &.{}, + }, + }); + try testing.expectEqual(@sizeOf(U), 0); +} + test "Type.Fn" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig new file mode 100644 index 000000000000..17f7e9187097 --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_enum_fields.zig @@ -0,0 +1,30 @@ +const Tag = @Type(.{ + .Enum = .{ + .tag_type = u0, + .fields = &.{}, + .decls = &.{}, + .is_exhaustive = true, + }, +}); +const Tagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .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: Tagged = undefined; + _ = tagged; +} + +// error +// backend=stage2 +// target=native +// +// :9:16: error: no field named 'signed' in enum 'tmp.Tag' +// :1:13: note: enum declared here diff --git a/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig new file mode 100644 index 000000000000..3c29083418ad --- /dev/null +++ b/test/cases/compile_errors/reify_type_for_tagged_union_with_no_union_fields.zig @@ -0,0 +1,32 @@ +const Tag = @Type(.{ + .Enum = .{ + .tag_type = u1, + .fields = &.{ + .{ .name = "signed", .value = 0 }, + .{ .name = "unsigned", .value = 1 }, + }, + .decls = &.{}, + .is_exhaustive = true, + }, +}); +const Tagged = @Type(.{ + .Union = .{ + .layout = .Auto, + .tag_type = Tag, + .fields = &.{}, + .decls = &.{}, + }, +}); +export fn entry() void { + const tagged: Tagged = undefined; + _ = tagged; +} + +// error +// backend=stage2 +// target=native +// +// :12:16: error: enum field(s) missing in union +// :1:13: note: field 'signed' missing, declared here +// :1:13: note: field 'unsigned' missing, declared here +// :1:13: note: enum declared here