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) {...@@ -1713,84 +1713,16 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1713 uint64_t biggest_align_in_bits = 0;1713 uint64_t biggest_align_in_bits = 0;
1714 uint64_t biggest_size_in_bits = 0;1714 uint64_t biggest_size_in_bits = 0;
17151715
1716 ZigLLVMDIEnumerator **di_enumerators;
1717
1718 Scope *scope = &union_type->data.unionation.decls_scope->base;1716 Scope *scope = &union_type->data.unionation.decls_scope->base;
1719 ImportTableEntry *import = get_scope_import(scope);1717 ImportTableEntry *import = get_scope_import(scope);
17201718
1721 // set temporary flag1719 // set temporary flag
1722 union_type->data.unionation.embedded_in_current = true;1720 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
1790 for (uint32_t i = 0; i < field_count; i += 1) {1723 for (uint32_t i = 0; i < field_count; i += 1) {
1791 AstNode *field_node = decl_node->data.container_decl.fields.at(i);1724 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
1792 TypeUnionField *union_field = &union_type->data.unionation.fields[i];1725 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
1793 Buf *field_name = field_node->data.struct_field.name;
1794 TypeTableEntry *field_type = union_field->type_entry;1726 TypeTableEntry *field_type = union_field->type_entry;
17951727
1796 ensure_complete_type(g, field_type);1728 ensure_complete_type(g, field_type);
...@@ -1799,57 +1731,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1799,57 +1731,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1799 continue;1731 continue;
1800 }1732 }
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
1853 if (!type_has_bits(field_type))1734 if (!type_has_bits(field_type))
1854 continue;1735 continue;
18551736
...@@ -1876,48 +1757,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1876,48 +1757,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1876 }1757 }
1877 }1758 }
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
1922 // unset temporary flag1761 // unset temporary flag
1923 union_type->data.unionation.embedded_in_current = false;1762 union_type->data.unionation.embedded_in_current = false;
...@@ -1948,11 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1948,11 +1787,12 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1948 return;1787 return;
1949 }1788 }
19501789
1951 assert(most_aligned_union_member != nullptr);
1952
1953 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;1790 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;
1955 if (tag_type == nullptr) {1793 if (tag_type == nullptr) {
1794 assert(most_aligned_union_member != nullptr);
1795
1956 if (padding_in_bits > 0) {1796 if (padding_in_bits > 0) {
1957 TypeTableEntry *u8_type = get_int_type(g, false, 8);1797 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1958 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);1798 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) {...@@ -1993,7 +1833,13 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1993 };1833 };
1994 union_type_ref = LLVMStructType(union_element_types, 2, false);1834 union_type_ref = LLVMStructType(union_element_types, 2, false);
1995 } else if (most_aligned_union_member == nullptr) {1835 } 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;
1997 } else {1843 } else {
1998 union_type_ref = most_aligned_union_member->type_ref;1844 union_type_ref = most_aligned_union_member->type_ref;
1999 }1845 }
...@@ -2020,20 +1866,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -2020,20 +1866,6 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
2020 LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);1866 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
2037 // create debug type for union1869 // create debug type for union
2038 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,1870 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
2039 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",1871 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
...@@ -2053,6 +1885,10 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -2053,6 +1885,10 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
2053 biggest_align_in_bits,1885 biggest_align_in_bits,
2054 union_offset_in_bits,1886 union_offset_in_bits,
2055 0, union_di_type);1887 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
2056 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,1892 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
2057 ZigLLVMTypeToScope(union_type->di_type), "tag",1893 ZigLLVMTypeToScope(union_type->di_type), "tag",
2058 import->di_file, (unsigned)(decl_node->line + 1),1894 import->di_file, (unsigned)(decl_node->line + 1),
...@@ -2312,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2312,8 +2148,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2312 if (union_type->data.unionation.zero_bits_known)2148 if (union_type->data.unionation.zero_bits_known)
2313 return;2149 return;
23142150
2151 if (type_is_invalid(union_type))
2152 return;
2153
2315 if (union_type->data.unionation.zero_bits_loop_flag) {2154 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.
2316 union_type->data.unionation.zero_bits_known = true;2159 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 }
2317 return;2168 return;
2318 }2169 }
23192170
...@@ -2342,19 +2193,99 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2342,19 +2193,99 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
23422193
2343 Scope *scope = &union_type->data.unionation.decls_scope->base;2194 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
2345 uint32_t gen_field_index = 0;2265 uint32_t gen_field_index = 0;
2346 for (uint32_t i = 0; i < field_count; i += 1) {2266 for (uint32_t i = 0; i < field_count; i += 1) {
2347 AstNode *field_node = decl_node->data.container_decl.fields.at(i);2267 AstNode *field_node = decl_node->data.container_decl.fields.at(i);
2268 Buf *field_name = field_node->data.struct_field.name;
2348 TypeUnionField *union_field = &union_type->data.unionation.fields[i];2269 TypeUnionField *union_field = &union_type->data.unionation.fields[i];
2349 union_field->name = field_node->data.struct_field.name;2270 union_field->name = field_node->data.struct_field.name;
23502271
2272 TypeTableEntry *field_type;
2351 if (field_node->data.struct_field.type == nullptr) {2273 if (field_node->data.struct_field.type == nullptr) {
2352 add_node_error(g, field_node, buf_sprintf("union field missing type"));2274 if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) {
2353 union_type->data.unionation.is_invalid = true;2275 field_type = g->builtin_types.entry_void;
2354 continue;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 }
2355 }2288 }
2356
2357 TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
2358 union_field->type_entry = field_type;2289 union_field->type_entry = field_type;
23592290
2360 if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {2291 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) {...@@ -2364,11 +2295,57 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2364 buf_sprintf("consider 'union(enum)' here"));2295 buf_sprintf("consider 'union(enum)' here"));
2365 }2296 }
23662297
2367 type_ensure_zero_bits_known(g, field_type);2298 if (create_enum_type) {
2368 if (type_is_invalid(field_type)) {2299 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
2369 union_type->data.unionation.is_invalid = true;2300 union_field->enum_field = &tag_type->data.enumeration.fields[i];
2370 continue;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);
2371 }2347 }
2348 assert(union_field->enum_field != nullptr);
23722349
2373 if (!type_has_bits(field_type))2350 if (!type_has_bits(field_type))
2374 continue;2351 continue;
...@@ -2379,9 +2356,15 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {...@@ -2379,9 +2356,15 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2379 uint32_t field_align_bytes = get_abi_alignment(g, field_type);2356 uint32_t field_align_bytes = get_abi_alignment(g, field_type);
2380 if (field_align_bytes > biggest_align_bytes) {2357 if (field_align_bytes > biggest_align_bytes) {
2381 biggest_align_bytes = field_align_bytes;2358 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 }
2382 }2362 }
2383 }2363 }
23842364
2365 if (union_type->data.unionation.is_invalid)
2366 return;
2367
2385 bool src_have_tag = decl_node->data.container_decl.auto_enum ||2368 bool src_have_tag = decl_node->data.container_decl.auto_enum ||
2386 decl_node->data.container_decl.init_arg_expr != nullptr;2369 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) {...@@ -2405,15 +2388,66 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
2405 return;2388 return;
2406 }2389 }
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
2408 union_type->data.unionation.zero_bits_loop_flag = false;2447 union_type->data.unionation.zero_bits_loop_flag = false;
2409 union_type->data.unionation.gen_field_count = gen_field_index;2448 union_type->data.unionation.gen_field_count = gen_field_index;
2410 union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));2449 union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
2411 union_type->data.unionation.zero_bits_known = true;2450 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 }
2417}2451}
24182452
2419static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {2453static 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,...@@ -12970,10 +12970,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
12970 ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);12970 ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
12971 return target_type;12971 return target_type;
12972 case TypeTableEntryIdUnion: {12972 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 {
12974 ErrorMsg *msg = ir_add_error(ira, target_value_ptr,12977 ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
12975 buf_sprintf("switch on union which has no attached enum"));12978 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,
12977 buf_sprintf("union declared here"));12980 buf_sprintf("union declared here"));
12978 return ira->codegen->builtin_types.entry_invalid;12981 return ira->codegen->builtin_types.entry_invalid;
12979 }12982 }
test/cases/union.zig+13
...@@ -105,6 +105,18 @@ fn bar(value: &const Payload) -> i32 {...@@ -105,6 +105,18 @@ fn bar(value: &const Payload) -> i32 {
105 };105 };
106}106}
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
108const MultipleChoice2 = union(enum(u32)) {120const MultipleChoice2 = union(enum(u32)) {
109 Unspecified1: i32,121 Unspecified1: i32,
110 A: f32 = 20,122 A: f32 = 20,
...@@ -137,3 +149,4 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {...@@ -137,3 +149,4 @@ fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: &const MultipleChoice2) {
137 MultipleChoice2.Unspecified5 => 9,149 MultipleChoice2.Unspecified5 => 9,
138 });150 });
139}151}
152
test/compile_errors.zig+47
...@@ -2524,4 +2524,51 @@ pub fn addCases(cases: &tests.CompileErrorContext) {...@@ -2524,4 +2524,51 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2524 ,2524 ,
2525 ".tmp_source.zig:6:17: error: enum field missing: 'C'",2525 ".tmp_source.zig:6:17: error: enum field missing: 'C'",
2526 ".tmp_source.zig:4:5: note: declared here");2526 ".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
2527}2574}