sema: Prevent reifying non-empty union with empty tag type
This commit is contained in:
committed by
Veikka Tuominen
parent
15f7a477d0
commit
501a2350ab
@@ -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", .{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user