| author | |
| committer | |
| log | f276fd0f3728bf1a43b185e3e2d33d593309cb2f |
| tree | 39d52f6a39df87005065ddba1531e40f968cee86 |
| parent | 7a74dbadd79d2b26a449027dd83753ae4d2a8032 |
See #14410 files changed, 559 insertions(+), 26 deletions(-)
src/all_types.hpp+41-2| ... | ... | @@ -73,6 +73,7 @@ enum ConstParentId { |
| 73 | 73 | ConstParentIdNone, |
| 74 | 74 | ConstParentIdStruct, |
| 75 | 75 | ConstParentIdArray, |
| 76 | ConstParentIdUnion, | |
| 76 | 77 | }; |
| 77 | 78 | |
| 78 | 79 | struct ConstParent { |
| ... | ... | @@ -87,6 +88,9 @@ struct ConstParent { |
| 87 | 88 | ConstExprValue *struct_val; |
| 88 | 89 | size_t field_index; |
| 89 | 90 | } p_struct; |
| 91 | struct { | |
| 92 | ConstExprValue *union_val; | |
| 93 | } p_union; | |
| 90 | 94 | } data; |
| 91 | 95 | }; |
| 92 | 96 | |
| ... | ... | @@ -100,6 +104,11 @@ struct ConstStructValue { |
| 100 | 104 | ConstParent parent; |
| 101 | 105 | }; |
| 102 | 106 | |
| 107 | struct ConstUnionValue { | |
| 108 | ConstExprValue *value; | |
| 109 | ConstParent parent; | |
| 110 | }; | |
| 111 | ||
| 103 | 112 | enum ConstArraySpecial { |
| 104 | 113 | ConstArraySpecialNone, |
| 105 | 114 | ConstArraySpecialUndef, |
| ... | ... | @@ -238,6 +247,7 @@ struct ConstExprValue { |
| 238 | 247 | ErrorTableEntry *x_pure_err; |
| 239 | 248 | ConstEnumValue x_enum; |
| 240 | 249 | ConstStructValue x_struct; |
| 250 | ConstUnionValue x_union; | |
| 241 | 251 | ConstArrayValue x_array; |
| 242 | 252 | ConstPtrValue x_ptr; |
| 243 | 253 | ImportTableEntry *x_import; |
| ... | ... | @@ -336,6 +346,12 @@ struct TypeEnumField { |
| 336 | 346 | uint32_t gen_index; |
| 337 | 347 | }; |
| 338 | 348 | |
| 349 | struct TypeUnionField { | |
| 350 | Buf *name; | |
| 351 | TypeTableEntry *type_entry; | |
| 352 | uint32_t gen_index; | |
| 353 | }; | |
| 354 | ||
| 339 | 355 | enum NodeType { |
| 340 | 356 | NodeTypeRoot, |
| 341 | 357 | NodeTypeFnProto, |
| ... | ... | @@ -1026,9 +1042,9 @@ struct TypeTableEntryUnion { |
| 1026 | 1042 | ContainerLayout layout; |
| 1027 | 1043 | uint32_t src_field_count; |
| 1028 | 1044 | uint32_t gen_field_count; |
| 1029 | TypeStructField *fields; | |
| 1030 | uint64_t size_bytes; | |
| 1045 | TypeUnionField *fields; | |
| 1031 | 1046 | bool is_invalid; // true if any fields are invalid |
| 1047 | ||
| 1032 | 1048 | ScopeDecls *decls_scope; |
| 1033 | 1049 | |
| 1034 | 1050 | // set this flag temporarily to detect infinite loops |
| ... | ... | @@ -1039,6 +1055,10 @@ struct TypeTableEntryUnion { |
| 1039 | 1055 | |
| 1040 | 1056 | bool zero_bits_loop_flag; |
| 1041 | 1057 | bool zero_bits_known; |
| 1058 | uint32_t abi_alignment; // also figured out with zero_bits pass | |
| 1059 | ||
| 1060 | uint32_t size_bytes; | |
| 1061 | TypeTableEntry *most_aligned_union_member; | |
| 1042 | 1062 | }; |
| 1043 | 1063 | |
| 1044 | 1064 | struct FnGenParamInfo { |
| ... | ... | @@ -1796,6 +1816,7 @@ enum IrInstructionId { |
| 1796 | 1816 | IrInstructionIdFieldPtr, |
| 1797 | 1817 | IrInstructionIdStructFieldPtr, |
| 1798 | 1818 | IrInstructionIdEnumFieldPtr, |
| 1819 | IrInstructionIdUnionFieldPtr, | |
| 1799 | 1820 | IrInstructionIdElemPtr, |
| 1800 | 1821 | IrInstructionIdVarPtr, |
| 1801 | 1822 | IrInstructionIdCall, |
| ... | ... | @@ -1805,6 +1826,7 @@ enum IrInstructionId { |
| 1805 | 1826 | IrInstructionIdContainerInitList, |
| 1806 | 1827 | IrInstructionIdContainerInitFields, |
| 1807 | 1828 | IrInstructionIdStructInit, |
| 1829 | IrInstructionIdUnionInit, | |
| 1808 | 1830 | IrInstructionIdUnreachable, |
| 1809 | 1831 | IrInstructionIdTypeOf, |
| 1810 | 1832 | IrInstructionIdToPtrType, |
| ... | ... | @@ -2060,6 +2082,14 @@ struct IrInstructionEnumFieldPtr { |
| 2060 | 2082 | bool is_const; |
| 2061 | 2083 | }; |
| 2062 | 2084 | |
| 2085 | struct IrInstructionUnionFieldPtr { | |
| 2086 | IrInstruction base; | |
| 2087 | ||
| 2088 | IrInstruction *union_ptr; | |
| 2089 | TypeUnionField *field; | |
| 2090 | bool is_const; | |
| 2091 | }; | |
| 2092 | ||
| 2063 | 2093 | struct IrInstructionElemPtr { |
| 2064 | 2094 | IrInstruction base; |
| 2065 | 2095 | |
| ... | ... | @@ -2150,6 +2180,15 @@ struct IrInstructionStructInit { |
| 2150 | 2180 | LLVMValueRef tmp_ptr; |
| 2151 | 2181 | }; |
| 2152 | 2182 | |
| 2183 | struct IrInstructionUnionInit { | |
| 2184 | IrInstruction base; | |
| 2185 | ||
| 2186 | TypeTableEntry *union_type; | |
| 2187 | TypeUnionField *field; | |
| 2188 | IrInstruction *init_value; | |
| 2189 | LLVMValueRef tmp_ptr; | |
| 2190 | }; | |
| 2191 | ||
| 2153 | 2192 | struct IrInstructionUnreachable { |
| 2154 | 2193 | IrInstruction base; |
| 2155 | 2194 | }; |
src/analyze.cpp+217-6| ... | ... | @@ -992,18 +992,22 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 992 | 992 | TypeTableEntryId type_id = container_to_type(kind); |
| 993 | 993 | TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); |
| 994 | 994 | |
| 995 | unsigned dwarf_kind; | |
| 995 | 996 | switch (kind) { |
| 996 | 997 | case ContainerKindStruct: |
| 997 | 998 | entry->data.structure.decl_node = decl_node; |
| 998 | 999 | entry->data.structure.layout = layout; |
| 1000 | dwarf_kind = ZigLLVMTag_DW_structure_type(); | |
| 999 | 1001 | break; |
| 1000 | 1002 | case ContainerKindEnum: |
| 1001 | 1003 | entry->data.enumeration.decl_node = decl_node; |
| 1002 | 1004 | entry->data.enumeration.layout = layout; |
| 1005 | dwarf_kind = ZigLLVMTag_DW_structure_type(); | |
| 1003 | 1006 | break; |
| 1004 | 1007 | case ContainerKindUnion: |
| 1005 | 1008 | entry->data.unionation.decl_node = decl_node; |
| 1006 | 1009 | entry->data.unionation.layout = layout; |
| 1010 | dwarf_kind = ZigLLVMTag_DW_union_type(); | |
| 1007 | 1011 | break; |
| 1008 | 1012 | } |
| 1009 | 1013 | |
| ... | ... | @@ -1012,7 +1016,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 1012 | 1016 | ImportTableEntry *import = get_scope_import(scope); |
| 1013 | 1017 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); |
| 1014 | 1018 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, |
| 1015 | ZigLLVMTag_DW_structure_type(), name, | |
| 1019 | dwarf_kind, name, | |
| 1016 | 1020 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); |
| 1017 | 1021 | |
| 1018 | 1022 | buf_init_from_str(&entry->name, name); |
| ... | ... | @@ -1285,7 +1289,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1285 | 1289 | return; |
| 1286 | 1290 | |
| 1287 | 1291 | resolve_enum_zero_bits(g, enum_type); |
| 1288 | if (enum_type->data.enumeration.is_invalid) | |
| 1292 | if (type_is_invalid(enum_type)) | |
| 1289 | 1293 | return; |
| 1290 | 1294 | |
| 1291 | 1295 | AstNode *decl_node = enum_type->data.enumeration.decl_node; |
| ... | ... | @@ -1834,7 +1838,140 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1834 | 1838 | } |
| 1835 | 1839 | |
| 1836 | 1840 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1837 | zig_panic("TODO"); | |
| 1841 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 1842 | ||
| 1843 | if (union_type->data.unionation.complete) | |
| 1844 | return; | |
| 1845 | ||
| 1846 | resolve_union_zero_bits(g, union_type); | |
| 1847 | if (type_is_invalid(union_type)) | |
| 1848 | return; | |
| 1849 | ||
| 1850 | AstNode *decl_node = union_type->data.unionation.decl_node; | |
| 1851 | ||
| 1852 | if (union_type->data.unionation.embedded_in_current) { | |
| 1853 | if (!union_type->data.unionation.reported_infinite_err) { | |
| 1854 | union_type->data.unionation.reported_infinite_err = true; | |
| 1855 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | |
| 1856 | } | |
| 1857 | return; | |
| 1858 | } | |
| 1859 | ||
| 1860 | assert(!union_type->data.unionation.zero_bits_loop_flag); | |
| 1861 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 1862 | assert(union_type->di_type); | |
| 1863 | ||
| 1864 | uint32_t field_count = union_type->data.unionation.src_field_count; | |
| 1865 | ||
| 1866 | assert(union_type->data.unionation.fields); | |
| 1867 | ||
| 1868 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; | |
| 1869 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); | |
| 1870 | ||
| 1871 | TypeTableEntry *most_aligned_union_member = nullptr; | |
| 1872 | uint64_t size_of_most_aligned_member_in_bits = 0; | |
| 1873 | uint64_t biggest_align_in_bits = 0; | |
| 1874 | uint64_t biggest_size_in_bits = 0; | |
| 1875 | ||
| 1876 | Scope *scope = &union_type->data.unionation.decls_scope->base; | |
| 1877 | ImportTableEntry *import = get_scope_import(scope); | |
| 1878 | ||
| 1879 | // set temporary flag | |
| 1880 | union_type->data.unionation.embedded_in_current = true; | |
| 1881 | ||
| 1882 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 1883 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 1884 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 1885 | TypeTableEntry *field_type = type_union_field->type_entry; | |
| 1886 | ||
| 1887 | ensure_complete_type(g, field_type); | |
| 1888 | if (type_is_invalid(field_type)) { | |
| 1889 | union_type->data.unionation.is_invalid = true; | |
| 1890 | continue; | |
| 1891 | } | |
| 1892 | ||
| 1893 | if (!type_has_bits(field_type)) | |
| 1894 | continue; | |
| 1895 | ||
| 1896 | uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | |
| 1897 | uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); | |
| 1898 | ||
| 1899 | assert(store_size_in_bits > 0); | |
| 1900 | assert(abi_align_in_bits > 0); | |
| 1901 | ||
| 1902 | union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | |
| 1903 | ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name), | |
| 1904 | import->di_file, (unsigned)(field_node->line + 1), | |
| 1905 | store_size_in_bits, | |
| 1906 | abi_align_in_bits, | |
| 1907 | 0, | |
| 1908 | 0, field_type->di_type); | |
| 1909 | ||
| 1910 | biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits); | |
| 1911 | ||
| 1912 | if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) { | |
| 1913 | most_aligned_union_member = field_type; | |
| 1914 | biggest_align_in_bits = abi_align_in_bits; | |
| 1915 | size_of_most_aligned_member_in_bits = store_size_in_bits; | |
| 1916 | } | |
| 1917 | } | |
| 1918 | ||
| 1919 | // unset temporary flag | |
| 1920 | union_type->data.unionation.embedded_in_current = false; | |
| 1921 | union_type->data.unionation.complete = true; | |
| 1922 | union_type->data.unionation.size_bytes = biggest_size_in_bits / 8; | |
| 1923 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; | |
| 1924 | ||
| 1925 | if (union_type->data.unionation.is_invalid) | |
| 1926 | return; | |
| 1927 | ||
| 1928 | if (union_type->zero_bits) { | |
| 1929 | union_type->type_ref = LLVMVoidType(); | |
| 1930 | ||
| 1931 | uint64_t debug_size_in_bits = 0; | |
| 1932 | uint64_t debug_align_in_bits = 0; | |
| 1933 | ZigLLVMDIType **di_root_members = nullptr; | |
| 1934 | size_t debug_member_count = 0; | |
| 1935 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1936 | ZigLLVMFileToScope(import->di_file), | |
| 1937 | buf_ptr(&union_type->name), | |
| 1938 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1939 | debug_size_in_bits, | |
| 1940 | debug_align_in_bits, | |
| 1941 | 0, di_root_members, (int)debug_member_count, 0, ""); | |
| 1942 | ||
| 1943 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | |
| 1944 | union_type->di_type = replacement_di_type; | |
| 1945 | return; | |
| 1946 | } | |
| 1947 | ||
| 1948 | assert(most_aligned_union_member != nullptr); | |
| 1949 | ||
| 1950 | // create llvm type for union | |
| 1951 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | |
| 1952 | if (padding_in_bits > 0) { | |
| 1953 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | |
| 1954 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | |
| 1955 | LLVMTypeRef union_element_types[] = { | |
| 1956 | most_aligned_union_member->type_ref, | |
| 1957 | padding_array->type_ref, | |
| 1958 | }; | |
| 1959 | LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false); | |
| 1960 | } else { | |
| 1961 | LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false); | |
| 1962 | } | |
| 1963 | ||
| 1964 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits); | |
| 1965 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits); | |
| 1966 | ||
| 1967 | // create debug type for union | |
| 1968 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | |
| 1969 | ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name), | |
| 1970 | import->di_file, (unsigned)(decl_node->line + 1), | |
| 1971 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | |
| 1972 | gen_field_count, 0, ""); | |
| 1973 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | |
| 1974 | union_type->di_type = replacement_di_type; | |
| 1838 | 1975 | } |
| 1839 | 1976 | |
| 1840 | 1977 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| ... | ... | @@ -1873,7 +2010,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1873 | 2010 | type_enum_field->value = i; |
| 1874 | 2011 | |
| 1875 | 2012 | type_ensure_zero_bits_known(g, field_type); |
| 1876 | if (field_type->id == TypeTableEntryIdInvalid) { | |
| 2013 | if (type_is_invalid(field_type)) { | |
| 1877 | 2014 | enum_type->data.enumeration.is_invalid = true; |
| 1878 | 2015 | continue; |
| 1879 | 2016 | } |
| ... | ... | @@ -1980,7 +2117,66 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 1980 | 2117 | } |
| 1981 | 2118 | |
| 1982 | 2119 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 1983 | zig_panic("TODO resolve_union_zero_bits"); | |
| 2120 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 2121 | ||
| 2122 | if (union_type->data.unionation.zero_bits_known) | |
| 2123 | return; | |
| 2124 | ||
| 2125 | if (union_type->data.unionation.zero_bits_loop_flag) { | |
| 2126 | union_type->data.unionation.zero_bits_known = true; | |
| 2127 | return; | |
| 2128 | } | |
| 2129 | ||
| 2130 | union_type->data.unionation.zero_bits_loop_flag = true; | |
| 2131 | ||
| 2132 | AstNode *decl_node = union_type->data.unionation.decl_node; | |
| 2133 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2134 | assert(union_type->di_type); | |
| 2135 | ||
| 2136 | assert(!union_type->data.unionation.fields); | |
| 2137 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | |
| 2138 | union_type->data.unionation.src_field_count = field_count; | |
| 2139 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); | |
| 2140 | ||
| 2141 | uint32_t biggest_align_bytes = 0; | |
| 2142 | ||
| 2143 | Scope *scope = &union_type->data.unionation.decls_scope->base; | |
| 2144 | ||
| 2145 | uint32_t gen_field_index = 0; | |
| 2146 | for (uint32_t i = 0; i < field_count; i += 1) { | |
| 2147 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | |
| 2148 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | |
| 2149 | type_union_field->name = field_node->data.struct_field.name; | |
| 2150 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2151 | type_union_field->type_entry = field_type; | |
| 2152 | ||
| 2153 | type_ensure_zero_bits_known(g, field_type); | |
| 2154 | if (type_is_invalid(field_type)) { | |
| 2155 | union_type->data.unionation.is_invalid = true; | |
| 2156 | continue; | |
| 2157 | } | |
| 2158 | ||
| 2159 | if (!type_has_bits(field_type)) | |
| 2160 | continue; | |
| 2161 | ||
| 2162 | type_union_field->gen_index = gen_field_index; | |
| 2163 | gen_field_index += 1; | |
| 2164 | ||
| 2165 | uint32_t field_align_bytes = get_abi_alignment(g, field_type); | |
| 2166 | if (field_align_bytes > biggest_align_bytes) { | |
| 2167 | biggest_align_bytes = field_align_bytes; | |
| 2168 | } | |
| 2169 | } | |
| 2170 | ||
| 2171 | union_type->data.unionation.zero_bits_loop_flag = false; | |
| 2172 | union_type->data.unionation.gen_field_count = gen_field_index; | |
| 2173 | union_type->zero_bits = (gen_field_index == 0); | |
| 2174 | union_type->data.unionation.zero_bits_known = true; | |
| 2175 | ||
| 2176 | // also compute abi_alignment | |
| 2177 | if (!union_type->zero_bits) { | |
| 2178 | union_type->data.unionation.abi_alignment = biggest_align_bytes; | |
| 2179 | } | |
| 1984 | 2180 | } |
| 1985 | 2181 | |
| 1986 | 2182 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { |
| ... | ... | @@ -2851,6 +3047,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 2851 | 3047 | return nullptr; |
| 2852 | 3048 | } |
| 2853 | 3049 | |
| 3050 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | |
| 3051 | assert(type_entry->id == TypeTableEntryIdUnion); | |
| 3052 | assert(type_entry->data.unionation.complete); | |
| 3053 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | |
| 3054 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | |
| 3055 | if (buf_eql_buf(field->name, name)) { | |
| 3056 | return field; | |
| 3057 | } | |
| 3058 | } | |
| 3059 | return nullptr; | |
| 3060 | } | |
| 3061 | ||
| 2854 | 3062 | static bool is_container(TypeTableEntry *type_entry) { |
| 2855 | 3063 | switch (type_entry->id) { |
| 2856 | 3064 | case TypeTableEntryIdInvalid: |
| ... | ... | @@ -4703,6 +4911,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 4703 | 4911 | return &value->data.x_array.s_none.parent; |
| 4704 | 4912 | } else if (type_entry->id == TypeTableEntryIdStruct) { |
| 4705 | 4913 | return &value->data.x_struct.parent; |
| 4914 | } else if (type_entry->id == TypeTableEntryIdUnion) { | |
| 4915 | return &value->data.x_union.parent; | |
| 4706 | 4916 | } |
| 4707 | 4917 | return nullptr; |
| 4708 | 4918 | } |
| ... | ... | @@ -4914,7 +5124,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 4914 | 5124 | assert(type_entry->data.enumeration.abi_alignment != 0); |
| 4915 | 5125 | return type_entry->data.enumeration.abi_alignment; |
| 4916 | 5126 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 4917 | zig_panic("TODO"); | |
| 5127 | assert(type_entry->data.unionation.abi_alignment != 0); | |
| 5128 | return type_entry->data.unionation.abi_alignment; | |
| 4918 | 5129 | } else if (type_entry->id == TypeTableEntryIdOpaque) { |
| 4919 | 5130 | return 1; |
| 4920 | 5131 | } else { |
src/analyze.hpp+1| ... | ... | @@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); |
| 63 | 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); |
| 64 | 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| 65 | 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); |
| 66 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name); | |
| 66 | 67 | bool is_container_ref(TypeTableEntry *type_entry); |
| 67 | 68 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 68 | 69 | void scan_import(CodeGen *g, ImportTableEntry *import); |
src/codegen.cpp+97-4| ... | ... | @@ -2393,6 +2393,27 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl |
| 2393 | 2393 | return bitcasted_union_field_ptr; |
| 2394 | 2394 | } |
| 2395 | 2395 | |
| 2396 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, | |
| 2397 | IrInstructionUnionFieldPtr *instruction) | |
| 2398 | { | |
| 2399 | TypeTableEntry *union_ptr_type = instruction->union_ptr->value.type; | |
| 2400 | assert(union_ptr_type->id == TypeTableEntryIdPointer); | |
| 2401 | TypeTableEntry *union_type = union_ptr_type->data.pointer.child_type; | |
| 2402 | assert(union_type->id == TypeTableEntryIdUnion); | |
| 2403 | ||
| 2404 | TypeUnionField *field = instruction->field; | |
| 2405 | ||
| 2406 | if (!type_has_bits(field->type_entry)) | |
| 2407 | return nullptr; | |
| 2408 | ||
| 2409 | LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); | |
| 2410 | LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); | |
| 2411 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, ""); | |
| 2412 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | |
| 2413 | ||
| 2414 | return bitcasted_union_field_ptr; | |
| 2415 | } | |
| 2416 | ||
| 2396 | 2417 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { |
| 2397 | 2418 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; |
| 2398 | 2419 | size_t len = tok->end - tok->start - 2; |
| ... | ... | @@ -3365,6 +3386,25 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 3365 | 3386 | return instruction->tmp_ptr; |
| 3366 | 3387 | } |
| 3367 | 3388 | |
| 3389 | static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { | |
| 3390 | TypeUnionField *type_union_field = instruction->field; | |
| 3391 | ||
| 3392 | assert(type_has_bits(type_union_field->type_entry)); | |
| 3393 | ||
| 3394 | LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); | |
| 3395 | LLVMValueRef value = ir_llvm_value(g, instruction->init_value); | |
| 3396 | ||
| 3397 | uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); | |
| 3398 | ||
| 3399 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, | |
| 3400 | false, false, field_align_bytes, | |
| 3401 | 0, 0); | |
| 3402 | ||
| 3403 | gen_assign_raw(g, field_ptr, ptr_type, value); | |
| 3404 | ||
| 3405 | return instruction->tmp_ptr; | |
| 3406 | } | |
| 3407 | ||
| 3368 | 3408 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, |
| 3369 | 3409 | IrInstructionContainerInitList *instruction) |
| 3370 | 3410 | { |
| ... | ... | @@ -3486,6 +3526,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3486 | 3526 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3487 | 3527 | case IrInstructionIdEnumFieldPtr: |
| 3488 | 3528 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); |
| 3529 | case IrInstructionIdUnionFieldPtr: | |
| 3530 | return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction); | |
| 3489 | 3531 | case IrInstructionIdAsm: |
| 3490 | 3532 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 3491 | 3533 | case IrInstructionIdTestNonNull: |
| ... | ... | @@ -3544,6 +3586,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3544 | 3586 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); |
| 3545 | 3587 | case IrInstructionIdStructInit: |
| 3546 | 3588 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3589 | case IrInstructionIdUnionInit: | |
| 3590 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | |
| 3547 | 3591 | case IrInstructionIdPtrCast: |
| 3548 | 3592 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); |
| 3549 | 3593 | case IrInstructionIdBitCast: |
| ... | ... | @@ -3595,6 +3639,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { |
| 3595 | 3639 | |
| 3596 | 3640 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 3597 | 3641 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); |
| 3642 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val); | |
| 3598 | 3643 | |
| 3599 | 3644 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 3600 | 3645 | switch (parent->id) { |
| ... | ... | @@ -3608,6 +3653,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 3608 | 3653 | case ConstParentIdArray: |
| 3609 | 3654 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 3610 | 3655 | parent->data.p_array.elem_index); |
| 3656 | case ConstParentIdUnion: | |
| 3657 | return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val); | |
| 3611 | 3658 | } |
| 3612 | 3659 | zig_unreachable(); |
| 3613 | 3660 | } |
| ... | ... | @@ -3637,6 +3684,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 3637 | 3684 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 3638 | 3685 | } |
| 3639 | 3686 | |
| 3687 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { | |
| 3688 | ConstParent *parent = &union_const_val->data.x_union.parent; | |
| 3689 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); | |
| 3690 | ||
| 3691 | TypeTableEntry *u32 = g->builtin_types.entry_u32; | |
| 3692 | LLVMValueRef indices[] = { | |
| 3693 | LLVMConstNull(u32->type_ref), | |
| 3694 | LLVMConstInt(u32->type_ref, 0, false), | |
| 3695 | }; | |
| 3696 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | |
| 3697 | } | |
| 3698 | ||
| 3640 | 3699 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 3641 | 3700 | switch (const_val->special) { |
| 3642 | 3701 | case ConstValSpecialRuntime: |
| ... | ... | @@ -3872,10 +3931,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3872 | 3931 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); |
| 3873 | 3932 | } |
| 3874 | 3933 | } |
| 3875 | case TypeTableEntryIdUnion: | |
| 3876 | { | |
| 3877 | zig_panic("TODO"); | |
| 3878 | } | |
| 3879 | 3934 | case TypeTableEntryIdArray: |
| 3880 | 3935 | { |
| 3881 | 3936 | uint64_t len = type_entry->data.array.len; |
| ... | ... | @@ -3898,6 +3953,41 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3898 | 3953 | return LLVMConstArray(element_type_ref, values, (unsigned)len); |
| 3899 | 3954 | } |
| 3900 | 3955 | } |
| 3956 | case TypeTableEntryIdUnion: | |
| 3957 | { | |
| 3958 | LLVMTypeRef union_type_ref = type_entry->type_ref; | |
| 3959 | ConstExprValue *payload_value = const_val->data.x_union.value; | |
| 3960 | assert(payload_value != nullptr); | |
| 3961 | ||
| 3962 | if (!type_has_bits(payload_value->type)) { | |
| 3963 | return LLVMGetUndef(union_type_ref); | |
| 3964 | } | |
| 3965 | ||
| 3966 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); | |
| 3967 | uint64_t pad_bytes = type_entry->data.unionation.size_bytes - field_type_bytes; | |
| 3968 | ||
| 3969 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | |
| 3970 | ||
| 3971 | bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | |
| 3972 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | |
| 3973 | ||
| 3974 | unsigned field_count; | |
| 3975 | LLVMValueRef fields[2]; | |
| 3976 | fields[0] = correctly_typed_value; | |
| 3977 | if (pad_bytes == 0) { | |
| 3978 | field_count = 1; | |
| 3979 | } else { | |
| 3980 | fields[0] = correctly_typed_value; | |
| 3981 | fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); | |
| 3982 | field_count = 2; | |
| 3983 | } | |
| 3984 | ||
| 3985 | if (make_unnamed_struct) { | |
| 3986 | return LLVMConstStruct(fields, field_count, false); | |
| 3987 | } else { | |
| 3988 | return LLVMConstNamedStruct(type_entry->type_ref, fields, field_count); | |
| 3989 | } | |
| 3990 | } | |
| 3901 | 3991 | case TypeTableEntryIdEnum: |
| 3902 | 3992 | { |
| 3903 | 3993 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; |
| ... | ... | @@ -4376,6 +4466,9 @@ static void do_code_gen(CodeGen *g) { |
| 4376 | 4466 | } else if (instruction->id == IrInstructionIdStructInit) { |
| 4377 | 4467 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; |
| 4378 | 4468 | slot = &struct_init_instruction->tmp_ptr; |
| 4469 | } else if (instruction->id == IrInstructionIdUnionInit) { | |
| 4470 | IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; | |
| 4471 | slot = &union_init_instruction->tmp_ptr; | |
| 4379 | 4472 | } else if (instruction->id == IrInstructionIdCall) { |
| 4380 | 4473 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; |
| 4381 | 4474 | slot = &call_instruction->tmp_ptr; |
src/ir.cpp+160-11| ... | ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) |
| 227 | 227 | return IrInstructionIdEnumFieldPtr; |
| 228 | 228 | } |
| 229 | 229 | |
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { | |
| 231 | return IrInstructionIdUnionFieldPtr; | |
| 232 | } | |
| 233 | ||
| 230 | 234 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { |
| 231 | 235 | return IrInstructionIdElemPtr; |
| 232 | 236 | } |
| ... | ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { |
| 351 | 355 | return IrInstructionIdStructInit; |
| 352 | 356 | } |
| 353 | 357 | |
| 358 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { | |
| 359 | return IrInstructionIdUnionInit; | |
| 360 | } | |
| 361 | ||
| 354 | 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { |
| 355 | 363 | return IrInstructionIdMinValue; |
| 356 | 364 | } |
| ... | ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction |
| 922 | 930 | return new_instruction; |
| 923 | 931 | } |
| 924 | 932 | |
| 933 | static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 934 | IrInstruction *union_ptr, TypeUnionField *field) | |
| 935 | { | |
| 936 | IrInstructionUnionFieldPtr *instruction = ir_build_instruction<IrInstructionUnionFieldPtr>(irb, scope, source_node); | |
| 937 | instruction->union_ptr = union_ptr; | |
| 938 | instruction->field = field; | |
| 939 | ||
| 940 | ir_ref_instruction(union_ptr, irb->current_basic_block); | |
| 941 | ||
| 942 | return &instruction->base; | |
| 943 | } | |
| 944 | ||
| 945 | static IrInstruction *ir_build_union_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 946 | IrInstruction *union_ptr, TypeUnionField *type_union_field) | |
| 947 | { | |
| 948 | IrInstruction *new_instruction = ir_build_union_field_ptr(irb, old_instruction->scope, | |
| 949 | old_instruction->source_node, union_ptr, type_union_field); | |
| 950 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 951 | return new_instruction; | |
| 952 | } | |
| 953 | ||
| 925 | 954 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 926 | 955 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 927 | 956 | bool is_comptime, bool is_inline) |
| ... | ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o |
| 1112 | 1141 | return new_instruction; |
| 1113 | 1142 | } |
| 1114 | 1143 | |
| 1144 | static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1145 | TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) | |
| 1146 | { | |
| 1147 | IrInstructionUnionInit *union_init_instruction = ir_build_instruction<IrInstructionUnionInit>(irb, scope, source_node); | |
| 1148 | union_init_instruction->union_type = union_type; | |
| 1149 | union_init_instruction->field = field; | |
| 1150 | union_init_instruction->init_value = init_value; | |
| 1151 | ||
| 1152 | ir_ref_instruction(init_value, irb->current_basic_block); | |
| 1153 | ||
| 1154 | return &union_init_instruction->base; | |
| 1155 | } | |
| 1156 | ||
| 1157 | static IrInstruction *ir_build_union_init_from(IrBuilder *irb, IrInstruction *old_instruction, | |
| 1158 | TypeTableEntry *union_type, TypeUnionField *field, IrInstruction *init_value) | |
| 1159 | { | |
| 1160 | IrInstruction *new_instruction = ir_build_union_init(irb, old_instruction->scope, | |
| 1161 | old_instruction->source_node, union_type, field, init_value); | |
| 1162 | ir_link_new_instruction(new_instruction, old_instruction); | |
| 1163 | return new_instruction; | |
| 1164 | } | |
| 1165 | ||
| 1115 | 1166 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1116 | 1167 | IrInstructionUnreachable *unreachable_instruction = |
| 1117 | 1168 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); |
| ... | ... | @@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField |
| 2422 | 2473 | } |
| 2423 | 2474 | } |
| 2424 | 2475 | |
| 2476 | static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) { | |
| 2477 | switch (index) { | |
| 2478 | case 0: return instruction->union_ptr; | |
| 2479 | default: return nullptr; | |
| 2480 | } | |
| 2481 | } | |
| 2482 | ||
| 2425 | 2483 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { |
| 2426 | 2484 | switch (index) { |
| 2427 | 2485 | case 0: return instruction->array_ptr; |
| ... | ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit |
| 2485 | 2543 | return nullptr; |
| 2486 | 2544 | } |
| 2487 | 2545 | |
| 2546 | static IrInstruction *ir_instruction_unioninit_get_dep(IrInstructionUnionInit *instruction, size_t index) { | |
| 2547 | switch (index) { | |
| 2548 | case 0: return instruction->init_value; | |
| 2549 | default: return nullptr; | |
| 2550 | } | |
| 2551 | } | |
| 2552 | ||
| 2488 | 2553 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { |
| 2489 | 2554 | return nullptr; |
| 2490 | 2555 | } |
| ... | ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3099 | 3164 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); |
| 3100 | 3165 | case IrInstructionIdEnumFieldPtr: |
| 3101 | 3166 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); |
| 3167 | case IrInstructionIdUnionFieldPtr: | |
| 3168 | return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); | |
| 3102 | 3169 | case IrInstructionIdElemPtr: |
| 3103 | 3170 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); |
| 3104 | 3171 | case IrInstructionIdVarPtr: |
| ... | ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3117 | 3184 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); |
| 3118 | 3185 | case IrInstructionIdStructInit: |
| 3119 | 3186 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); |
| 3187 | case IrInstructionIdUnionInit: | |
| 3188 | return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index); | |
| 3120 | 3189 | case IrInstructionIdUnreachable: |
| 3121 | 3190 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); |
| 3122 | 3191 | case IrInstructionIdTypeOf: |
| ... | ... | @@ -11417,8 +11486,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 11417 | 11486 | return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); |
| 11418 | 11487 | } |
| 11419 | 11488 | } |
| 11489 | const char *prefix_name; | |
| 11490 | if (is_slice(bare_struct_type)) { | |
| 11491 | prefix_name = ""; | |
| 11492 | } else if (bare_struct_type->id == TypeTableEntryIdStruct) { | |
| 11493 | prefix_name = "struct "; | |
| 11494 | } else if (bare_struct_type->id == TypeTableEntryIdEnum) { | |
| 11495 | prefix_name = "enum "; | |
| 11496 | } else if (bare_struct_type->id == TypeTableEntryIdUnion) { | |
| 11497 | prefix_name = "union "; | |
| 11498 | } else { | |
| 11499 | prefix_name = ""; | |
| 11500 | } | |
| 11420 | 11501 | ir_add_error_node(ira, field_ptr_instruction->base.source_node, |
| 11421 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); | |
| 11502 | buf_sprintf("no member named '%s' in %s'%s'", buf_ptr(field_name), prefix_name, buf_ptr(&bare_struct_type->name))); | |
| 11422 | 11503 | return ira->codegen->builtin_types.entry_invalid; |
| 11423 | 11504 | } |
| 11424 | 11505 | |
| ... | ... | @@ -11428,14 +11509,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11428 | 11509 | { |
| 11429 | 11510 | TypeTableEntry *bare_type = container_ref_type(container_type); |
| 11430 | 11511 | ensure_complete_type(ira->codegen, bare_type); |
| 11512 | if (type_is_invalid(bare_type)) | |
| 11513 | return ira->codegen->builtin_types.entry_invalid; | |
| 11431 | 11514 | |
| 11432 | 11515 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); |
| 11433 | 11516 | bool is_const = container_ptr->value.type->data.pointer.is_const; |
| 11434 | 11517 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; |
| 11435 | 11518 | if (bare_type->id == TypeTableEntryIdStruct) { |
| 11436 | if (bare_type->data.structure.is_invalid) | |
| 11437 | return ira->codegen->builtin_types.entry_invalid; | |
| 11438 | ||
| 11439 | 11519 | TypeStructField *field = find_struct_type_field(bare_type, field_name); |
| 11440 | 11520 | if (field) { |
| 11441 | 11521 | bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); |
| ... | ... | @@ -11476,9 +11556,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11476 | 11556 | field_ptr_instruction, container_ptr, container_type); |
| 11477 | 11557 | } |
| 11478 | 11558 | } else if (bare_type->id == TypeTableEntryIdEnum) { |
| 11479 | if (bare_type->data.enumeration.is_invalid) | |
| 11480 | return ira->codegen->builtin_types.entry_invalid; | |
| 11481 | ||
| 11482 | 11559 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); |
| 11483 | 11560 | if (field) { |
| 11484 | 11561 | ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); |
| ... | ... | @@ -11489,7 +11566,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11489 | 11566 | field_ptr_instruction, container_ptr, container_type); |
| 11490 | 11567 | } |
| 11491 | 11568 | } else if (bare_type->id == TypeTableEntryIdUnion) { |
| 11492 | zig_panic("TODO"); | |
| 11569 | TypeUnionField *field = find_union_type_field(bare_type, field_name); | |
| 11570 | if (field) { | |
| 11571 | ir_build_union_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); | |
| 11572 | return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, | |
| 11573 | get_abi_alignment(ira->codegen, field->type_entry), 0, 0); | |
| 11574 | } else { | |
| 11575 | return ir_analyze_container_member_access_inner(ira, bare_type, field_name, | |
| 11576 | field_ptr_instruction, container_ptr, container_type); | |
| 11577 | } | |
| 11493 | 11578 | } else { |
| 11494 | 11579 | zig_unreachable(); |
| 11495 | 11580 | } |
| ... | ... | @@ -13033,9 +13118,70 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR |
| 13033 | 13118 | return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); |
| 13034 | 13119 | } |
| 13035 | 13120 | |
| 13121 | static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, | |
| 13122 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | |
| 13123 | { | |
| 13124 | assert(container_type->id == TypeTableEntryIdUnion); | |
| 13125 | ||
| 13126 | ensure_complete_type(ira->codegen, container_type); | |
| 13127 | ||
| 13128 | if (instr_field_count != 1) { | |
| 13129 | ir_add_error(ira, instruction, | |
| 13130 | buf_sprintf("union initialization expects exactly one field")); | |
| 13131 | return ira->codegen->builtin_types.entry_invalid; | |
| 13132 | } | |
| 13133 | ||
| 13134 | IrInstructionContainerInitFieldsField *field = &fields[0]; | |
| 13135 | IrInstruction *field_value = field->value->other; | |
| 13136 | if (type_is_invalid(field_value->value.type)) | |
| 13137 | return ira->codegen->builtin_types.entry_invalid; | |
| 13138 | ||
| 13139 | TypeUnionField *type_field = find_union_type_field(container_type, field->name); | |
| 13140 | if (!type_field) { | |
| 13141 | ir_add_error_node(ira, field->source_node, | |
| 13142 | buf_sprintf("no member named '%s' in union '%s'", | |
| 13143 | buf_ptr(field->name), buf_ptr(&container_type->name))); | |
| 13144 | return ira->codegen->builtin_types.entry_invalid; | |
| 13145 | } | |
| 13146 | ||
| 13147 | if (type_is_invalid(type_field->type_entry)) | |
| 13148 | return ira->codegen->builtin_types.entry_invalid; | |
| 13149 | ||
| 13150 | IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); | |
| 13151 | if (casted_field_value == ira->codegen->invalid_instruction) | |
| 13152 | return ira->codegen->builtin_types.entry_invalid; | |
| 13153 | ||
| 13154 | bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope); | |
| 13155 | if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { | |
| 13156 | ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); | |
| 13157 | if (!field_val) | |
| 13158 | return ira->codegen->builtin_types.entry_invalid; | |
| 13159 | ||
| 13160 | ConstExprValue *out_val = ir_build_const_from(ira, instruction); | |
| 13161 | out_val->data.x_union.value = field_val; | |
| 13162 | ||
| 13163 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); | |
| 13164 | if (parent != nullptr) { | |
| 13165 | parent->id = ConstParentIdUnion; | |
| 13166 | parent->data.p_union.union_val = out_val; | |
| 13167 | } | |
| 13168 | ||
| 13169 | return container_type; | |
| 13170 | } | |
| 13171 | ||
| 13172 | IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction, | |
| 13173 | container_type, type_field, casted_field_value); | |
| 13174 | ||
| 13175 | ir_add_alloca(ira, new_instruction, container_type); | |
| 13176 | return container_type; | |
| 13177 | } | |
| 13178 | ||
| 13036 | 13179 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 13037 | 13180 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) |
| 13038 | 13181 | { |
| 13182 | if (container_type->id == TypeTableEntryIdUnion) { | |
| 13183 | return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); | |
| 13184 | } | |
| 13039 | 13185 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { |
| 13040 | 13186 | ir_add_error(ira, instruction, |
| 13041 | 13187 | buf_sprintf("type '%s' does not support struct initialization syntax", |
| ... | ... | @@ -13043,8 +13189,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13043 | 13189 | return ira->codegen->builtin_types.entry_invalid; |
| 13044 | 13190 | } |
| 13045 | 13191 | |
| 13046 | if (!type_is_complete(container_type)) | |
| 13047 | resolve_container_type(ira->codegen, container_type); | |
| 13192 | ensure_complete_type(ira->codegen, container_type); | |
| 13048 | 13193 | |
| 13049 | 13194 | size_t actual_field_count = container_type->data.structure.src_field_count; |
| 13050 | 13195 | |
| ... | ... | @@ -13070,7 +13215,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13070 | 13215 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); |
| 13071 | 13216 | if (!type_field) { |
| 13072 | 13217 | ir_add_error_node(ira, field->source_node, |
| 13073 | buf_sprintf("no member named '%s' in '%s'", | |
| 13218 | buf_sprintf("no member named '%s' in struct '%s'", | |
| 13074 | 13219 | buf_ptr(field->name), buf_ptr(&container_type->name))); |
| 13075 | 13220 | return ira->codegen->builtin_types.entry_invalid; |
| 13076 | 13221 | } |
| ... | ... | @@ -15657,8 +15802,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15657 | 15802 | case IrInstructionIdIntToErr: |
| 15658 | 15803 | case IrInstructionIdErrToInt: |
| 15659 | 15804 | case IrInstructionIdStructInit: |
| 15805 | case IrInstructionIdUnionInit: | |
| 15660 | 15806 | case IrInstructionIdStructFieldPtr: |
| 15661 | 15807 | case IrInstructionIdEnumFieldPtr: |
| 15808 | case IrInstructionIdUnionFieldPtr: | |
| 15662 | 15809 | case IrInstructionIdInitEnum: |
| 15663 | 15810 | case IrInstructionIdMaybeWrap: |
| 15664 | 15811 | case IrInstructionIdErrWrapCode: |
| ... | ... | @@ -15968,6 +16115,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15968 | 16115 | case IrInstructionIdContainerInitList: |
| 15969 | 16116 | case IrInstructionIdContainerInitFields: |
| 15970 | 16117 | case IrInstructionIdStructInit: |
| 16118 | case IrInstructionIdUnionInit: | |
| 15971 | 16119 | case IrInstructionIdFieldPtr: |
| 15972 | 16120 | case IrInstructionIdElemPtr: |
| 15973 | 16121 | case IrInstructionIdVarPtr: |
| ... | ... | @@ -15977,6 +16125,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15977 | 16125 | case IrInstructionIdArrayLen: |
| 15978 | 16126 | case IrInstructionIdStructFieldPtr: |
| 15979 | 16127 | case IrInstructionIdEnumFieldPtr: |
| 16128 | case IrInstructionIdUnionFieldPtr: | |
| 15980 | 16129 | case IrInstructionIdArrayType: |
| 15981 | 16130 | case IrInstructionIdSliceType: |
| 15982 | 16131 | case IrInstructionIdSizeOf: |
src/ir_print.cpp+22| ... | ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct |
| 290 | 290 | fprintf(irp->f, "} // struct init"); |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { | |
| 294 | Buf *field_name = instruction->field->name; | |
| 295 | ||
| 296 | fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name)); | |
| 297 | fprintf(irp->f, ".%s = ", buf_ptr(field_name)); | |
| 298 | ir_print_other_instruction(irp, instruction->init_value); | |
| 299 | fprintf(irp->f, "} // union init"); | |
| 300 | } | |
| 301 | ||
| 293 | 302 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { |
| 294 | 303 | fprintf(irp->f, "unreachable"); |
| 295 | 304 | } |
| ... | ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins |
| 359 | 368 | fprintf(irp->f, ")"); |
| 360 | 369 | } |
| 361 | 370 | |
| 371 | static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) { | |
| 372 | fprintf(irp->f, "@UnionFieldPtr(&"); | |
| 373 | ir_print_other_instruction(irp, instruction->union_ptr); | |
| 374 | fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); | |
| 375 | fprintf(irp->f, ")"); | |
| 376 | } | |
| 377 | ||
| 362 | 378 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { |
| 363 | 379 | fprintf(irp->f, "@setDebugSafety("); |
| 364 | 380 | ir_print_other_instruction(irp, instruction->scope_value); |
| ... | ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1023 | 1039 | case IrInstructionIdStructInit: |
| 1024 | 1040 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); |
| 1025 | 1041 | break; |
| 1042 | case IrInstructionIdUnionInit: | |
| 1043 | ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); | |
| 1044 | break; | |
| 1026 | 1045 | case IrInstructionIdUnreachable: |
| 1027 | 1046 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); |
| 1028 | 1047 | break; |
| ... | ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1056 | 1075 | case IrInstructionIdEnumFieldPtr: |
| 1057 | 1076 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); |
| 1058 | 1077 | break; |
| 1078 | case IrInstructionIdUnionFieldPtr: | |
| 1079 | ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction); | |
| 1080 | break; | |
| 1059 | 1081 | case IrInstructionIdSetDebugSafety: |
| 1060 | 1082 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); |
| 1061 | 1083 | break; |
src/zig_llvm.cpp+4| ... | ... | @@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 403 | 403 | return dwarf::DW_TAG_structure_type; |
| 404 | 404 | } |
| 405 | 405 | |
| 406 | unsigned ZigLLVMTag_DW_union_type(void) { | |
| 407 | return dwarf::DW_TAG_union_type; | |
| 408 | } | |
| 409 | ||
| 406 | 410 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 407 | 411 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); |
| 408 | 412 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
src/zig_llvm.hpp+1| ... | ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 117 | 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 118 | 118 | unsigned ZigLLVMTag_DW_variable(void); |
| 119 | 119 | unsigned ZigLLVMTag_DW_structure_type(void); |
| 120 | unsigned ZigLLVMTag_DW_union_type(void); | |
| 120 | 121 | |
| 121 | 122 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
| 122 | 123 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
test/cases/union.zig+13| ... | ... | @@ -31,3 +31,16 @@ test "unions embedded in aggregate types" { |
| 31 | 31 | else => unreachable, |
| 32 | 32 | } |
| 33 | 33 | } |
| 34 | ||
| 35 | ||
| 36 | const Foo = union { | |
| 37 | float: f64, | |
| 38 | int: i32, | |
| 39 | }; | |
| 40 | ||
| 41 | test "basic unions" { | |
| 42 | var foo = Foo { .int = 1 }; | |
| 43 | assert(foo.int == 1); | |
| 44 | foo.float = 12.34; | |
| 45 | assert(foo.float == 12.34); | |
| 46 | } |
test/compile_errors.zig+3-3| ... | ... | @@ -389,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 389 | 389 | \\ const y = a.bar; |
| 390 | 390 | \\} |
| 391 | 391 | , |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' in 'A'", | |
| 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in 'A'"); | |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' in struct 'A'", | |
| 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); | |
| 394 | 394 | |
| 395 | 395 | cases.add("redefinition of struct", |
| 396 | 396 | \\const A = struct { x : i32, }; |
| ... | ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 454 | 454 | \\ .foo = 42, |
| 455 | 455 | \\ }; |
| 456 | 456 | \\} |
| 457 | , ".tmp_source.zig:10:9: error: no member named 'foo' in 'A'"); | |
| 457 | , ".tmp_source.zig:10:9: error: no member named 'foo' in struct 'A'"); | |
| 458 | 458 | |
| 459 | 459 | cases.add("invalid break expression", |
| 460 | 460 | \\export fn f() { |