Commit fce435db26
Changed files (4)
test
src/analyze.cpp
@@ -1713,84 +1713,16 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
uint64_t biggest_align_in_bits = 0;
uint64_t biggest_size_in_bits = 0;
- ZigLLVMDIEnumerator **di_enumerators;
-
Scope *scope = &union_type->data.unionation.decls_scope->base;
ImportTableEntry *import = get_scope_import(scope);
// set temporary flag
union_type->data.unionation.embedded_in_current = true;
- HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
-
- AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
- bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
- bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
- TypeTableEntry *tag_type;
- bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
- bool *covered_enum_fields;
- if (create_enum_type) {
- occupied_tag_values.init(field_count);
-
- di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
-
- TypeTableEntry *tag_int_type;
- if (enum_type_node != nullptr) {
- tag_int_type = analyze_type_expr(g, scope, enum_type_node);
- if (type_is_invalid(tag_int_type)) {
- union_type->data.unionation.is_invalid = true;
- return;
- }
- if (tag_int_type->id != TypeTableEntryIdInt) {
- add_node_error(g, enum_type_node,
- buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
- union_type->data.unionation.is_invalid = true;
- return;
- }
- } else {
- tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
- }
-
- tag_type = new_type_table_entry(TypeTableEntryIdEnum);
- buf_resize(&tag_type->name, 0);
- buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
- tag_type->is_copyable = true;
- tag_type->type_ref = tag_int_type->type_ref;
- tag_type->zero_bits = tag_int_type->zero_bits;
-
- tag_type->data.enumeration.tag_int_type = tag_int_type;
- tag_type->data.enumeration.zero_bits_known = true;
- tag_type->data.enumeration.decl_node = decl_node;
- tag_type->data.enumeration.layout = ContainerLayoutAuto;
- tag_type->data.enumeration.src_field_count = field_count;
- tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
- tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
- tag_type->data.enumeration.complete = true;
- } else if (enum_type_node != nullptr) {
- TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
- if (type_is_invalid(enum_type)) {
- union_type->data.unionation.is_invalid = true;
- union_type->data.unionation.embedded_in_current = false;
- return;
- }
- if (enum_type->id != TypeTableEntryIdEnum) {
- union_type->data.unionation.is_invalid = true;
- union_type->data.unionation.embedded_in_current = false;
- add_node_error(g, enum_type_node,
- buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
- return;
- }
- tag_type = enum_type;
- covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
- } else {
- tag_type = nullptr;
- }
- union_type->data.unionation.tag_type = tag_type;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
- Buf *field_name = field_node->data.struct_field.name;
TypeTableEntry *field_type = union_field->type_entry;
ensure_complete_type(g, field_type);
@@ -1799,57 +1731,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
continue;
}
- if (create_enum_type) {
- di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
- union_field->enum_field = &tag_type->data.enumeration.fields[i];
- union_field->enum_field->name = field_name;
- union_field->enum_field->decl_index = i;
-
- AstNode *tag_value = field_node->data.struct_field.value;
- // In this first pass we resolve explicit tag values.
- // In a second pass we will fill in the unspecified ones.
- if (tag_value != nullptr) {
- TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
- IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
- if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- assert(result_inst->value.special != ConstValSpecialRuntime);
- assert(result_inst->value.type->id == TypeTableEntryIdInt);
- auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
- if (entry == nullptr) {
- bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
- } else {
- Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
-
- ErrorMsg *msg = add_node_error(g, tag_value,
- buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
- add_error_note(g, msg, entry->value,
- buf_sprintf("other occurrence here"));
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- }
- } else if (enum_type_node != nullptr) {
- union_field->enum_field = find_enum_type_field(tag_type, field_name);
- if (union_field->enum_field == nullptr) {
- ErrorMsg *msg = add_node_error(g, field_node,
- buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
- add_error_note(g, msg, tag_type->data.enumeration.decl_node,
- buf_sprintf("enum declared here"));
- union_type->data.unionation.is_invalid = true;
- continue;
- }
- covered_enum_fields[union_field->enum_field->decl_index] = true;
- } else {
- union_field->enum_field = allocate<TypeEnumField>(1);
- union_field->enum_field->name = field_name;
- union_field->enum_field->decl_index = i;
- bigint_init_unsigned(&union_field->enum_field->value, i);
- }
-
if (!type_has_bits(field_type))
continue;
@@ -1876,48 +1757,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
}
}
- if (create_enum_type) {
- // Now iterate again and populate the unspecified tag values
- uint32_t next_maybe_unoccupied_index = 0;
-
- for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
- AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
- TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
- AstNode *tag_value = field_node->data.struct_field.value;
-
- if (tag_value == nullptr) {
- if (occupied_tag_values.size() == 0) {
- bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
- next_maybe_unoccupied_index += 1;
- } else {
- BigInt proposed_value;
- for (;;) {
- bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
- next_maybe_unoccupied_index += 1;
- auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
- if (entry != nullptr) {
- continue;
- }
- break;
- }
- bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
- }
- }
- }
- } 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]) {
- 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,
- buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
- add_error_note(g, msg, field_node,
- buf_sprintf("declared here"));
- union_type->data.unionation.is_invalid = true;
- }
- }
- }
// unset temporary flag
union_type->data.unionation.embedded_in_current = false;
@@ -1948,11 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
return;
}
- assert(most_aligned_union_member != nullptr);
-
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
+ TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
if (tag_type == nullptr) {
+ assert(most_aligned_union_member != nullptr);
+
if (padding_in_bits > 0) {
TypeTableEntry *u8_type = get_int_type(g, false, 8);
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
@@ -1993,7 +1833,13 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
};
union_type_ref = LLVMStructType(union_element_types, 2, false);
} else if (most_aligned_union_member == nullptr) {
- zig_panic("TODO zero bit payload");
+ union_type->data.unionation.gen_tag_index = SIZE_MAX;
+ union_type->data.unionation.gen_union_index = SIZE_MAX;
+ union_type->type_ref = tag_type->type_ref;
+
+ ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type);
+ union_type->di_type = tag_type->di_type;
+ return;
} else {
union_type_ref = most_aligned_union_member->type_ref;
}
@@ -2020,20 +1866,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
- // create debug type for root struct
-
- uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
- uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
- if (create_enum_type) {
- // create debug type for tag
- ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
- ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
- import->di_file, (unsigned)(decl_node->line + 1),
- tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
- tag_type->di_type, "");
- tag_type->di_type = tag_di_type;
- }
-
// create debug type for union
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
@@ -2053,6 +1885,10 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
biggest_align_in_bits,
union_offset_in_bits,
0, union_di_type);
+
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
+
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
ZigLLVMTypeToScope(union_type->di_type), "tag",
import->di_file, (unsigned)(decl_node->line + 1),
@@ -2312,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
if (union_type->data.unionation.zero_bits_known)
return;
+ if (type_is_invalid(union_type))
+ return;
+
if (union_type->data.unionation.zero_bits_loop_flag) {
+ // If we get here it's due to recursion. From this we conclude that the struct is
+ // not zero bits, and if abi_alignment == 0 we further conclude that the first field
+ // is a pointer to this very struct, or a function pointer with parameters that
+ // reference such a type.
union_type->data.unionation.zero_bits_known = true;
+ if (union_type->data.unionation.abi_alignment == 0) {
+ if (union_type->data.unionation.layout == ContainerLayoutPacked) {
+ union_type->data.unionation.abi_alignment = 1;
+ } else {
+ union_type->data.unionation.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
+ LLVMPointerType(LLVMInt8Type(), 0));
+ }
+ }
return;
}
@@ -2342,19 +2193,99 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
Scope *scope = &union_type->data.unionation.decls_scope->base;
+ HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
+
+ AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
+ bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
+ bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
+ TypeTableEntry *tag_type;
+ bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
+ bool *covered_enum_fields;
+ ZigLLVMDIEnumerator **di_enumerators;
+ if (create_enum_type) {
+ occupied_tag_values.init(field_count);
+
+ di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
+
+ TypeTableEntry *tag_int_type;
+ if (enum_type_node != nullptr) {
+ tag_int_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(tag_int_type)) {
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ if (tag_int_type->id != TypeTableEntryIdInt) {
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
+ union_type->data.unionation.is_invalid = true;
+ return;
+ }
+ } else {
+ tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
+ }
+ union_type->data.unionation.abi_alignment = get_abi_alignment(g, tag_int_type);
+
+ tag_type = new_type_table_entry(TypeTableEntryIdEnum);
+ buf_resize(&tag_type->name, 0);
+ buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
+ tag_type->is_copyable = true;
+ tag_type->type_ref = tag_int_type->type_ref;
+ tag_type->zero_bits = tag_int_type->zero_bits;
+
+ tag_type->data.enumeration.tag_int_type = tag_int_type;
+ tag_type->data.enumeration.zero_bits_known = true;
+ tag_type->data.enumeration.decl_node = decl_node;
+ tag_type->data.enumeration.layout = ContainerLayoutAuto;
+ tag_type->data.enumeration.src_field_count = field_count;
+ tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
+ tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
+ tag_type->data.enumeration.complete = true;
+ } else if (enum_type_node != nullptr) {
+ TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
+ if (type_is_invalid(enum_type)) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ return;
+ }
+ if (enum_type->id != TypeTableEntryIdEnum) {
+ union_type->data.unionation.is_invalid = true;
+ union_type->data.unionation.embedded_in_current = false;
+ add_node_error(g, enum_type_node,
+ buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
+ return;
+ }
+ tag_type = enum_type;
+ covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
+ union_type->data.unionation.abi_alignment = get_abi_alignment(g, enum_type);
+ } else {
+ tag_type = nullptr;
+ }
+ union_type->data.unionation.tag_type = tag_type;
+
uint32_t gen_field_index = 0;
for (uint32_t i = 0; i < field_count; i += 1) {
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
+ Buf *field_name = field_node->data.struct_field.name;
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
union_field->name = field_node->data.struct_field.name;
+ TypeTableEntry *field_type;
if (field_node->data.struct_field.type == nullptr) {
- add_node_error(g, field_node, buf_sprintf("union field missing type"));
- union_type->data.unionation.is_invalid = true;
- continue;
+ if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
+ field_type = g->builtin_types.entry_void;
+ } else {
+ add_node_error(g, field_node, buf_sprintf("union field missing type"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ } else {
+ field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
+ type_ensure_zero_bits_known(g, field_type);
+ if (type_is_invalid(field_type)) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
}
-
- TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
union_field->type_entry = field_type;
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
@@ -2364,11 +2295,57 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
buf_sprintf("consider 'union(enum)' here"));
}
- type_ensure_zero_bits_known(g, field_type);
- if (type_is_invalid(field_type)) {
- union_type->data.unionation.is_invalid = true;
- continue;
+ if (create_enum_type) {
+ di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
+ union_field->enum_field = &tag_type->data.enumeration.fields[i];
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+
+ AstNode *tag_value = field_node->data.struct_field.value;
+ // In this first pass we resolve explicit tag values.
+ // In a second pass we will fill in the unspecified ones.
+ if (tag_value != nullptr) {
+ TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
+ IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
+ if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ assert(result_inst->value.special != ConstValSpecialRuntime);
+ assert(result_inst->value.type->id == TypeTableEntryIdInt);
+ auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
+ if (entry == nullptr) {
+ bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
+ } else {
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
+
+ ErrorMsg *msg = add_node_error(g, tag_value,
+ buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
+ add_error_note(g, msg, entry->value,
+ buf_sprintf("other occurrence here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ }
+ } else if (enum_type_node != nullptr) {
+ union_field->enum_field = find_enum_type_field(tag_type, field_name);
+ if (union_field->enum_field == nullptr) {
+ ErrorMsg *msg = add_node_error(g, field_node,
+ buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
+ add_error_note(g, msg, tag_type->data.enumeration.decl_node,
+ buf_sprintf("enum declared here"));
+ union_type->data.unionation.is_invalid = true;
+ continue;
+ }
+ covered_enum_fields[union_field->enum_field->decl_index] = true;
+ } else {
+ union_field->enum_field = allocate<TypeEnumField>(1);
+ union_field->enum_field->name = field_name;
+ union_field->enum_field->decl_index = i;
+ bigint_init_unsigned(&union_field->enum_field->value, i);
}
+ assert(union_field->enum_field != nullptr);
if (!type_has_bits(field_type))
continue;
@@ -2379,9 +2356,15 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
uint32_t field_align_bytes = get_abi_alignment(g, field_type);
if (field_align_bytes > biggest_align_bytes) {
biggest_align_bytes = field_align_bytes;
+ if (biggest_align_bytes > union_type->data.unionation.abi_alignment) {
+ union_type->data.unionation.abi_alignment = biggest_align_bytes;
+ }
}
}
+ if (union_type->data.unionation.is_invalid)
+ return;
+
bool src_have_tag = decl_node->data.container_decl.auto_enum ||
decl_node->data.container_decl.init_arg_expr != nullptr;
@@ -2405,15 +2388,66 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
return;
}
+ if (create_enum_type) {
+ // Now iterate again and populate the unspecified tag values
+ uint32_t next_maybe_unoccupied_index = 0;
+
+ for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
+ AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
+ TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
+ AstNode *tag_value = field_node->data.struct_field.value;
+
+ if (tag_value == nullptr) {
+ if (occupied_tag_values.size() == 0) {
+ bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ } else {
+ BigInt proposed_value;
+ for (;;) {
+ bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
+ next_maybe_unoccupied_index += 1;
+ auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
+ if (entry != nullptr) {
+ continue;
+ }
+ break;
+ }
+ bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
+ }
+ }
+ }
+ } 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]) {
+ 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,
+ buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
+ add_error_note(g, msg, field_node,
+ buf_sprintf("declared here"));
+ union_type->data.unionation.is_invalid = true;
+ }
+ }
+ }
+
+ if (create_enum_type) {
+ ImportTableEntry *import = get_scope_import(scope);
+ uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
+ uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
+ // TODO get a more accurate debug scope
+ ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
+ ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
+ import->di_file, (unsigned)(decl_node->line + 1),
+ tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
+ tag_type->di_type, "");
+ tag_type->di_type = tag_di_type;
+ }
+
union_type->data.unionation.zero_bits_loop_flag = false;
union_type->data.unionation.gen_field_count = gen_field_index;
union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
union_type->data.unionation.zero_bits_known = true;
-
- // also compute abi_alignment
- if (!union_type->zero_bits) {
- union_type->data.unionation.abi_alignment = biggest_align_bytes;
- }
}
static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
src/ir.cpp
@@ -12970,10 +12970,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
return target_type;
case TypeTableEntryIdUnion: {
- if (target_type->data.unionation.gen_tag_index == SIZE_MAX) {
+ AstNode *decl_node = target_type->data.unionation.decl_node;
+ if (!decl_node->data.container_decl.auto_enum &&
+ decl_node->data.container_decl.init_arg_expr == nullptr)
+ {
ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
buf_sprintf("switch on union which has no attached enum"));
- add_error_note(ira->codegen, msg, target_type->data.unionation.decl_node,
+ add_error_note(ira->codegen, msg, decl_node,
buf_sprintf("union declared here"));
return ira->codegen->builtin_types.entry_invalid;
}
test/cases/union.zig
@@ -105,6 +105,18 @@ fn bar(value: &const Payload) -> i32 {
};
}
+const MultipleChoice = union(enum(u32)) {
+ A = 20,
+ B = 40,
+ C = 60,
+ D = 1000,
+};
+test "simple union(enum(u32))" {
+ var x = MultipleChoice.C;
+ assert(x == MultipleChoice.C);
+ assert(u32(@TagType(MultipleChoice)(x)) == 60);
+}
+
const MultipleChoice2 = union(enum(u32)) {
Unspecified1: i32,
A: f32 = 20,
@@ -137,3 +149,4 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
MultipleChoice2.Unspecified5 => 9,
});
}
+
test/compile_errors.zig
@@ -2524,4 +2524,51 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
,
".tmp_source.zig:6:17: error: enum field missing: 'C'",
".tmp_source.zig:4:5: note: declared here");
+
+ cases.add("@TagType when union has no attached enum",
+ \\const Foo = union {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
+ ".tmp_source.zig:1:13: note: consider 'union(enum)' here");
+
+ cases.add("non-integer tag type to automatic union enum",
+ \\const Foo = union(enum(f32)) {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'");
+
+ cases.add("non-enum tag type passed to union",
+ \\const Foo = union(u32) {
+ \\ A: i32,
+ \\};
+ \\export fn entry() {
+ \\ const x = @TagType(Foo);
+ \\}
+ ,
+ ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'");
+
+ cases.add("union auto-enum value already taken",
+ \\const MultipleChoice = union(enum(u32)) {
+ \\ A = 20,
+ \\ B = 40,
+ \\ C = 60,
+ \\ D = 1000,
+ \\ E = 60,
+ \\};
+ \\export fn entry() {
+ \\ var x = MultipleChoice { .C = {} };
+ \\}
+ ,
+ ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
+ ".tmp_source.zig:4:9: note: other occurrence here");
+
}