authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-04 00:32:12-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-12-04 00:32:12-05:00
logfce435db269162774106ce7e6ddf70871d5eeb49
tree802b598efbacef024bada19b17aec4c40cf11be9
parent5a8367e8924e809b1390796eb656633ea5e34a86

fix abi alignment of union-enums not counting tag type

add more tests for unions See #618

4 files changed, 291 insertions(+), 194 deletions(-)

src/analyze.cpp+226-192
......@@ -1713,84 +1713,16 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
17131713 uint64_t biggest_align_in_bits = 0;
17141714 uint64_t biggest_size_in_bits = 0;
17151715
1716 ZigLLVMDIEnumerator **di_enumerators;
1717
17181716 Scope *scope = &union_type->data.unionation.decls_scope->base;
17191717 ImportTableEntry *import = get_scope_import(scope);
17201718
17211719 // set temporary flag
17221720 union_type->data.unionation.embedded_in_current = true;
17231721
1724 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
1725
1726 AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
1727 bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
1728 bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
1729 TypeTableEntry *tag_type;
1730 bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
1731 bool *covered_enum_fields;
1732 if (create_enum_type) {
1733 occupied_tag_values.init(field_count);
1734
1735 di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
1736
1737 TypeTableEntry *tag_int_type;
1738 if (enum_type_node != nullptr) {
1739 tag_int_type = analyze_type_expr(g, scope, enum_type_node);
1740 if (type_is_invalid(tag_int_type)) {
1741 union_type->data.unionation.is_invalid = true;
1742 return;
1743 }
1744 if (tag_int_type->id != TypeTableEntryIdInt) {
1745 add_node_error(g, enum_type_node,
1746 buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
1747 union_type->data.unionation.is_invalid = true;
1748 return;
1749 }
1750 } else {
1751 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
1752 }
1753
1754 tag_type = new_type_table_entry(TypeTableEntryIdEnum);
1755 buf_resize(&tag_type->name, 0);
1756 buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
1757 tag_type->is_copyable = true;
1758 tag_type->type_ref = tag_int_type->type_ref;
1759 tag_type->zero_bits = tag_int_type->zero_bits;
1760
1761 tag_type->data.enumeration.tag_int_type = tag_int_type;
1762 tag_type->data.enumeration.zero_bits_known = true;
1763 tag_type->data.enumeration.decl_node = decl_node;
1764 tag_type->data.enumeration.layout = ContainerLayoutAuto;
1765 tag_type->data.enumeration.src_field_count = field_count;
1766 tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
1767 tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
1768 tag_type->data.enumeration.complete = true;
1769 } else if (enum_type_node != nullptr) {
1770 TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
1771 if (type_is_invalid(enum_type)) {
1772 union_type->data.unionation.is_invalid = true;
1773 union_type->data.unionation.embedded_in_current = false;
1774 return;
1775 }
1776 if (enum_type->id != TypeTableEntryIdEnum) {
1777 union_type->data.unionation.is_invalid = true;
1778 union_type->data.unionation.embedded_in_current = false;
1779 add_node_error(g, enum_type_node,
1780 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
1781 return;
1782 }
1783 tag_type = enum_type;
1784 covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
1785 } else {
1786 tag_type = nullptr;
1787 }
1788 union_type->data.unionation.tag_type = tag_type;
17891722
17901723 for (uint32_t i = 0; i < field_count; i += 1) {
17911724 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
17921725 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
1793 Buf *field_name = field_node->data.struct_field.name;
17941726 TypeTableEntry *field_type = union_field->type_entry;
17951727
17961728 ensure_complete_type(g, field_type);
......@@ -1799,57 +1731,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
17991731 continue;
18001732 }
18011733
1802 if (create_enum_type) {
1803 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
1804 union_field->enum_field = &tag_type->data.enumeration.fields[i];
1805 union_field->enum_field->name = field_name;
1806 union_field->enum_field->decl_index = i;
1807
1808 AstNode *tag_value = field_node->data.struct_field.value;
1809 // In this first pass we resolve explicit tag values.
1810 // In a second pass we will fill in the unspecified ones.
1811 if (tag_value != nullptr) {
1812 TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
1813 IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
1814 if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
1815 union_type->data.unionation.is_invalid = true;
1816 continue;
1817 }
1818 assert(result_inst->value.special != ConstValSpecialRuntime);
1819 assert(result_inst->value.type->id == TypeTableEntryIdInt);
1820 auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
1821 if (entry == nullptr) {
1822 bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
1823 } else {
1824 Buf *val_buf = buf_alloc();
1825 bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
1826
1827 ErrorMsg *msg = add_node_error(g, tag_value,
1828 buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
1829 add_error_note(g, msg, entry->value,
1830 buf_sprintf("other occurrence here"));
1831 union_type->data.unionation.is_invalid = true;
1832 continue;
1833 }
1834 }
1835 } else if (enum_type_node != nullptr) {
1836 union_field->enum_field = find_enum_type_field(tag_type, field_name);
1837 if (union_field->enum_field == nullptr) {
1838 ErrorMsg *msg = add_node_error(g, field_node,
1839 buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
1840 add_error_note(g, msg, tag_type->data.enumeration.decl_node,
1841 buf_sprintf("enum declared here"));
1842 union_type->data.unionation.is_invalid = true;
1843 continue;
1844 }
1845 covered_enum_fields[union_field->enum_field->decl_index] = true;
1846 } else {
1847 union_field->enum_field = allocate<TypeEnumField>(1);
1848 union_field->enum_field->name = field_name;
1849 union_field->enum_field->decl_index = i;
1850 bigint_init_unsigned(&union_field->enum_field->value, i);
1851 }
1852
18531734 if (!type_has_bits(field_type))
18541735 continue;
18551736
......@@ -1876,48 +1757,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
18761757 }
18771758 }
18781759
1879 if (create_enum_type) {
1880 // Now iterate again and populate the unspecified tag values
1881 uint32_t next_maybe_unoccupied_index = 0;
1882
1883 for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
1884 AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
1885 TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
1886 AstNode *tag_value = field_node->data.struct_field.value;
1887
1888 if (tag_value == nullptr) {
1889 if (occupied_tag_values.size() == 0) {
1890 bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
1891 next_maybe_unoccupied_index += 1;
1892 } else {
1893 BigInt proposed_value;
1894 for (;;) {
1895 bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
1896 next_maybe_unoccupied_index += 1;
1897 auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
1898 if (entry != nullptr) {
1899 continue;
1900 }
1901 break;
1902 }
1903 bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
1904 }
1905 }
1906 }
1907 } else if (enum_type_node != nullptr) {
1908 for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
1909 TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
1910 if (!covered_enum_fields[i]) {
1911 AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
1912 AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
1913 ErrorMsg *msg = add_node_error(g, decl_node,
1914 buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
1915 add_error_note(g, msg, field_node,
1916 buf_sprintf("declared here"));
1917 union_type->data.unionation.is_invalid = true;
1918 }
1919 }
1920 }
19211760
19221761 // unset temporary flag
19231762 union_type->data.unionation.embedded_in_current = false;
......@@ -1948,11 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
19481787 return;
19491788 }
19501789
1951 assert(most_aligned_union_member != nullptr);
1952
19531790 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
19541791
1792 TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
19551793 if (tag_type == nullptr) {
1794 assert(most_aligned_union_member != nullptr);
1795
19561796 if (padding_in_bits > 0) {
19571797 TypeTableEntry *u8_type = get_int_type(g, false, 8);
19581798 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) {
19931833 };
19941834 union_type_ref = LLVMStructType(union_element_types, 2, false);
19951835 } else if (most_aligned_union_member == nullptr) {
1996 zig_panic("TODO zero bit payload");
1836 union_type->data.unionation.gen_tag_index = SIZE_MAX;
1837 union_type->data.unionation.gen_union_index = SIZE_MAX;
1838 union_type->type_ref = tag_type->type_ref;
1839
1840 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, tag_type->di_type);
1841 union_type->di_type = tag_type->di_type;
1842 return;
19971843 } else {
19981844 union_type_ref = most_aligned_union_member->type_ref;
19991845 }
......@@ -2020,20 +1866,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
20201866 LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
20211867
20221868
2023 // create debug type for root struct
2024
2025 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
2026 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
2027 if (create_enum_type) {
2028 // create debug type for tag
2029 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
2030 ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
2031 import->di_file, (unsigned)(decl_node->line + 1),
2032 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
2033 tag_type->di_type, "");
2034 tag_type->di_type = tag_di_type;
2035 }
2036
20371869 // create debug type for union
20381870 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
20391871 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
......@@ -2053,6 +1885,10 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
20531885 biggest_align_in_bits,
20541886 union_offset_in_bits,
20551887 0, union_di_type);
1888
1889 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
1890 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
1891
20561892 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
20571893 ZigLLVMTypeToScope(union_type->di_type), "tag",
20581894 import->di_file, (unsigned)(decl_node->line + 1),
......@@ -2312,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
23122148 if (union_type->data.unionation.zero_bits_known)
23132149 return;
23142150
2151 if (type_is_invalid(union_type))
2152 return;
2153
23152154 if (union_type->data.unionation.zero_bits_loop_flag) {
2155 // If we get here it's due to recursion. From this we conclude that the struct is
2156 // not zero bits, and if abi_alignment == 0 we further conclude that the first field
2157 // is a pointer to this very struct, or a function pointer with parameters that
2158 // reference such a type.
23162159 union_type->data.unionation.zero_bits_known = true;
2160 if (union_type->data.unionation.abi_alignment == 0) {
2161 if (union_type->data.unionation.layout == ContainerLayoutPacked) {
2162 union_type->data.unionation.abi_alignment = 1;
2163 } else {
2164 union_type->data.unionation.abi_alignment = LLVMABIAlignmentOfType(g->target_data_ref,
2165 LLVMPointerType(LLVMInt8Type(), 0));
2166 }
2167 }
23172168 return;
23182169 }
23192170
......@@ -2342,19 +2193,99 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
23422193
23432194 Scope *scope = &union_type->data.unionation.decls_scope->base;
23442195
2196 HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
2197
2198 AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
2199 bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
2200 bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
2201 TypeTableEntry *tag_type;
2202 bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
2203 bool *covered_enum_fields;
2204 ZigLLVMDIEnumerator **di_enumerators;
2205 if (create_enum_type) {
2206 occupied_tag_values.init(field_count);
2207
2208 di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
2209
2210 TypeTableEntry *tag_int_type;
2211 if (enum_type_node != nullptr) {
2212 tag_int_type = analyze_type_expr(g, scope, enum_type_node);
2213 if (type_is_invalid(tag_int_type)) {
2214 union_type->data.unionation.is_invalid = true;
2215 return;
2216 }
2217 if (tag_int_type->id != TypeTableEntryIdInt) {
2218 add_node_error(g, enum_type_node,
2219 buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
2220 union_type->data.unionation.is_invalid = true;
2221 return;
2222 }
2223 } else {
2224 tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
2225 }
2226 union_type->data.unionation.abi_alignment = get_abi_alignment(g, tag_int_type);
2227
2228 tag_type = new_type_table_entry(TypeTableEntryIdEnum);
2229 buf_resize(&tag_type->name, 0);
2230 buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
2231 tag_type->is_copyable = true;
2232 tag_type->type_ref = tag_int_type->type_ref;
2233 tag_type->zero_bits = tag_int_type->zero_bits;
2234
2235 tag_type->data.enumeration.tag_int_type = tag_int_type;
2236 tag_type->data.enumeration.zero_bits_known = true;
2237 tag_type->data.enumeration.decl_node = decl_node;
2238 tag_type->data.enumeration.layout = ContainerLayoutAuto;
2239 tag_type->data.enumeration.src_field_count = field_count;
2240 tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
2241 tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
2242 tag_type->data.enumeration.complete = true;
2243 } else if (enum_type_node != nullptr) {
2244 TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
2245 if (type_is_invalid(enum_type)) {
2246 union_type->data.unionation.is_invalid = true;
2247 union_type->data.unionation.embedded_in_current = false;
2248 return;
2249 }
2250 if (enum_type->id != TypeTableEntryIdEnum) {
2251 union_type->data.unionation.is_invalid = true;
2252 union_type->data.unionation.embedded_in_current = false;
2253 add_node_error(g, enum_type_node,
2254 buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
2255 return;
2256 }
2257 tag_type = enum_type;
2258 covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
2259 union_type->data.unionation.abi_alignment = get_abi_alignment(g, enum_type);
2260 } else {
2261 tag_type = nullptr;
2262 }
2263 union_type->data.unionation.tag_type = tag_type;
2264
23452265 uint32_t gen_field_index = 0;
23462266 for (uint32_t i = 0; i < field_count; i += 1) {
23472267 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
2268 Buf *field_name = field_node->data.struct_field.name;
23482269 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
23492270 union_field->name = field_node->data.struct_field.name;
23502271
2272 TypeTableEntry *field_type;
23512273 if (field_node->data.struct_field.type == nullptr) {
2352 add_node_error(g, field_node, buf_sprintf("union field missing type"));
2353 union_type->data.unionation.is_invalid = true;
2354 continue;
2274 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
2275 field_type = g->builtin_types.entry_void;
2276 } else {
2277 add_node_error(g, field_node, buf_sprintf("union field missing type"));
2278 union_type->data.unionation.is_invalid = true;
2279 continue;
2280 }
2281 } else {
2282 field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
2283 type_ensure_zero_bits_known(g, field_type);
2284 if (type_is_invalid(field_type)) {
2285 union_type->data.unionation.is_invalid = true;
2286 continue;
2287 }
23552288 }
2356
2357 TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
23582289 union_field->type_entry = field_type;
23592290
23602291 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) {
23642295 buf_sprintf("consider 'union(enum)' here"));
23652296 }
23662297
2367 type_ensure_zero_bits_known(g, field_type);
2368 if (type_is_invalid(field_type)) {
2369 union_type->data.unionation.is_invalid = true;
2370 continue;
2298 if (create_enum_type) {
2299 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
2300 union_field->enum_field = &tag_type->data.enumeration.fields[i];
2301 union_field->enum_field->name = field_name;
2302 union_field->enum_field->decl_index = i;
2303
2304 AstNode *tag_value = field_node->data.struct_field.value;
2305 // In this first pass we resolve explicit tag values.
2306 // In a second pass we will fill in the unspecified ones.
2307 if (tag_value != nullptr) {
2308 TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
2309 IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
2310 if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
2311 union_type->data.unionation.is_invalid = true;
2312 continue;
2313 }
2314 assert(result_inst->value.special != ConstValSpecialRuntime);
2315 assert(result_inst->value.type->id == TypeTableEntryIdInt);
2316 auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
2317 if (entry == nullptr) {
2318 bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
2319 } else {
2320 Buf *val_buf = buf_alloc();
2321 bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
2322
2323 ErrorMsg *msg = add_node_error(g, tag_value,
2324 buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
2325 add_error_note(g, msg, entry->value,
2326 buf_sprintf("other occurrence here"));
2327 union_type->data.unionation.is_invalid = true;
2328 continue;
2329 }
2330 }
2331 } else if (enum_type_node != nullptr) {
2332 union_field->enum_field = find_enum_type_field(tag_type, field_name);
2333 if (union_field->enum_field == nullptr) {
2334 ErrorMsg *msg = add_node_error(g, field_node,
2335 buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
2336 add_error_note(g, msg, tag_type->data.enumeration.decl_node,
2337 buf_sprintf("enum declared here"));
2338 union_type->data.unionation.is_invalid = true;
2339 continue;
2340 }
2341 covered_enum_fields[union_field->enum_field->decl_index] = true;
2342 } else {
2343 union_field->enum_field = allocate<TypeEnumField>(1);
2344 union_field->enum_field->name = field_name;
2345 union_field->enum_field->decl_index = i;
2346 bigint_init_unsigned(&union_field->enum_field->value, i);
23712347 }
2348 assert(union_field->enum_field != nullptr);
23722349
23732350 if (!type_has_bits(field_type))
23742351 continue;
......@@ -2379,9 +2356,15 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
23792356 uint32_t field_align_bytes = get_abi_alignment(g, field_type);
23802357 if (field_align_bytes > biggest_align_bytes) {
23812358 biggest_align_bytes = field_align_bytes;
2359 if (biggest_align_bytes > union_type->data.unionation.abi_alignment) {
2360 union_type->data.unionation.abi_alignment = biggest_align_bytes;
2361 }
23822362 }
23832363 }
23842364
2365 if (union_type->data.unionation.is_invalid)
2366 return;
2367
23852368 bool src_have_tag = decl_node->data.container_decl.auto_enum ||
23862369 decl_node->data.container_decl.init_arg_expr != nullptr;
23872370
......@@ -2405,15 +2388,66 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
24052388 return;
24062389 }
24072390
2391 if (create_enum_type) {
2392 // Now iterate again and populate the unspecified tag values
2393 uint32_t next_maybe_unoccupied_index = 0;
2394
2395 for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
2396 AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
2397 TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
2398 AstNode *tag_value = field_node->data.struct_field.value;
2399
2400 if (tag_value == nullptr) {
2401 if (occupied_tag_values.size() == 0) {
2402 bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
2403 next_maybe_unoccupied_index += 1;
2404 } else {
2405 BigInt proposed_value;
2406 for (;;) {
2407 bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
2408 next_maybe_unoccupied_index += 1;
2409 auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
2410 if (entry != nullptr) {
2411 continue;
2412 }
2413 break;
2414 }
2415 bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
2416 }
2417 }
2418 }
2419 } else if (enum_type_node != nullptr) {
2420 for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
2421 TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
2422 if (!covered_enum_fields[i]) {
2423 AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
2424 AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
2425 ErrorMsg *msg = add_node_error(g, decl_node,
2426 buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
2427 add_error_note(g, msg, field_node,
2428 buf_sprintf("declared here"));
2429 union_type->data.unionation.is_invalid = true;
2430 }
2431 }
2432 }
2433
2434 if (create_enum_type) {
2435 ImportTableEntry *import = get_scope_import(scope);
2436 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
2437 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
2438 // TODO get a more accurate debug scope
2439 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
2440 ZigLLVMFileToScope(import->di_file), buf_ptr(&tag_type->name),
2441 import->di_file, (unsigned)(decl_node->line + 1),
2442 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
2443 tag_type->di_type, "");
2444 tag_type->di_type = tag_di_type;
2445 }
2446
24082447 union_type->data.unionation.zero_bits_loop_flag = false;
24092448 union_type->data.unionation.gen_field_count = gen_field_index;
24102449 union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
24112450 union_type->data.unionation.zero_bits_known = true;
2412
2413 // also compute abi_alignment
2414 if (!union_type->zero_bits) {
2415 union_type->data.unionation.abi_alignment = biggest_align_bytes;
2416 }
24172451}
24182452
24192453static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {
src/ir.cpp+5-2
......@@ -12970,10 +12970,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
1297012970 ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
1297112971 return target_type;
1297212972 case TypeTableEntryIdUnion: {
12973 if (target_type->data.unionation.gen_tag_index == SIZE_MAX) {
12973 AstNode *decl_node = target_type->data.unionation.decl_node;
12974 if (!decl_node->data.container_decl.auto_enum &&
12975 decl_node->data.container_decl.init_arg_expr == nullptr)
12976 {
1297412977 ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
1297512978 buf_sprintf("switch on union which has no attached enum"));
12976 add_error_note(ira->codegen, msg, target_type->data.unionation.decl_node,
12979 add_error_note(ira->codegen, msg, decl_node,
1297712980 buf_sprintf("union declared here"));
1297812981 return ira->codegen->builtin_types.entry_invalid;
1297912982 }
test/cases/union.zig+13
......@@ -105,6 +105,18 @@ fn bar(value: &const Payload) -> i32 {
105105 };
106106}
107107
108const MultipleChoice = union(enum(u32)) {
109 A = 20,
110 B = 40,
111 C = 60,
112 D = 1000,
113};
114test "simple union(enum(u32))" {
115 var x = MultipleChoice.C;
116 assert(x == MultipleChoice.C);
117 assert(u32(@TagType(MultipleChoice)(x)) == 60);
118}
119
108120const MultipleChoice2 = union(enum(u32)) {
109121 Unspecified1: i32,
110122 A: f32 = 20,
......@@ -137,3 +149,4 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
137149 MultipleChoice2.Unspecified5 => 9,
138150 });
139151}
152
test/compile_errors.zig+47
......@@ -2524,4 +2524,51 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
25242524 ,
25252525 ".tmp_source.zig:6:17: error: enum field missing: 'C'",
25262526 ".tmp_source.zig:4:5: note: declared here");
2527
2528 cases.add("@TagType when union has no attached enum",
2529 \\const Foo = union {
2530 \\ A: i32,
2531 \\};
2532 \\export fn entry() {
2533 \\ const x = @TagType(Foo);
2534 \\}
2535 ,
2536 ".tmp_source.zig:5:24: error: union 'Foo' has no tag",
2537 ".tmp_source.zig:1:13: note: consider 'union(enum)' here");
2538
2539 cases.add("non-integer tag type to automatic union enum",
2540 \\const Foo = union(enum(f32)) {
2541 \\ A: i32,
2542 \\};
2543 \\export fn entry() {
2544 \\ const x = @TagType(Foo);
2545 \\}
2546 ,
2547 ".tmp_source.zig:1:23: error: expected integer tag type, found 'f32'");
2548
2549 cases.add("non-enum tag type passed to union",
2550 \\const Foo = union(u32) {
2551 \\ A: i32,
2552 \\};
2553 \\export fn entry() {
2554 \\ const x = @TagType(Foo);
2555 \\}
2556 ,
2557 ".tmp_source.zig:1:18: error: expected enum tag type, found 'u32'");
2558
2559 cases.add("union auto-enum value already taken",
2560 \\const MultipleChoice = union(enum(u32)) {
2561 \\ A = 20,
2562 \\ B = 40,
2563 \\ C = 60,
2564 \\ D = 1000,
2565 \\ E = 60,
2566 \\};
2567 \\export fn entry() {
2568 \\ var x = MultipleChoice { .C = {} };
2569 \\}
2570 ,
2571 ".tmp_source.zig:6:9: error: enum tag value 60 already taken",
2572 ".tmp_source.zig:4:9: note: other occurrence here");
2573
25272574}