diff --git a/src/analyze.cpp b/src/analyze.cpp index b70e756f47..6086ff2bf3 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2603,16 +2603,16 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { if (decl_node->type == NodeTypeContainerDecl) { assert(!enum_type->data.enumeration.fields); field_count = (uint32_t)decl_node->data.container_decl.fields.length; - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); - - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = nullptr; - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } else { - field_count = enum_type->data.enumeration.src_field_count; + field_count = enum_type->data.enumeration.src_field_count + enum_type->data.enumeration.non_exhaustive; + } + + if (field_count == 0) { + add_node_error(g, decl_node, buf_sprintf("enums must have 1 or more fields")); + enum_type->data.enumeration.src_field_count = field_count; + enum_type->data.enumeration.fields = nullptr; + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; } Scope *scope = &enum_type->data.enumeration.decls_scope->base; @@ -3072,18 +3072,19 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { if (decl_node->type == NodeTypeContainerDecl) { assert(union_type->data.unionation.fields == nullptr); field_count = (uint32_t)decl_node->data.container_decl.fields.length; - if (field_count == 0) { - add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); - union_type->data.unionation.src_field_count = field_count; - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } union_type->data.unionation.src_field_count = field_count; union_type->data.unionation.fields = heap::c_allocator.allocate(field_count); union_type->data.unionation.fields_by_name.init(field_count); } else { - assert(union_type->data.unionation.fields != nullptr); field_count = union_type->data.unionation.src_field_count; + assert(field_count == 0 || union_type->data.unionation.fields != nullptr); + } + + if (field_count == 0) { + add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields")); + union_type->data.unionation.src_field_count = field_count; + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; } Scope *scope = &union_type->data.unionation.decls_scope->base; @@ -3217,41 +3218,6 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } assert(field_type_val->special != ConstValSpecialRuntime); union_field->type_val = field_type_val; - if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) - return ErrorSemanticAnalyzeFail; - - bool field_is_opaque_type; - if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - if (field_is_opaque_type) { - add_node_error(g, field_node, - buf_create_from_str( - "opaque types have unknown size and therefore cannot be directly embedded in unions")); - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } - - switch (type_val_resolve_requires_comptime(g, field_type_val)) { - case ReqCompTimeInvalid: - if (g->trace_err != nullptr) { - g->trace_err = add_error_note(g, g->trace_err, field_node, - buf_create_from_str("while checking this field")); - } - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - case ReqCompTimeYes: - union_type->data.unionation.requires_comptime = true; - break; - case ReqCompTimeNo: - break; - } - - if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &is_zero_bits[i]))) { - union_type->data.unionation.resolve_status = ResolveStatusInvalid; - return ErrorSemanticAnalyzeFail; - } } if (field_node->data.struct_field.value != nullptr && !is_auto_enum) { @@ -3261,6 +3227,41 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } } + if (union_field->type_val != nullptr) { + bool field_is_opaque_type; + if ((err = type_val_resolve_is_opaque_type(g, union_field->type_val, &field_is_opaque_type))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + if (field_is_opaque_type) { + add_node_error(g, union_field->decl_node, + buf_create_from_str( + "opaque types have unknown size and therefore cannot be directly embedded in unions")); + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + + switch (type_val_resolve_requires_comptime(g, union_field->type_val)) { + case ReqCompTimeInvalid: + if (g->trace_err != nullptr) { + g->trace_err = add_error_note(g, g->trace_err, union_field->decl_node, + buf_create_from_str("while checking this field")); + } + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + case ReqCompTimeYes: + union_type->data.unionation.requires_comptime = true; + break; + case ReqCompTimeNo: + break; + } + + if ((err = type_val_resolve_zero_bits(g, union_field->type_val, union_type, nullptr, &is_zero_bits[i]))) { + union_type->data.unionation.resolve_status = ResolveStatusInvalid; + return ErrorSemanticAnalyzeFail; + } + } + if (create_enum_type) { di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(union_field->name), i); union_field->enum_field = &tag_type->data.enumeration.fields[i]; diff --git a/src/ir.cpp b/src/ir.cpp index 36852de706..6cb5d8bc2d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -26222,14 +26222,19 @@ static ZigType *type_info_to_type(IrAnalyze *ira, IrInst *source_instr, ZigTypeI assert(payload->type == ir_type_info_get_type(ira, "Union", nullptr)); ZigValue *layout_value = get_const_field(ira, source_instr->source_node, payload, "layout", 0); + if (layout_value == nullptr) + return ira->codegen->invalid_inst_gen->value->type; assert(layout_value->special == ConstValSpecialStatic); assert(layout_value->type == ir_type_info_get_type(ira, "ContainerLayout", nullptr)); ContainerLayout layout = (ContainerLayout)bigint_as_u32(&layout_value->data.x_enum_tag); ZigType *tag_type = get_const_field_meta_type_optional(ira, source_instr->source_node, payload, "tag_type", 1); + if (tag_type != nullptr && type_is_invalid(tag_type)) { + return ira->codegen->invalid_inst_gen->value->type; + } if (tag_type != nullptr && tag_type->id != ZigTypeIdEnum) { ir_add_error(ira, source_instr, buf_sprintf( - "union tag type must be an enum, not %s", type_id_name(tag_type->id))); + "expected enum type, found '%s'", type_id_name(tag_type->id))); return ira->codegen->invalid_inst_gen->value->type; } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 741c5fdb71..f457c74609 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -10,6 +10,63 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:2:37: error: expected type '[:1]const u8', found '*const [2:2]u8'", }); + cases.add("@Type for union with opaque field", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Untagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = null, + \\ .fields = &[_]TypeInfo.UnionField{ + \\ .{ .name = "foo", .field_type = @Type(.Opaque) }, + \\ }, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = Untagged{}; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: opaque types have unknown size and therefore cannot be directly embedded in unions", + "tmp.zig:13:17: note: referenced here", + }); + + cases.add("@Type for union with zero fields", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Untagged = @Type(.{ + \\ .Union = .{ + \\ .layout = .Auto, + \\ .tag_type = null, + \\ .fields = &[_]TypeInfo.UnionField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = Untagged{}; + \\} + , &[_][]const u8{ + "tmp.zig:2:25: error: unions must have 1 or more fields", + "tmp.zig:11:17: note: referenced here", + }); + + cases.add("@Type for exhaustive enum with zero fields", + \\const TypeInfo = @import("builtin").TypeInfo; + \\const Tag = @Type(.{ + \\ .Enum = .{ + \\ .layout = .Auto, + \\ .tag_type = u1, + \\ .fields = &[_]TypeInfo.EnumField{}, + \\ .decls = &[_]TypeInfo.Declaration{}, + \\ .is_exhaustive = true, + \\ }, + \\}); + \\export fn entry() void { + \\ _ = @intToEnum(Tag, 0); + \\} + , &[_][]const u8{ + "tmp.zig:2:20: error: enums must have 1 or more fields", + "tmp.zig:12:9: note: referenced here", + }); + cases.add("@Type for tagged union with extra union field", \\const TypeInfo = @import("builtin").TypeInfo; \\const Tag = @Type(.{