| 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,6 +73,7 @@ enum ConstParentId { |
| 73 | ConstParentIdNone, | 73 | ConstParentIdNone, |
| 74 | ConstParentIdStruct, | 74 | ConstParentIdStruct, |
| 75 | ConstParentIdArray, | 75 | ConstParentIdArray, |
| 76 | ConstParentIdUnion, | ||
| 76 | }; | 77 | }; |
| 77 | 78 | ||
| 78 | struct ConstParent { | 79 | struct ConstParent { |
| ... | @@ -87,6 +88,9 @@ struct ConstParent { | ... | @@ -87,6 +88,9 @@ struct ConstParent { |
| 87 | ConstExprValue *struct_val; | 88 | ConstExprValue *struct_val; |
| 88 | size_t field_index; | 89 | size_t field_index; |
| 89 | } p_struct; | 90 | } p_struct; |
| 91 | struct { | ||
| 92 | ConstExprValue *union_val; | ||
| 93 | } p_union; | ||
| 90 | } data; | 94 | } data; |
| 91 | }; | 95 | }; |
| 92 | 96 | ||
| ... | @@ -100,6 +104,11 @@ struct ConstStructValue { | ... | @@ -100,6 +104,11 @@ struct ConstStructValue { |
| 100 | ConstParent parent; | 104 | ConstParent parent; |
| 101 | }; | 105 | }; |
| 102 | 106 | ||
| 107 | struct ConstUnionValue { | ||
| 108 | ConstExprValue *value; | ||
| 109 | ConstParent parent; | ||
| 110 | }; | ||
| 111 | |||
| 103 | enum ConstArraySpecial { | 112 | enum ConstArraySpecial { |
| 104 | ConstArraySpecialNone, | 113 | ConstArraySpecialNone, |
| 105 | ConstArraySpecialUndef, | 114 | ConstArraySpecialUndef, |
| ... | @@ -238,6 +247,7 @@ struct ConstExprValue { | ... | @@ -238,6 +247,7 @@ struct ConstExprValue { |
| 238 | ErrorTableEntry *x_pure_err; | 247 | ErrorTableEntry *x_pure_err; |
| 239 | ConstEnumValue x_enum; | 248 | ConstEnumValue x_enum; |
| 240 | ConstStructValue x_struct; | 249 | ConstStructValue x_struct; |
| 250 | ConstUnionValue x_union; | ||
| 241 | ConstArrayValue x_array; | 251 | ConstArrayValue x_array; |
| 242 | ConstPtrValue x_ptr; | 252 | ConstPtrValue x_ptr; |
| 243 | ImportTableEntry *x_import; | 253 | ImportTableEntry *x_import; |
| ... | @@ -336,6 +346,12 @@ struct TypeEnumField { | ... | @@ -336,6 +346,12 @@ struct TypeEnumField { |
| 336 | uint32_t gen_index; | 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 | enum NodeType { | 355 | enum NodeType { |
| 340 | NodeTypeRoot, | 356 | NodeTypeRoot, |
| 341 | NodeTypeFnProto, | 357 | NodeTypeFnProto, |
| ... | @@ -1026,9 +1042,9 @@ struct TypeTableEntryUnion { | ... | @@ -1026,9 +1042,9 @@ struct TypeTableEntryUnion { |
| 1026 | ContainerLayout layout; | 1042 | ContainerLayout layout; |
| 1027 | uint32_t src_field_count; | 1043 | uint32_t src_field_count; |
| 1028 | uint32_t gen_field_count; | 1044 | uint32_t gen_field_count; |
| 1029 | TypeStructField *fields; | 1045 | TypeUnionField *fields; |
| 1030 | uint64_t size_bytes; | ||
| 1031 | bool is_invalid; // true if any fields are invalid | 1046 | bool is_invalid; // true if any fields are invalid |
| 1047 | |||
| 1032 | ScopeDecls *decls_scope; | 1048 | ScopeDecls *decls_scope; |
| 1033 | 1049 | ||
| 1034 | // set this flag temporarily to detect infinite loops | 1050 | // set this flag temporarily to detect infinite loops |
| ... | @@ -1039,6 +1055,10 @@ struct TypeTableEntryUnion { | ... | @@ -1039,6 +1055,10 @@ struct TypeTableEntryUnion { |
| 1039 | 1055 | ||
| 1040 | bool zero_bits_loop_flag; | 1056 | bool zero_bits_loop_flag; |
| 1041 | bool zero_bits_known; | 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 | struct FnGenParamInfo { | 1064 | struct FnGenParamInfo { |
| ... | @@ -1796,6 +1816,7 @@ enum IrInstructionId { | ... | @@ -1796,6 +1816,7 @@ enum IrInstructionId { |
| 1796 | IrInstructionIdFieldPtr, | 1816 | IrInstructionIdFieldPtr, |
| 1797 | IrInstructionIdStructFieldPtr, | 1817 | IrInstructionIdStructFieldPtr, |
| 1798 | IrInstructionIdEnumFieldPtr, | 1818 | IrInstructionIdEnumFieldPtr, |
| 1819 | IrInstructionIdUnionFieldPtr, | ||
| 1799 | IrInstructionIdElemPtr, | 1820 | IrInstructionIdElemPtr, |
| 1800 | IrInstructionIdVarPtr, | 1821 | IrInstructionIdVarPtr, |
| 1801 | IrInstructionIdCall, | 1822 | IrInstructionIdCall, |
| ... | @@ -1805,6 +1826,7 @@ enum IrInstructionId { | ... | @@ -1805,6 +1826,7 @@ enum IrInstructionId { |
| 1805 | IrInstructionIdContainerInitList, | 1826 | IrInstructionIdContainerInitList, |
| 1806 | IrInstructionIdContainerInitFields, | 1827 | IrInstructionIdContainerInitFields, |
| 1807 | IrInstructionIdStructInit, | 1828 | IrInstructionIdStructInit, |
| 1829 | IrInstructionIdUnionInit, | ||
| 1808 | IrInstructionIdUnreachable, | 1830 | IrInstructionIdUnreachable, |
| 1809 | IrInstructionIdTypeOf, | 1831 | IrInstructionIdTypeOf, |
| 1810 | IrInstructionIdToPtrType, | 1832 | IrInstructionIdToPtrType, |
| ... | @@ -2060,6 +2082,14 @@ struct IrInstructionEnumFieldPtr { | ... | @@ -2060,6 +2082,14 @@ struct IrInstructionEnumFieldPtr { |
| 2060 | bool is_const; | 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 | struct IrInstructionElemPtr { | 2093 | struct IrInstructionElemPtr { |
| 2064 | IrInstruction base; | 2094 | IrInstruction base; |
| 2065 | 2095 | ||
| ... | @@ -2150,6 +2180,15 @@ struct IrInstructionStructInit { | ... | @@ -2150,6 +2180,15 @@ struct IrInstructionStructInit { |
| 2150 | LLVMValueRef tmp_ptr; | 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 | struct IrInstructionUnreachable { | 2192 | struct IrInstructionUnreachable { |
| 2154 | IrInstruction base; | 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,18 +992,22 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 992 | TypeTableEntryId type_id = container_to_type(kind); | 992 | TypeTableEntryId type_id = container_to_type(kind); |
| 993 | TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); | 993 | TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope); |
| 994 | 994 | ||
| 995 | unsigned dwarf_kind; | ||
| 995 | switch (kind) { | 996 | switch (kind) { |
| 996 | case ContainerKindStruct: | 997 | case ContainerKindStruct: |
| 997 | entry->data.structure.decl_node = decl_node; | 998 | entry->data.structure.decl_node = decl_node; |
| 998 | entry->data.structure.layout = layout; | 999 | entry->data.structure.layout = layout; |
| 1000 | dwarf_kind = ZigLLVMTag_DW_structure_type(); | ||
| 999 | break; | 1001 | break; |
| 1000 | case ContainerKindEnum: | 1002 | case ContainerKindEnum: |
| 1001 | entry->data.enumeration.decl_node = decl_node; | 1003 | entry->data.enumeration.decl_node = decl_node; |
| 1002 | entry->data.enumeration.layout = layout; | 1004 | entry->data.enumeration.layout = layout; |
| 1005 | dwarf_kind = ZigLLVMTag_DW_structure_type(); | ||
| 1003 | break; | 1006 | break; |
| 1004 | case ContainerKindUnion: | 1007 | case ContainerKindUnion: |
| 1005 | entry->data.unionation.decl_node = decl_node; | 1008 | entry->data.unionation.decl_node = decl_node; |
| 1006 | entry->data.unionation.layout = layout; | 1009 | entry->data.unionation.layout = layout; |
| 1010 | dwarf_kind = ZigLLVMTag_DW_union_type(); | ||
| 1007 | break; | 1011 | break; |
| 1008 | } | 1012 | } |
| 1009 | 1013 | ||
| ... | @@ -1012,7 +1016,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi | ... | @@ -1012,7 +1016,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 1012 | ImportTableEntry *import = get_scope_import(scope); | 1016 | ImportTableEntry *import = get_scope_import(scope); |
| 1013 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); | 1017 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); |
| 1014 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | 1018 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, |
| 1015 | ZigLLVMTag_DW_structure_type(), name, | 1019 | dwarf_kind, name, |
| 1016 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); | 1020 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); |
| 1017 | 1021 | ||
| 1018 | buf_init_from_str(&entry->name, name); | 1022 | buf_init_from_str(&entry->name, name); |
| ... | @@ -1285,7 +1289,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1285,7 +1289,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1285 | return; | 1289 | return; |
| 1286 | 1290 | ||
| 1287 | resolve_enum_zero_bits(g, enum_type); | 1291 | resolve_enum_zero_bits(g, enum_type); |
| 1288 | if (enum_type->data.enumeration.is_invalid) | 1292 | if (type_is_invalid(enum_type)) |
| 1289 | return; | 1293 | return; |
| 1290 | 1294 | ||
| 1291 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | 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,7 +1838,140 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1834 | } | 1838 | } |
| 1835 | 1839 | ||
| 1836 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | 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 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | 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,7 +2010,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1873 | type_enum_field->value = i; | 2010 | type_enum_field->value = i; |
| 1874 | 2011 | ||
| 1875 | type_ensure_zero_bits_known(g, field_type); | 2012 | type_ensure_zero_bits_known(g, field_type); |
| 1876 | if (field_type->id == TypeTableEntryIdInvalid) { | 2013 | if (type_is_invalid(field_type)) { |
| 1877 | enum_type->data.enumeration.is_invalid = true; | 2014 | enum_type->data.enumeration.is_invalid = true; |
| 1878 | continue; | 2015 | continue; |
| 1879 | } | 2016 | } |
| ... | @@ -1980,7 +2117,66 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1980,7 +2117,66 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 1980 | } | 2117 | } |
| 1981 | 2118 | ||
| 1982 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | 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 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { | 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,6 +3047,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 2851 | return nullptr; | 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 | static bool is_container(TypeTableEntry *type_entry) { | 3062 | static bool is_container(TypeTableEntry *type_entry) { |
| 2855 | switch (type_entry->id) { | 3063 | switch (type_entry->id) { |
| 2856 | case TypeTableEntryIdInvalid: | 3064 | case TypeTableEntryIdInvalid: |
| ... | @@ -4703,6 +4911,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { | ... | @@ -4703,6 +4911,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 4703 | return &value->data.x_array.s_none.parent; | 4911 | return &value->data.x_array.s_none.parent; |
| 4704 | } else if (type_entry->id == TypeTableEntryIdStruct) { | 4912 | } else if (type_entry->id == TypeTableEntryIdStruct) { |
| 4705 | return &value->data.x_struct.parent; | 4913 | return &value->data.x_struct.parent; |
| 4914 | } else if (type_entry->id == TypeTableEntryIdUnion) { | ||
| 4915 | return &value->data.x_union.parent; | ||
| 4706 | } | 4916 | } |
| 4707 | return nullptr; | 4917 | return nullptr; |
| 4708 | } | 4918 | } |
| ... | @@ -4914,7 +5124,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -4914,7 +5124,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 4914 | assert(type_entry->data.enumeration.abi_alignment != 0); | 5124 | assert(type_entry->data.enumeration.abi_alignment != 0); |
| 4915 | return type_entry->data.enumeration.abi_alignment; | 5125 | return type_entry->data.enumeration.abi_alignment; |
| 4916 | } else if (type_entry->id == TypeTableEntryIdUnion) { | 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 | } else if (type_entry->id == TypeTableEntryIdOpaque) { | 5129 | } else if (type_entry->id == TypeTableEntryIdOpaque) { |
| 4919 | return 1; | 5130 | return 1; |
| 4920 | } else { | 5131 | } else { |
src/analyze.hpp+1| ... | @@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); | ... | @@ -63,6 +63,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry); |
| 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); | 63 | TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name); |
| 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); | 64 | ScopeDecls *get_container_scope(TypeTableEntry *type_entry); |
| 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); | 65 | TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name); |
| 66 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name); | ||
| 66 | bool is_container_ref(TypeTableEntry *type_entry); | 67 | bool is_container_ref(TypeTableEntry *type_entry); |
| 67 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); | 68 | void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node); |
| 68 | void scan_import(CodeGen *g, ImportTableEntry *import); | 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,6 +2393,27 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl |
| 2393 | return bitcasted_union_field_ptr; | 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 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { | 2417 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { |
| 2397 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; | 2418 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; |
| 2398 | size_t len = tok->end - tok->start - 2; | 2419 | size_t len = tok->end - tok->start - 2; |
| ... | @@ -3365,6 +3386,25 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, | ... | @@ -3365,6 +3386,25 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 3365 | return instruction->tmp_ptr; | 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 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, | 3408 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, |
| 3369 | IrInstructionContainerInitList *instruction) | 3409 | IrInstructionContainerInitList *instruction) |
| 3370 | { | 3410 | { |
| ... | @@ -3486,6 +3526,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3486,6 +3526,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3486 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); | 3526 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3487 | case IrInstructionIdEnumFieldPtr: | 3527 | case IrInstructionIdEnumFieldPtr: |
| 3488 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); | 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 | case IrInstructionIdAsm: | 3531 | case IrInstructionIdAsm: |
| 3490 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); | 3532 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 3491 | case IrInstructionIdTestNonNull: | 3533 | case IrInstructionIdTestNonNull: |
| ... | @@ -3544,6 +3586,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3544,6 +3586,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3544 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); | 3586 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); |
| 3545 | case IrInstructionIdStructInit: | 3587 | case IrInstructionIdStructInit: |
| 3546 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); | 3588 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3589 | case IrInstructionIdUnionInit: | ||
| 3590 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | ||
| 3547 | case IrInstructionIdPtrCast: | 3591 | case IrInstructionIdPtrCast: |
| 3548 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); | 3592 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); |
| 3549 | case IrInstructionIdBitCast: | 3593 | case IrInstructionIdBitCast: |
| ... | @@ -3595,6 +3639,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { | ... | @@ -3595,6 +3639,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { |
| 3595 | 3639 | ||
| 3596 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); | 3640 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); |
| 3597 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); | 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 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { | 3644 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 3600 | switch (parent->id) { | 3645 | switch (parent->id) { |
| ... | @@ -3608,6 +3653,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent | ... | @@ -3608,6 +3653,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 3608 | case ConstParentIdArray: | 3653 | case ConstParentIdArray: |
| 3609 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, | 3654 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 3610 | parent->data.p_array.elem_index); | 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 | zig_unreachable(); | 3659 | zig_unreachable(); |
| 3613 | } | 3660 | } |
| ... | @@ -3637,6 +3684,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s | ... | @@ -3637,6 +3684,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 3637 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 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 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { | 3699 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 3641 | switch (const_val->special) { | 3700 | switch (const_val->special) { |
| 3642 | case ConstValSpecialRuntime: | 3701 | case ConstValSpecialRuntime: |
| ... | @@ -3872,10 +3931,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3872,10 +3931,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3872 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); | 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 | case TypeTableEntryIdArray: | 3934 | case TypeTableEntryIdArray: |
| 3880 | { | 3935 | { |
| 3881 | uint64_t len = type_entry->data.array.len; | 3936 | uint64_t len = type_entry->data.array.len; |
| ... | @@ -3898,6 +3953,41 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3898,6 +3953,41 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3898 | return LLVMConstArray(element_type_ref, values, (unsigned)len); | 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 | case TypeTableEntryIdEnum: | 3991 | case TypeTableEntryIdEnum: |
| 3902 | { | 3992 | { |
| 3903 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; | 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,6 +4466,9 @@ static void do_code_gen(CodeGen *g) { |
| 4376 | } else if (instruction->id == IrInstructionIdStructInit) { | 4466 | } else if (instruction->id == IrInstructionIdStructInit) { |
| 4377 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; | 4467 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; |
| 4378 | slot = &struct_init_instruction->tmp_ptr; | 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 | } else if (instruction->id == IrInstructionIdCall) { | 4472 | } else if (instruction->id == IrInstructionIdCall) { |
| 4380 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; | 4473 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; |
| 4381 | slot = &call_instruction->tmp_ptr; | 4474 | slot = &call_instruction->tmp_ptr; |
src/ir.cpp+160-11| ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) | ... | @@ -227,6 +227,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) |
| 227 | return IrInstructionIdEnumFieldPtr; | 227 | return IrInstructionIdEnumFieldPtr; |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) { | ||
| 231 | return IrInstructionIdUnionFieldPtr; | ||
| 232 | } | ||
| 233 | |||
| 230 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { | 234 | static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { |
| 231 | return IrInstructionIdElemPtr; | 235 | return IrInstructionIdElemPtr; |
| 232 | } | 236 | } |
| ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { | ... | @@ -351,6 +355,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { |
| 351 | return IrInstructionIdStructInit; | 355 | return IrInstructionIdStructInit; |
| 352 | } | 356 | } |
| 353 | 357 | ||
| 358 | static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { | ||
| 359 | return IrInstructionIdUnionInit; | ||
| 360 | } | ||
| 361 | |||
| 354 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { | 362 | static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) { |
| 355 | return IrInstructionIdMinValue; | 363 | return IrInstructionIdMinValue; |
| 356 | } | 364 | } |
| ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction | ... | @@ -922,6 +930,27 @@ static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction |
| 922 | return new_instruction; | 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 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, | 954 | static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 926 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, | 955 | FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 927 | bool is_comptime, bool is_inline) | 956 | bool is_comptime, bool is_inline) |
| ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o | ... | @@ -1112,6 +1141,28 @@ static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *o |
| 1112 | return new_instruction; | 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 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { | 1166 | static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { |
| 1116 | IrInstructionUnreachable *unreachable_instruction = | 1167 | IrInstructionUnreachable *unreachable_instruction = |
| 1117 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); | 1168 | ir_build_instruction<IrInstructionUnreachable>(irb, scope, source_node); |
| ... | @@ -2422,6 +2473,13 @@ static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumField | ... | @@ -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 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { | 2483 | static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) { |
| 2426 | switch (index) { | 2484 | switch (index) { |
| 2427 | case 0: return instruction->array_ptr; | 2485 | case 0: return instruction->array_ptr; |
| ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit | ... | @@ -2485,6 +2543,13 @@ static IrInstruction *ir_instruction_structinit_get_dep(IrInstructionStructInit |
| 2485 | return nullptr; | 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 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { | 2553 | static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) { |
| 2489 | return nullptr; | 2554 | return nullptr; |
| 2490 | } | 2555 | } |
| ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3099,6 +3164,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3099 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); | 3164 | return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index); |
| 3100 | case IrInstructionIdEnumFieldPtr: | 3165 | case IrInstructionIdEnumFieldPtr: |
| 3101 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); | 3166 | return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index); |
| 3167 | case IrInstructionIdUnionFieldPtr: | ||
| 3168 | return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index); | ||
| 3102 | case IrInstructionIdElemPtr: | 3169 | case IrInstructionIdElemPtr: |
| 3103 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); | 3170 | return ir_instruction_elemptr_get_dep((IrInstructionElemPtr *) instruction, index); |
| 3104 | case IrInstructionIdVarPtr: | 3171 | case IrInstructionIdVarPtr: |
| ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t | ... | @@ -3117,6 +3184,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t |
| 3117 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); | 3184 | return ir_instruction_containerinitfields_get_dep((IrInstructionContainerInitFields *) instruction, index); |
| 3118 | case IrInstructionIdStructInit: | 3185 | case IrInstructionIdStructInit: |
| 3119 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); | 3186 | return ir_instruction_structinit_get_dep((IrInstructionStructInit *) instruction, index); |
| 3187 | case IrInstructionIdUnionInit: | ||
| 3188 | return ir_instruction_unioninit_get_dep((IrInstructionUnionInit *) instruction, index); | ||
| 3120 | case IrInstructionIdUnreachable: | 3189 | case IrInstructionIdUnreachable: |
| 3121 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); | 3190 | return ir_instruction_unreachable_get_dep((IrInstructionUnreachable *) instruction, index); |
| 3122 | case IrInstructionIdTypeOf: | 3191 | case IrInstructionIdTypeOf: |
| ... | @@ -11417,8 +11486,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, | ... | @@ -11417,8 +11486,20 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 11417 | return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value, true, false); | 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 | ir_add_error_node(ira, field_ptr_instruction->base.source_node, | 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 | return ira->codegen->builtin_types.entry_invalid; | 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,14 +11509,13 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11428 | { | 11509 | { |
| 11429 | TypeTableEntry *bare_type = container_ref_type(container_type); | 11510 | TypeTableEntry *bare_type = container_ref_type(container_type); |
| 11430 | ensure_complete_type(ira->codegen, bare_type); | 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 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); | 11515 | assert(container_ptr->value.type->id == TypeTableEntryIdPointer); |
| 11433 | bool is_const = container_ptr->value.type->data.pointer.is_const; | 11516 | bool is_const = container_ptr->value.type->data.pointer.is_const; |
| 11434 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; | 11517 | bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; |
| 11435 | if (bare_type->id == TypeTableEntryIdStruct) { | 11518 | if (bare_type->id == TypeTableEntryIdStruct) { |
| 11436 | if (bare_type->data.structure.is_invalid) | ||
| 11437 | return ira->codegen->builtin_types.entry_invalid; | ||
| 11438 | |||
| 11439 | TypeStructField *field = find_struct_type_field(bare_type, field_name); | 11519 | TypeStructField *field = find_struct_type_field(bare_type, field_name); |
| 11440 | if (field) { | 11520 | if (field) { |
| 11441 | bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); | 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,9 +11556,6 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11476 | field_ptr_instruction, container_ptr, container_type); | 11556 | field_ptr_instruction, container_ptr, container_type); |
| 11477 | } | 11557 | } |
| 11478 | } else if (bare_type->id == TypeTableEntryIdEnum) { | 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 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); | 11559 | TypeEnumField *field = find_enum_type_field(bare_type, field_name); |
| 11483 | if (field) { | 11560 | if (field) { |
| 11484 | ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); | 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,7 +11566,15 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field |
| 11489 | field_ptr_instruction, container_ptr, container_type); | 11566 | field_ptr_instruction, container_ptr, container_type); |
| 11490 | } | 11567 | } |
| 11491 | } else if (bare_type->id == TypeTableEntryIdUnion) { | 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 | } else { | 11578 | } else { |
| 11494 | zig_unreachable(); | 11579 | zig_unreachable(); |
| 11495 | } | 11580 | } |
| ... | @@ -13033,9 +13118,70 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR | ... | @@ -13033,9 +13118,70 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR |
| 13033 | return ir_analyze_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); | 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 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, | 13179 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 13037 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | 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 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { | 13185 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { |
| 13040 | ir_add_error(ira, instruction, | 13186 | ir_add_error(ira, instruction, |
| 13041 | buf_sprintf("type '%s' does not support struct initialization syntax", | 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,8 +13189,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13043 | return ira->codegen->builtin_types.entry_invalid; | 13189 | return ira->codegen->builtin_types.entry_invalid; |
| 13044 | } | 13190 | } |
| 13045 | 13191 | ||
| 13046 | if (!type_is_complete(container_type)) | 13192 | ensure_complete_type(ira->codegen, container_type); |
| 13047 | resolve_container_type(ira->codegen, container_type); | ||
| 13048 | 13193 | ||
| 13049 | size_t actual_field_count = container_type->data.structure.src_field_count; | 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,7 +13215,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13070 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); | 13215 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); |
| 13071 | if (!type_field) { | 13216 | if (!type_field) { |
| 13072 | ir_add_error_node(ira, field->source_node, | 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 | buf_ptr(field->name), buf_ptr(&container_type->name))); | 13219 | buf_ptr(field->name), buf_ptr(&container_type->name))); |
| 13075 | return ira->codegen->builtin_types.entry_invalid; | 13220 | return ira->codegen->builtin_types.entry_invalid; |
| 13076 | } | 13221 | } |
| ... | @@ -15657,8 +15802,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -15657,8 +15802,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15657 | case IrInstructionIdIntToErr: | 15802 | case IrInstructionIdIntToErr: |
| 15658 | case IrInstructionIdErrToInt: | 15803 | case IrInstructionIdErrToInt: |
| 15659 | case IrInstructionIdStructInit: | 15804 | case IrInstructionIdStructInit: |
| 15805 | case IrInstructionIdUnionInit: | ||
| 15660 | case IrInstructionIdStructFieldPtr: | 15806 | case IrInstructionIdStructFieldPtr: |
| 15661 | case IrInstructionIdEnumFieldPtr: | 15807 | case IrInstructionIdEnumFieldPtr: |
| 15808 | case IrInstructionIdUnionFieldPtr: | ||
| 15662 | case IrInstructionIdInitEnum: | 15809 | case IrInstructionIdInitEnum: |
| 15663 | case IrInstructionIdMaybeWrap: | 15810 | case IrInstructionIdMaybeWrap: |
| 15664 | case IrInstructionIdErrWrapCode: | 15811 | case IrInstructionIdErrWrapCode: |
| ... | @@ -15968,6 +16115,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15968,6 +16115,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15968 | case IrInstructionIdContainerInitList: | 16115 | case IrInstructionIdContainerInitList: |
| 15969 | case IrInstructionIdContainerInitFields: | 16116 | case IrInstructionIdContainerInitFields: |
| 15970 | case IrInstructionIdStructInit: | 16117 | case IrInstructionIdStructInit: |
| 16118 | case IrInstructionIdUnionInit: | ||
| 15971 | case IrInstructionIdFieldPtr: | 16119 | case IrInstructionIdFieldPtr: |
| 15972 | case IrInstructionIdElemPtr: | 16120 | case IrInstructionIdElemPtr: |
| 15973 | case IrInstructionIdVarPtr: | 16121 | case IrInstructionIdVarPtr: |
| ... | @@ -15977,6 +16125,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15977,6 +16125,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15977 | case IrInstructionIdArrayLen: | 16125 | case IrInstructionIdArrayLen: |
| 15978 | case IrInstructionIdStructFieldPtr: | 16126 | case IrInstructionIdStructFieldPtr: |
| 15979 | case IrInstructionIdEnumFieldPtr: | 16127 | case IrInstructionIdEnumFieldPtr: |
| 16128 | case IrInstructionIdUnionFieldPtr: | ||
| 15980 | case IrInstructionIdArrayType: | 16129 | case IrInstructionIdArrayType: |
| 15981 | case IrInstructionIdSliceType: | 16130 | case IrInstructionIdSliceType: |
| 15982 | case IrInstructionIdSizeOf: | 16131 | case IrInstructionIdSizeOf: |
src/ir_print.cpp+22| ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct | ... | @@ -290,6 +290,15 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct |
| 290 | fprintf(irp->f, "} // struct init"); | 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 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { | 302 | static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { |
| 294 | fprintf(irp->f, "unreachable"); | 303 | fprintf(irp->f, "unreachable"); |
| 295 | } | 304 | } |
| ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins | ... | @@ -359,6 +368,13 @@ static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *ins |
| 359 | fprintf(irp->f, ")"); | 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 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { | 378 | static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) { |
| 363 | fprintf(irp->f, "@setDebugSafety("); | 379 | fprintf(irp->f, "@setDebugSafety("); |
| 364 | ir_print_other_instruction(irp, instruction->scope_value); | 380 | ir_print_other_instruction(irp, instruction->scope_value); |
| ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1023,6 +1039,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1023 | case IrInstructionIdStructInit: | 1039 | case IrInstructionIdStructInit: |
| 1024 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); | 1040 | ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); |
| 1025 | break; | 1041 | break; |
| 1042 | case IrInstructionIdUnionInit: | ||
| 1043 | ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); | ||
| 1044 | break; | ||
| 1026 | case IrInstructionIdUnreachable: | 1045 | case IrInstructionIdUnreachable: |
| 1027 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); | 1046 | ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); |
| 1028 | break; | 1047 | break; |
| ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { | ... | @@ -1056,6 +1075,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 1056 | case IrInstructionIdEnumFieldPtr: | 1075 | case IrInstructionIdEnumFieldPtr: |
| 1057 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); | 1076 | ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); |
| 1058 | break; | 1077 | break; |
| 1078 | case IrInstructionIdUnionFieldPtr: | ||
| 1079 | ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction); | ||
| 1080 | break; | ||
| 1059 | case IrInstructionIdSetDebugSafety: | 1081 | case IrInstructionIdSetDebugSafety: |
| 1060 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); | 1082 | ir_print_set_debug_safety(irp, (IrInstructionSetDebugSafety *)instruction); |
| 1061 | break; | 1083 | break; |
src/zig_llvm.cpp+4| ... | @@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { | ... | @@ -403,6 +403,10 @@ unsigned ZigLLVMTag_DW_structure_type(void) { |
| 403 | return dwarf::DW_TAG_structure_type; | 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 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { | 410 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) { |
| 407 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); | 411 | DIBuilder *di_builder = new DIBuilder(*unwrap(module), allow_unresolved); |
| 408 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); | 412 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
src/zig_llvm.hpp+1| ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); | ... | @@ -117,6 +117,7 @@ unsigned ZigLLVMEncoding_DW_ATE_signed_char(void); |
| 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); | 117 | unsigned ZigLLVMLang_DW_LANG_C99(void); |
| 118 | unsigned ZigLLVMTag_DW_variable(void); | 118 | unsigned ZigLLVMTag_DW_variable(void); |
| 119 | unsigned ZigLLVMTag_DW_structure_type(void); | 119 | unsigned ZigLLVMTag_DW_structure_type(void); |
| 120 | unsigned ZigLLVMTag_DW_union_type(void); | ||
| 120 | 121 | ||
| 121 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | 122 | ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
| 122 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | 123 | void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
test/cases/union.zig+13| ... | @@ -31,3 +31,16 @@ test "unions embedded in aggregate types" { | ... | @@ -31,3 +31,16 @@ test "unions embedded in aggregate types" { |
| 31 | else => unreachable, | 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,8 +389,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 389 | \\ const y = a.bar; | 389 | \\ const y = a.bar; |
| 390 | \\} | 390 | \\} |
| 391 | , | 391 | , |
| 392 | ".tmp_source.zig:4:6: error: no member named 'foo' 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 'A'"); | 393 | ".tmp_source.zig:5:16: error: no member named 'bar' in struct 'A'"); |
| 394 | 394 | ||
| 395 | cases.add("redefinition of struct", | 395 | cases.add("redefinition of struct", |
| 396 | \\const A = struct { x : i32, }; | 396 | \\const A = struct { x : i32, }; |
| ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { | ... | @@ -454,7 +454,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) { |
| 454 | \\ .foo = 42, | 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 | cases.add("invalid break expression", | 459 | cases.add("invalid break expression", |
| 460 | \\export fn f() { | 460 | \\export fn f() { |