diff --git a/src/analyze.cpp b/src/analyze.cpp index 18dc7e032c..e064677a09 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2569,16 +2569,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { return ErrorSemanticAnalyzeFail; } - enum_type->data.enumeration.src_field_count = field_count; - enum_type->data.enumeration.fields = allocate(field_count); - enum_type->data.enumeration.fields_by_name.init(field_count); - enum_type->data.enumeration.non_exhaustive = false; - Scope *scope = &enum_type->data.enumeration.decls_scope->base; - HashMap occupied_tag_values = {}; - occupied_tag_values.init(field_count); - ZigType *tag_int_type; if (enum_type->data.enumeration.layout == ContainerLayoutExtern) { tag_int_type = get_c_int_type(g, CIntTypeInt); @@ -2620,6 +2612,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { } } + enum_type->data.enumeration.non_exhaustive = false; enum_type->data.enumeration.tag_int_type = tag_int_type; enum_type->size_in_bits = tag_int_type->size_in_bits; enum_type->abi_size = tag_int_type->abi_size; @@ -2628,6 +2621,31 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { BigInt bi_one; bigint_init_unsigned(&bi_one, 1); + AstNode *last_field_node = decl_node->data.container_decl.fields.at(field_count - 1); + if (buf_eql_str(last_field_node->data.struct_field.name, "_")) { + field_count -= 1; + if (field_count > 1 && log2_u64(field_count) == enum_type->size_in_bits) { + add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum specifies every value")); + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + } + if (decl_node->data.container_decl.init_arg_expr == nullptr) { + add_node_error(g, last_field_node, buf_sprintf("non-exhaustive enum must specify size")); + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + } + if (last_field_node->data.struct_field.value != nullptr) { + add_node_error(g, last_field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum")); + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; + } + enum_type->data.enumeration.non_exhaustive = true; + } + + enum_type->data.enumeration.src_field_count = field_count; + enum_type->data.enumeration.fields = allocate(field_count); + enum_type->data.enumeration.fields_by_name.init(field_count); + + HashMap occupied_tag_values = {}; + occupied_tag_values.init(field_count); + TypeEnumField *last_enum_field = nullptr; for (uint32_t field_i = 0; field_i < field_count; field_i += 1) { @@ -2649,27 +2667,9 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { buf_sprintf("consider 'union(enum)' here")); } - AstNode *tag_value = field_node->data.struct_field.value; - if (buf_eql_str(type_enum_field->name, "_")) { - if (decl_node->data.container_decl.init_arg_expr == nullptr) { - add_node_error(g, field_node, buf_sprintf("non-exhaustive enum must specify size")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - if (field_count > 1 && log2_u64(field_count - 1) == enum_type->size_in_bits) { - add_node_error(g, field_node, buf_sprintf("non-exhaustive enum specifies every value")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - if (field_i != field_count - 1) { - add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - if (tag_value != nullptr) { - add_node_error(g, field_node, buf_sprintf("value assigned to '_' field of non-exhaustive enum")); - enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; - } - enum_type->data.enumeration.non_exhaustive = true; - continue; + add_node_error(g, field_node, buf_sprintf("'_' field of non-exhaustive enum must be last")); + enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; } auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); @@ -2681,6 +2681,8 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { continue; } + AstNode *tag_value = field_node->data.struct_field.value; + if (tag_value != nullptr) { // A user-specified value is available ZigValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, @@ -3293,7 +3295,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { } else if (enum_type_node != nullptr) { for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) { TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i]; - if (!covered_enum_fields[i] && !buf_eql_str(enum_field->name, "_")) { + if (!covered_enum_fields[i]) { AstNode *enum_decl_node = tag_type->data.enumeration.decl_node; AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i); ErrorMsg *msg = add_node_error(g, decl_node, diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 702cc76524..be2a40d74d 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -13,9 +13,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _, \\ b, \\}; + \\const C = enum(u1) { + \\ a, + \\ b, + \\ _, + \\}; \\pub export fn entry() void { \\ _ = A; \\ _ = B; + \\ _ = C; \\} , &[_][]const u8{ "tmp.zig:4:5: error: non-exhaustive enum must specify size", diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 82e57a3a38..62b7d51c26 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -41,6 +41,7 @@ test "non-exhaustive enum" { .b => {}, else => {}, } + expect(@typeInfo(E).Enum.fields.len == 2); expect(@enumToInt(e) == 1); e = @intToEnum(E, 12); expect(@enumToInt(e) == 12);