| author | |
| committer | |
| log | d1086893829d91d0e1335e14b0434a23ff0e8999 |
| tree | 17e55b50e624ae06a93522a38aba3c0e83edf37e |
| parent | 7a74dbadd79d2b26a449027dd83753ae4d2a8032 |
| parent | 1473eb9ae0196db729716aa0d29f5ce263412307 |
closes #14412 files changed, 799 insertions(+), 26 deletions(-)
doc/langref.html.in+7| ... | @@ -75,6 +75,7 @@ | ... | @@ -75,6 +75,7 @@ |
| 75 | <li><a href="#slices">Slices</a></li> | 75 | <li><a href="#slices">Slices</a></li> |
| 76 | <li><a href="#struct">struct</a></li> | 76 | <li><a href="#struct">struct</a></li> |
| 77 | <li><a href="#enum">enum</a></li> | 77 | <li><a href="#enum">enum</a></li> |
| 78 | <li><a href="#union">union</a></li> | ||
| 78 | <li><a href="#switch">switch</a></li> | 79 | <li><a href="#switch">switch</a></li> |
| 79 | <li><a href="#while">while</a></li> | 80 | <li><a href="#while">while</a></li> |
| 80 | <li><a href="#for">for</a></li> | 81 | <li><a href="#for">for</a></li> |
| ... | @@ -209,6 +210,7 @@ | ... | @@ -209,6 +210,7 @@ |
| 209 | <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> | 210 | <li><a href="#undef-invalid-error-code">Invalid Error Code</a></li> |
| 210 | <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> | 211 | <li><a href="#undef-invalid-enum-cast">Invalid Enum Cast</a></li> |
| 211 | <li><a href="#undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</a></li> | 212 | <li><a href="#undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</a></li> |
| 213 | <li><a href="#undef-bad-union-field">Wrong Union Field Access</a></li> | ||
| 212 | </ul> | 214 | </ul> |
| 213 | </li> | 215 | </li> |
| 214 | <li><a href="#memory">Memory</a></li> | 216 | <li><a href="#memory">Memory</a></li> |
| ... | @@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre> | ... | @@ -2189,6 +2191,8 @@ Test 4/4 enum builtins...OK</code></pre> |
| 2189 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> | 2191 | <li><a href="#builtin-enumTagName">@enumTagName</a></li> |
| 2190 | <li><a href="#builtin-memberCount">@memberCount</a></li> | 2192 | <li><a href="#builtin-memberCount">@memberCount</a></li> |
| 2191 | </ul> | 2193 | </ul> |
| 2194 | <h2 id="union">union</h2> | ||
| 2195 | <p>TODO union documentation</p> | ||
| 2192 | <h2 id="switch">switch</h2> | 2196 | <h2 id="switch">switch</h2> |
| 2193 | <pre><code class="zig">const assert = @import("std").debug.assert; | 2197 | <pre><code class="zig">const assert = @import("std").debug.assert; |
| 2194 | const builtin = @import("builtin"); | 2198 | const builtin = @import("builtin"); |
| ... | @@ -5117,6 +5121,9 @@ comptime { | ... | @@ -5117,6 +5121,9 @@ comptime { |
| 5117 | <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> | 5121 | <h3 id="undef-incorrect-pointer-alignment">Incorrect Pointer Alignment</h3> |
| 5118 | <p>TODO</p> | 5122 | <p>TODO</p> |
| 5119 | 5123 | ||
| 5124 | <h3 id="undef-bad-union-field">Wrong Union Field Access</h3> | ||
| 5125 | <p>TODO</p> | ||
| 5126 | |||
| 5120 | <h2 id="memory">Memory</h2> | 5127 | <h2 id="memory">Memory</h2> |
| 5121 | <p>TODO: explain no default allocator in zig</p> | 5128 | <p>TODO: explain no default allocator in zig</p> |
| 5122 | <p>TODO: show how to use the allocator interface</p> | 5129 | <p>TODO: show how to use the allocator interface</p> |
src/all_types.hpp+52-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,12 @@ struct ConstStructValue { | ... | @@ -100,6 +104,12 @@ struct ConstStructValue { |
| 100 | ConstParent parent; | 104 | ConstParent parent; |
| 101 | }; | 105 | }; |
| 102 | 106 | ||
| 107 | struct ConstUnionValue { | ||
| 108 | uint64_t tag; | ||
| 109 | ConstExprValue *payload; | ||
| 110 | ConstParent parent; | ||
| 111 | }; | ||
| 112 | |||
| 103 | enum ConstArraySpecial { | 113 | enum ConstArraySpecial { |
| 104 | ConstArraySpecialNone, | 114 | ConstArraySpecialNone, |
| 105 | ConstArraySpecialUndef, | 115 | ConstArraySpecialUndef, |
| ... | @@ -238,6 +248,7 @@ struct ConstExprValue { | ... | @@ -238,6 +248,7 @@ struct ConstExprValue { |
| 238 | ErrorTableEntry *x_pure_err; | 248 | ErrorTableEntry *x_pure_err; |
| 239 | ConstEnumValue x_enum; | 249 | ConstEnumValue x_enum; |
| 240 | ConstStructValue x_struct; | 250 | ConstStructValue x_struct; |
| 251 | ConstUnionValue x_union; | ||
| 241 | ConstArrayValue x_array; | 252 | ConstArrayValue x_array; |
| 242 | ConstPtrValue x_ptr; | 253 | ConstPtrValue x_ptr; |
| 243 | ImportTableEntry *x_import; | 254 | ImportTableEntry *x_import; |
| ... | @@ -336,6 +347,13 @@ struct TypeEnumField { | ... | @@ -336,6 +347,13 @@ struct TypeEnumField { |
| 336 | uint32_t gen_index; | 347 | uint32_t gen_index; |
| 337 | }; | 348 | }; |
| 338 | 349 | ||
| 350 | struct TypeUnionField { | ||
| 351 | Buf *name; | ||
| 352 | TypeTableEntry *type_entry; | ||
| 353 | uint32_t value; | ||
| 354 | uint32_t gen_index; | ||
| 355 | }; | ||
| 356 | |||
| 339 | enum NodeType { | 357 | enum NodeType { |
| 340 | NodeTypeRoot, | 358 | NodeTypeRoot, |
| 341 | NodeTypeFnProto, | 359 | NodeTypeFnProto, |
| ... | @@ -1021,14 +1039,19 @@ struct TypeTableEntryEnumTag { | ... | @@ -1021,14 +1039,19 @@ struct TypeTableEntryEnumTag { |
| 1021 | LLVMValueRef name_table; | 1039 | LLVMValueRef name_table; |
| 1022 | }; | 1040 | }; |
| 1023 | 1041 | ||
| 1042 | uint32_t type_ptr_hash(const TypeTableEntry *ptr); | ||
| 1043 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b); | ||
| 1044 | |||
| 1024 | struct TypeTableEntryUnion { | 1045 | struct TypeTableEntryUnion { |
| 1025 | AstNode *decl_node; | 1046 | AstNode *decl_node; |
| 1026 | ContainerLayout layout; | 1047 | ContainerLayout layout; |
| 1027 | uint32_t src_field_count; | 1048 | uint32_t src_field_count; |
| 1028 | uint32_t gen_field_count; | 1049 | uint32_t gen_field_count; |
| 1029 | TypeStructField *fields; | 1050 | TypeUnionField *fields; |
| 1030 | uint64_t size_bytes; | ||
| 1031 | bool is_invalid; // true if any fields are invalid | 1051 | bool is_invalid; // true if any fields are invalid |
| 1052 | TypeTableEntry *tag_type; | ||
| 1053 | LLVMTypeRef union_type_ref; | ||
| 1054 | |||
| 1032 | ScopeDecls *decls_scope; | 1055 | ScopeDecls *decls_scope; |
| 1033 | 1056 | ||
| 1034 | // set this flag temporarily to detect infinite loops | 1057 | // set this flag temporarily to detect infinite loops |
| ... | @@ -1039,6 +1062,13 @@ struct TypeTableEntryUnion { | ... | @@ -1039,6 +1062,13 @@ struct TypeTableEntryUnion { |
| 1039 | 1062 | ||
| 1040 | bool zero_bits_loop_flag; | 1063 | bool zero_bits_loop_flag; |
| 1041 | bool zero_bits_known; | 1064 | bool zero_bits_known; |
| 1065 | uint32_t abi_alignment; // also figured out with zero_bits pass | ||
| 1066 | |||
| 1067 | size_t gen_union_index; | ||
| 1068 | size_t gen_tag_index; | ||
| 1069 | |||
| 1070 | uint32_t union_size_bytes; | ||
| 1071 | TypeTableEntry *most_aligned_union_member; | ||
| 1042 | }; | 1072 | }; |
| 1043 | 1073 | ||
| 1044 | struct FnGenParamInfo { | 1074 | struct FnGenParamInfo { |
| ... | @@ -1287,6 +1317,7 @@ enum PanicMsgId { | ... | @@ -1287,6 +1317,7 @@ enum PanicMsgId { |
| 1287 | PanicMsgIdUnwrapMaybeFail, | 1317 | PanicMsgIdUnwrapMaybeFail, |
| 1288 | PanicMsgIdInvalidErrorCode, | 1318 | PanicMsgIdInvalidErrorCode, |
| 1289 | PanicMsgIdIncorrectAlignment, | 1319 | PanicMsgIdIncorrectAlignment, |
| 1320 | PanicMsgIdBadUnionField, | ||
| 1290 | 1321 | ||
| 1291 | PanicMsgIdCount, | 1322 | PanicMsgIdCount, |
| 1292 | }; | 1323 | }; |
| ... | @@ -1796,6 +1827,7 @@ enum IrInstructionId { | ... | @@ -1796,6 +1827,7 @@ enum IrInstructionId { |
| 1796 | IrInstructionIdFieldPtr, | 1827 | IrInstructionIdFieldPtr, |
| 1797 | IrInstructionIdStructFieldPtr, | 1828 | IrInstructionIdStructFieldPtr, |
| 1798 | IrInstructionIdEnumFieldPtr, | 1829 | IrInstructionIdEnumFieldPtr, |
| 1830 | IrInstructionIdUnionFieldPtr, | ||
| 1799 | IrInstructionIdElemPtr, | 1831 | IrInstructionIdElemPtr, |
| 1800 | IrInstructionIdVarPtr, | 1832 | IrInstructionIdVarPtr, |
| 1801 | IrInstructionIdCall, | 1833 | IrInstructionIdCall, |
| ... | @@ -1805,6 +1837,7 @@ enum IrInstructionId { | ... | @@ -1805,6 +1837,7 @@ enum IrInstructionId { |
| 1805 | IrInstructionIdContainerInitList, | 1837 | IrInstructionIdContainerInitList, |
| 1806 | IrInstructionIdContainerInitFields, | 1838 | IrInstructionIdContainerInitFields, |
| 1807 | IrInstructionIdStructInit, | 1839 | IrInstructionIdStructInit, |
| 1840 | IrInstructionIdUnionInit, | ||
| 1808 | IrInstructionIdUnreachable, | 1841 | IrInstructionIdUnreachable, |
| 1809 | IrInstructionIdTypeOf, | 1842 | IrInstructionIdTypeOf, |
| 1810 | IrInstructionIdToPtrType, | 1843 | IrInstructionIdToPtrType, |
| ... | @@ -2060,6 +2093,14 @@ struct IrInstructionEnumFieldPtr { | ... | @@ -2060,6 +2093,14 @@ struct IrInstructionEnumFieldPtr { |
| 2060 | bool is_const; | 2093 | bool is_const; |
| 2061 | }; | 2094 | }; |
| 2062 | 2095 | ||
| 2096 | struct IrInstructionUnionFieldPtr { | ||
| 2097 | IrInstruction base; | ||
| 2098 | |||
| 2099 | IrInstruction *union_ptr; | ||
| 2100 | TypeUnionField *field; | ||
| 2101 | bool is_const; | ||
| 2102 | }; | ||
| 2103 | |||
| 2063 | struct IrInstructionElemPtr { | 2104 | struct IrInstructionElemPtr { |
| 2064 | IrInstruction base; | 2105 | IrInstruction base; |
| 2065 | 2106 | ||
| ... | @@ -2150,6 +2191,15 @@ struct IrInstructionStructInit { | ... | @@ -2150,6 +2191,15 @@ struct IrInstructionStructInit { |
| 2150 | LLVMValueRef tmp_ptr; | 2191 | LLVMValueRef tmp_ptr; |
| 2151 | }; | 2192 | }; |
| 2152 | 2193 | ||
| 2194 | struct IrInstructionUnionInit { | ||
| 2195 | IrInstruction base; | ||
| 2196 | |||
| 2197 | TypeTableEntry *union_type; | ||
| 2198 | TypeUnionField *field; | ||
| 2199 | IrInstruction *init_value; | ||
| 2200 | LLVMValueRef tmp_ptr; | ||
| 2201 | }; | ||
| 2202 | |||
| 2153 | struct IrInstructionUnreachable { | 2203 | struct IrInstructionUnreachable { |
| 2154 | IrInstruction base; | 2204 | IrInstruction base; |
| 2155 | }; | 2205 | }; |
src/analyze.cpp+331-6| ... | @@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi | ... | @@ -1008,11 +1008,12 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi |
| 1008 | } | 1008 | } |
| 1009 | 1009 | ||
| 1010 | size_t line = decl_node ? decl_node->line : 0; | 1010 | size_t line = decl_node ? decl_node->line : 0; |
| 1011 | unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); | ||
| 1011 | 1012 | ||
| 1012 | ImportTableEntry *import = get_scope_import(scope); | 1013 | ImportTableEntry *import = get_scope_import(scope); |
| 1013 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); | 1014 | entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name); |
| 1014 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | 1015 | entry->di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, |
| 1015 | ZigLLVMTag_DW_structure_type(), name, | 1016 | dwarf_kind, name, |
| 1016 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); | 1017 | ZigLLVMFileToScope(import->di_file), import->di_file, (unsigned)(line + 1)); |
| 1017 | 1018 | ||
| 1018 | buf_init_from_str(&entry->name, name); | 1019 | buf_init_from_str(&entry->name, name); |
| ... | @@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1285,7 +1286,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) { |
| 1285 | return; | 1286 | return; |
| 1286 | 1287 | ||
| 1287 | resolve_enum_zero_bits(g, enum_type); | 1288 | resolve_enum_zero_bits(g, enum_type); |
| 1288 | if (enum_type->data.enumeration.is_invalid) | 1289 | if (type_is_invalid(enum_type)) |
| 1289 | return; | 1290 | return; |
| 1290 | 1291 | ||
| 1291 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | 1292 | AstNode *decl_node = enum_type->data.enumeration.decl_node; |
| ... | @@ -1834,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1834,7 +1835,246 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) { |
| 1834 | } | 1835 | } |
| 1835 | 1836 | ||
| 1836 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { | 1837 | static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) { |
| 1837 | zig_panic("TODO"); | 1838 | assert(union_type->id == TypeTableEntryIdUnion); |
| 1839 | |||
| 1840 | if (union_type->data.unionation.complete) | ||
| 1841 | return; | ||
| 1842 | |||
| 1843 | resolve_union_zero_bits(g, union_type); | ||
| 1844 | if (type_is_invalid(union_type)) | ||
| 1845 | return; | ||
| 1846 | |||
| 1847 | AstNode *decl_node = union_type->data.unionation.decl_node; | ||
| 1848 | |||
| 1849 | if (union_type->data.unionation.embedded_in_current) { | ||
| 1850 | if (!union_type->data.unionation.reported_infinite_err) { | ||
| 1851 | union_type->data.unionation.reported_infinite_err = true; | ||
| 1852 | add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | ||
| 1853 | } | ||
| 1854 | return; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | assert(!union_type->data.unionation.zero_bits_loop_flag); | ||
| 1858 | assert(decl_node->type == NodeTypeContainerDecl); | ||
| 1859 | assert(union_type->di_type); | ||
| 1860 | |||
| 1861 | uint32_t field_count = union_type->data.unionation.src_field_count; | ||
| 1862 | |||
| 1863 | assert(union_type->data.unionation.fields); | ||
| 1864 | |||
| 1865 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; | ||
| 1866 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); | ||
| 1867 | |||
| 1868 | TypeTableEntry *most_aligned_union_member = nullptr; | ||
| 1869 | uint64_t size_of_most_aligned_member_in_bits = 0; | ||
| 1870 | uint64_t biggest_align_in_bits = 0; | ||
| 1871 | uint64_t biggest_size_in_bits = 0; | ||
| 1872 | |||
| 1873 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | ||
| 1874 | ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count); | ||
| 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 | di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i); | ||
| 1897 | |||
| 1898 | uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref); | ||
| 1899 | uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref); | ||
| 1900 | |||
| 1901 | assert(store_size_in_bits > 0); | ||
| 1902 | assert(abi_align_in_bits > 0); | ||
| 1903 | |||
| 1904 | union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder, | ||
| 1905 | ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name), | ||
| 1906 | import->di_file, (unsigned)(field_node->line + 1), | ||
| 1907 | store_size_in_bits, | ||
| 1908 | abi_align_in_bits, | ||
| 1909 | 0, | ||
| 1910 | 0, field_type->di_type); | ||
| 1911 | |||
| 1912 | biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits); | ||
| 1913 | |||
| 1914 | if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) { | ||
| 1915 | most_aligned_union_member = field_type; | ||
| 1916 | biggest_align_in_bits = abi_align_in_bits; | ||
| 1917 | size_of_most_aligned_member_in_bits = store_size_in_bits; | ||
| 1918 | } | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | // unset temporary flag | ||
| 1922 | union_type->data.unionation.embedded_in_current = false; | ||
| 1923 | union_type->data.unionation.complete = true; | ||
| 1924 | union_type->data.unionation.union_size_bytes = biggest_size_in_bits / 8; | ||
| 1925 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; | ||
| 1926 | |||
| 1927 | if (union_type->data.unionation.is_invalid) | ||
| 1928 | return; | ||
| 1929 | |||
| 1930 | if (union_type->zero_bits) { | ||
| 1931 | union_type->type_ref = LLVMVoidType(); | ||
| 1932 | |||
| 1933 | uint64_t debug_size_in_bits = 0; | ||
| 1934 | uint64_t debug_align_in_bits = 0; | ||
| 1935 | ZigLLVMDIType **di_root_members = nullptr; | ||
| 1936 | size_t debug_member_count = 0; | ||
| 1937 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | ||
| 1938 | ZigLLVMFileToScope(import->di_file), | ||
| 1939 | buf_ptr(&union_type->name), | ||
| 1940 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 1941 | debug_size_in_bits, | ||
| 1942 | debug_align_in_bits, | ||
| 1943 | 0, di_root_members, (int)debug_member_count, 0, ""); | ||
| 1944 | |||
| 1945 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | ||
| 1946 | union_type->di_type = replacement_di_type; | ||
| 1947 | return; | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | assert(most_aligned_union_member != nullptr); | ||
| 1951 | |||
| 1952 | bool want_safety = auto_layout && (field_count >= 2); | ||
| 1953 | uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits; | ||
| 1954 | |||
| 1955 | |||
| 1956 | if (!want_safety) { | ||
| 1957 | if (padding_in_bits > 0) { | ||
| 1958 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | ||
| 1959 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | ||
| 1960 | LLVMTypeRef union_element_types[] = { | ||
| 1961 | most_aligned_union_member->type_ref, | ||
| 1962 | padding_array->type_ref, | ||
| 1963 | }; | ||
| 1964 | LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false); | ||
| 1965 | } else { | ||
| 1966 | LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false); | ||
| 1967 | } | ||
| 1968 | union_type->data.unionation.union_type_ref = union_type->type_ref; | ||
| 1969 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | ||
| 1970 | union_type->data.unionation.gen_union_index = SIZE_MAX; | ||
| 1971 | |||
| 1972 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits); | ||
| 1973 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits); | ||
| 1974 | |||
| 1975 | // create debug type for union | ||
| 1976 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | ||
| 1977 | ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name), | ||
| 1978 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 1979 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | ||
| 1980 | gen_field_count, 0, ""); | ||
| 1981 | |||
| 1982 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | ||
| 1983 | union_type->di_type = replacement_di_type; | ||
| 1984 | return; | ||
| 1985 | } | ||
| 1986 | |||
| 1987 | LLVMTypeRef union_type_ref; | ||
| 1988 | if (padding_in_bits > 0) { | ||
| 1989 | TypeTableEntry *u8_type = get_int_type(g, false, 8); | ||
| 1990 | TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8); | ||
| 1991 | LLVMTypeRef union_element_types[] = { | ||
| 1992 | most_aligned_union_member->type_ref, | ||
| 1993 | padding_array->type_ref, | ||
| 1994 | }; | ||
| 1995 | union_type_ref = LLVMStructType(union_element_types, 2, false); | ||
| 1996 | } else { | ||
| 1997 | union_type_ref = most_aligned_union_member->type_ref; | ||
| 1998 | } | ||
| 1999 | union_type->data.unionation.union_type_ref = union_type_ref; | ||
| 2000 | |||
| 2001 | assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits); | ||
| 2002 | assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits); | ||
| 2003 | |||
| 2004 | // create llvm type for root struct | ||
| 2005 | TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1); | ||
| 2006 | TypeTableEntry *tag_type_entry = tag_int_type; | ||
| 2007 | union_type->data.unionation.tag_type = tag_type_entry; | ||
| 2008 | uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref); | ||
| 2009 | |||
| 2010 | if (align_of_tag_in_bits >= biggest_align_in_bits) { | ||
| 2011 | union_type->data.unionation.gen_tag_index = 0; | ||
| 2012 | union_type->data.unionation.gen_union_index = 1; | ||
| 2013 | } else { | ||
| 2014 | union_type->data.unionation.gen_union_index = 0; | ||
| 2015 | union_type->data.unionation.gen_tag_index = 1; | ||
| 2016 | } | ||
| 2017 | |||
| 2018 | LLVMTypeRef root_struct_element_types[2]; | ||
| 2019 | root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref; | ||
| 2020 | root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref; | ||
| 2021 | LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false); | ||
| 2022 | |||
| 2023 | |||
| 2024 | // create debug type for root struct | ||
| 2025 | |||
| 2026 | // create debug type for tag | ||
| 2027 | uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref); | ||
| 2028 | uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref); | ||
| 2029 | ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder, | ||
| 2030 | ZigLLVMTypeToScope(union_type->di_type), "AnonEnum", | ||
| 2031 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 2032 | tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count, | ||
| 2033 | tag_type_entry->di_type, ""); | ||
| 2034 | |||
| 2035 | // create debug type for union | ||
| 2036 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | ||
| 2037 | ZigLLVMTypeToScope(union_type->di_type), "AnonUnion", | ||
| 2038 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 2039 | biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types, | ||
| 2040 | gen_field_count, 0, ""); | ||
| 2041 | |||
| 2042 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref, | ||
| 2043 | union_type->data.unionation.gen_union_index); | ||
| 2044 | uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref, | ||
| 2045 | union_type->data.unionation.gen_tag_index); | ||
| 2046 | |||
| 2047 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | ||
| 2048 | ZigLLVMTypeToScope(union_type->di_type), "union_field", | ||
| 2049 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 2050 | biggest_size_in_bits, | ||
| 2051 | biggest_align_in_bits, | ||
| 2052 | union_offset_in_bits, | ||
| 2053 | 0, union_di_type); | ||
| 2054 | ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | ||
| 2055 | ZigLLVMTypeToScope(union_type->di_type), "tag_field", | ||
| 2056 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 2057 | tag_debug_size_in_bits, | ||
| 2058 | tag_debug_align_in_bits, | ||
| 2059 | tag_offset_in_bits, | ||
| 2060 | 0, tag_di_type); | ||
| 2061 | |||
| 2062 | ZigLLVMDIType *di_root_members[2]; | ||
| 2063 | di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type; | ||
| 2064 | di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type; | ||
| 2065 | |||
| 2066 | uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref); | ||
| 2067 | uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref); | ||
| 2068 | ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder, | ||
| 2069 | ZigLLVMFileToScope(import->di_file), | ||
| 2070 | buf_ptr(&union_type->name), | ||
| 2071 | import->di_file, (unsigned)(decl_node->line + 1), | ||
| 2072 | debug_size_in_bits, | ||
| 2073 | debug_align_in_bits, | ||
| 2074 | 0, nullptr, di_root_members, 2, 0, nullptr, ""); | ||
| 2075 | |||
| 2076 | ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type); | ||
| 2077 | union_type->di_type = replacement_di_type; | ||
| 1838 | } | 2078 | } |
| 1839 | 2079 | ||
| 1840 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | 2080 | static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| ... | @@ -1873,7 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { | ... | @@ -1873,7 +2113,7 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) { |
| 1873 | type_enum_field->value = i; | 2113 | type_enum_field->value = i; |
| 1874 | 2114 | ||
| 1875 | type_ensure_zero_bits_known(g, field_type); | 2115 | type_ensure_zero_bits_known(g, field_type); |
| 1876 | if (field_type->id == TypeTableEntryIdInvalid) { | 2116 | if (type_is_invalid(field_type)) { |
| 1877 | enum_type->data.enumeration.is_invalid = true; | 2117 | enum_type->data.enumeration.is_invalid = true; |
| 1878 | continue; | 2118 | continue; |
| 1879 | } | 2119 | } |
| ... | @@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { | ... | @@ -1980,7 +2220,69 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) { |
| 1980 | } | 2220 | } |
| 1981 | 2221 | ||
| 1982 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { | 2222 | static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) { |
| 1983 | zig_panic("TODO resolve_union_zero_bits"); | 2223 | assert(union_type->id == TypeTableEntryIdUnion); |
| 2224 | |||
| 2225 | if (union_type->data.unionation.zero_bits_known) | ||
| 2226 | return; | ||
| 2227 | |||
| 2228 | if (union_type->data.unionation.zero_bits_loop_flag) { | ||
| 2229 | union_type->data.unionation.zero_bits_known = true; | ||
| 2230 | return; | ||
| 2231 | } | ||
| 2232 | |||
| 2233 | union_type->data.unionation.zero_bits_loop_flag = true; | ||
| 2234 | |||
| 2235 | AstNode *decl_node = union_type->data.unionation.decl_node; | ||
| 2236 | assert(decl_node->type == NodeTypeContainerDecl); | ||
| 2237 | assert(union_type->di_type); | ||
| 2238 | |||
| 2239 | assert(!union_type->data.unionation.fields); | ||
| 2240 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | ||
| 2241 | union_type->data.unionation.src_field_count = field_count; | ||
| 2242 | union_type->data.unionation.fields = allocate<TypeUnionField>(field_count); | ||
| 2243 | |||
| 2244 | uint32_t biggest_align_bytes = 0; | ||
| 2245 | |||
| 2246 | Scope *scope = &union_type->data.unionation.decls_scope->base; | ||
| 2247 | |||
| 2248 | uint32_t gen_field_index = 0; | ||
| 2249 | for (uint32_t i = 0; i < field_count; i += 1) { | ||
| 2250 | AstNode *field_node = decl_node->data.container_decl.fields.at(i); | ||
| 2251 | TypeUnionField *type_union_field = &union_type->data.unionation.fields[i]; | ||
| 2252 | type_union_field->name = field_node->data.struct_field.name; | ||
| 2253 | TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | ||
| 2254 | type_union_field->type_entry = field_type; | ||
| 2255 | type_union_field->value = i; | ||
| 2256 | |||
| 2257 | type_ensure_zero_bits_known(g, field_type); | ||
| 2258 | if (type_is_invalid(field_type)) { | ||
| 2259 | union_type->data.unionation.is_invalid = true; | ||
| 2260 | continue; | ||
| 2261 | } | ||
| 2262 | |||
| 2263 | if (!type_has_bits(field_type)) | ||
| 2264 | continue; | ||
| 2265 | |||
| 2266 | type_union_field->gen_index = gen_field_index; | ||
| 2267 | gen_field_index += 1; | ||
| 2268 | |||
| 2269 | uint32_t field_align_bytes = get_abi_alignment(g, field_type); | ||
| 2270 | if (field_align_bytes > biggest_align_bytes) { | ||
| 2271 | biggest_align_bytes = field_align_bytes; | ||
| 2272 | } | ||
| 2273 | } | ||
| 2274 | |||
| 2275 | bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto); | ||
| 2276 | |||
| 2277 | union_type->data.unionation.zero_bits_loop_flag = false; | ||
| 2278 | union_type->data.unionation.gen_field_count = gen_field_index; | ||
| 2279 | union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout)); | ||
| 2280 | union_type->data.unionation.zero_bits_known = true; | ||
| 2281 | |||
| 2282 | // also compute abi_alignment | ||
| 2283 | if (!union_type->zero_bits) { | ||
| 2284 | union_type->data.unionation.abi_alignment = biggest_align_bytes; | ||
| 2285 | } | ||
| 1984 | } | 2286 | } |
| 1985 | 2287 | ||
| 1986 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { | 2288 | static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) { |
| ... | @@ -2851,6 +3153,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { | ... | @@ -2851,6 +3153,18 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) { |
| 2851 | return nullptr; | 3153 | return nullptr; |
| 2852 | } | 3154 | } |
| 2853 | 3155 | ||
| 3156 | TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) { | ||
| 3157 | assert(type_entry->id == TypeTableEntryIdUnion); | ||
| 3158 | assert(type_entry->data.unionation.complete); | ||
| 3159 | for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) { | ||
| 3160 | TypeUnionField *field = &type_entry->data.unionation.fields[i]; | ||
| 3161 | if (buf_eql_buf(field->name, name)) { | ||
| 3162 | return field; | ||
| 3163 | } | ||
| 3164 | } | ||
| 3165 | return nullptr; | ||
| 3166 | } | ||
| 3167 | |||
| 2854 | static bool is_container(TypeTableEntry *type_entry) { | 3168 | static bool is_container(TypeTableEntry *type_entry) { |
| 2855 | switch (type_entry->id) { | 3169 | switch (type_entry->id) { |
| 2856 | case TypeTableEntryIdInvalid: | 3170 | case TypeTableEntryIdInvalid: |
| ... | @@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { | ... | @@ -4703,6 +5017,8 @@ ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { |
| 4703 | return &value->data.x_array.s_none.parent; | 5017 | return &value->data.x_array.s_none.parent; |
| 4704 | } else if (type_entry->id == TypeTableEntryIdStruct) { | 5018 | } else if (type_entry->id == TypeTableEntryIdStruct) { |
| 4705 | return &value->data.x_struct.parent; | 5019 | return &value->data.x_struct.parent; |
| 5020 | } else if (type_entry->id == TypeTableEntryIdUnion) { | ||
| 5021 | return &value->data.x_union.parent; | ||
| 4706 | } | 5022 | } |
| 4707 | return nullptr; | 5023 | return nullptr; |
| 4708 | } | 5024 | } |
| ... | @@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { | ... | @@ -4914,7 +5230,8 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) { |
| 4914 | assert(type_entry->data.enumeration.abi_alignment != 0); | 5230 | assert(type_entry->data.enumeration.abi_alignment != 0); |
| 4915 | return type_entry->data.enumeration.abi_alignment; | 5231 | return type_entry->data.enumeration.abi_alignment; |
| 4916 | } else if (type_entry->id == TypeTableEntryIdUnion) { | 5232 | } else if (type_entry->id == TypeTableEntryIdUnion) { |
| 4917 | zig_panic("TODO"); | 5233 | assert(type_entry->data.unionation.abi_alignment != 0); |
| 5234 | return type_entry->data.unionation.abi_alignment; | ||
| 4918 | } else if (type_entry->id == TypeTableEntryIdOpaque) { | 5235 | } else if (type_entry->id == TypeTableEntryIdOpaque) { |
| 4919 | return 1; | 5236 | return 1; |
| 4920 | } else { | 5237 | } else { |
| ... | @@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) { | ... | @@ -4929,3 +5246,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) { |
| 4929 | } | 5246 | } |
| 4930 | return g->align_amt_type; | 5247 | return g->align_amt_type; |
| 4931 | } | 5248 | } |
| 5249 | |||
| 5250 | uint32_t type_ptr_hash(const TypeTableEntry *ptr) { | ||
| 5251 | return hash_ptr((void*)ptr); | ||
| 5252 | } | ||
| 5253 | |||
| 5254 | bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) { | ||
| 5255 | return a == b; | ||
| 5256 | } |
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+153-4| ... | @@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { | ... | @@ -810,6 +810,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { |
| 810 | return buf_create_from_str("invalid error code"); | 810 | return buf_create_from_str("invalid error code"); |
| 811 | case PanicMsgIdIncorrectAlignment: | 811 | case PanicMsgIdIncorrectAlignment: |
| 812 | return buf_create_from_str("incorrect alignment"); | 812 | return buf_create_from_str("incorrect alignment"); |
| 813 | case PanicMsgIdBadUnionField: | ||
| 814 | return buf_create_from_str("access of inactive union field"); | ||
| 813 | } | 815 | } |
| 814 | zig_unreachable(); | 816 | zig_unreachable(); |
| 815 | } | 817 | } |
| ... | @@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl | ... | @@ -2393,6 +2395,50 @@ static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executabl |
| 2393 | return bitcasted_union_field_ptr; | 2395 | return bitcasted_union_field_ptr; |
| 2394 | } | 2396 | } |
| 2395 | 2397 | ||
| 2398 | static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, | ||
| 2399 | IrInstructionUnionFieldPtr *instruction) | ||
| 2400 | { | ||
| 2401 | TypeTableEntry *union_ptr_type = instruction->union_ptr->value.type; | ||
| 2402 | assert(union_ptr_type->id == TypeTableEntryIdPointer); | ||
| 2403 | TypeTableEntry *union_type = union_ptr_type->data.pointer.child_type; | ||
| 2404 | assert(union_type->id == TypeTableEntryIdUnion); | ||
| 2405 | |||
| 2406 | TypeUnionField *field = instruction->field; | ||
| 2407 | |||
| 2408 | if (!type_has_bits(field->type_entry)) | ||
| 2409 | return nullptr; | ||
| 2410 | |||
| 2411 | LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); | ||
| 2412 | LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); | ||
| 2413 | |||
| 2414 | if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { | ||
| 2415 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, ""); | ||
| 2416 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | ||
| 2417 | return bitcasted_union_field_ptr; | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | if (ir_want_debug_safety(g, &instruction->base)) { | ||
| 2421 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); | ||
| 2422 | LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); | ||
| 2423 | LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | ||
| 2424 | field->value, false); | ||
| 2425 | |||
| 2426 | LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk"); | ||
| 2427 | LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail"); | ||
| 2428 | LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, ""); | ||
| 2429 | LLVMBuildCondBr(g->builder, ok_val, ok_block, bad_block); | ||
| 2430 | |||
| 2431 | LLVMPositionBuilderAtEnd(g->builder, bad_block); | ||
| 2432 | gen_debug_safety_crash(g, PanicMsgIdBadUnionField); | ||
| 2433 | |||
| 2434 | LLVMPositionBuilderAtEnd(g->builder, ok_block); | ||
| 2435 | } | ||
| 2436 | |||
| 2437 | LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, ""); | ||
| 2438 | LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); | ||
| 2439 | return bitcasted_union_field_ptr; | ||
| 2440 | } | ||
| 2441 | |||
| 2396 | static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { | 2442 | 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; | 2443 | const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; |
| 2398 | size_t len = tok->end - tok->start - 2; | 2444 | size_t len = tok->end - tok->start - 2; |
| ... | @@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, | ... | @@ -3365,6 +3411,42 @@ static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, |
| 3365 | return instruction->tmp_ptr; | 3411 | return instruction->tmp_ptr; |
| 3366 | } | 3412 | } |
| 3367 | 3413 | ||
| 3414 | static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { | ||
| 3415 | TypeUnionField *type_union_field = instruction->field; | ||
| 3416 | |||
| 3417 | if (!type_has_bits(type_union_field->type_entry)) | ||
| 3418 | return nullptr; | ||
| 3419 | |||
| 3420 | uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); | ||
| 3421 | TypeTableEntry *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, | ||
| 3422 | false, false, field_align_bytes, | ||
| 3423 | 0, 0); | ||
| 3424 | |||
| 3425 | LLVMValueRef uncasted_union_ptr; | ||
| 3426 | // Even if safety is off in this block, if the union type has the safety field, we have to populate it | ||
| 3427 | // correctly. Otherwise safety code somewhere other than here could fail. | ||
| 3428 | TypeTableEntry *union_type = instruction->union_type; | ||
| 3429 | if (union_type->data.unionation.gen_tag_index != SIZE_MAX) { | ||
| 3430 | LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, | ||
| 3431 | union_type->data.unionation.gen_tag_index, ""); | ||
| 3432 | LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref, | ||
| 3433 | type_union_field->value, false); | ||
| 3434 | gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); | ||
| 3435 | |||
| 3436 | uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, | ||
| 3437 | (unsigned)union_type->data.unionation.gen_union_index, ""); | ||
| 3438 | } else { | ||
| 3439 | uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); | ||
| 3440 | } | ||
| 3441 | |||
| 3442 | LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, ptr_type->type_ref, ""); | ||
| 3443 | LLVMValueRef value = ir_llvm_value(g, instruction->init_value); | ||
| 3444 | |||
| 3445 | gen_assign_raw(g, field_ptr, ptr_type, value); | ||
| 3446 | |||
| 3447 | return instruction->tmp_ptr; | ||
| 3448 | } | ||
| 3449 | |||
| 3368 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, | 3450 | static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, |
| 3369 | IrInstructionContainerInitList *instruction) | 3451 | IrInstructionContainerInitList *instruction) |
| 3370 | { | 3452 | { |
| ... | @@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3486,6 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3486 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); | 3568 | return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); |
| 3487 | case IrInstructionIdEnumFieldPtr: | 3569 | case IrInstructionIdEnumFieldPtr: |
| 3488 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); | 3570 | return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); |
| 3571 | case IrInstructionIdUnionFieldPtr: | ||
| 3572 | return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction); | ||
| 3489 | case IrInstructionIdAsm: | 3573 | case IrInstructionIdAsm: |
| 3490 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); | 3574 | return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); |
| 3491 | case IrInstructionIdTestNonNull: | 3575 | case IrInstructionIdTestNonNull: |
| ... | @@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, | ... | @@ -3544,6 +3628,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 3544 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); | 3628 | return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction); |
| 3545 | case IrInstructionIdStructInit: | 3629 | case IrInstructionIdStructInit: |
| 3546 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); | 3630 | return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); |
| 3631 | case IrInstructionIdUnionInit: | ||
| 3632 | return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); | ||
| 3547 | case IrInstructionIdPtrCast: | 3633 | case IrInstructionIdPtrCast: |
| 3548 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); | 3634 | return ir_render_ptr_cast(g, executable, (IrInstructionPtrCast *)instruction); |
| 3549 | case IrInstructionIdBitCast: | 3635 | case IrInstructionIdBitCast: |
| ... | @@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { | ... | @@ -3595,6 +3681,7 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { |
| 3595 | 3681 | ||
| 3596 | static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index); | 3682 | 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); | 3683 | static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index); |
| 3684 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val); | ||
| 3598 | 3685 | ||
| 3599 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { | 3686 | static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) { |
| 3600 | switch (parent->id) { | 3687 | switch (parent->id) { |
| ... | @@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent | ... | @@ -3608,6 +3695,8 @@ static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent |
| 3608 | case ConstParentIdArray: | 3695 | case ConstParentIdArray: |
| 3609 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, | 3696 | return gen_const_ptr_array_recursive(g, parent->data.p_array.array_val, |
| 3610 | parent->data.p_array.elem_index); | 3697 | parent->data.p_array.elem_index); |
| 3698 | case ConstParentIdUnion: | ||
| 3699 | return gen_const_ptr_union_recursive(g, parent->data.p_union.union_val); | ||
| 3611 | } | 3700 | } |
| 3612 | zig_unreachable(); | 3701 | zig_unreachable(); |
| 3613 | } | 3702 | } |
| ... | @@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s | ... | @@ -3637,6 +3726,18 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *s |
| 3637 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | 3726 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); |
| 3638 | } | 3727 | } |
| 3639 | 3728 | ||
| 3729 | static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *union_const_val) { | ||
| 3730 | ConstParent *parent = &union_const_val->data.x_union.parent; | ||
| 3731 | LLVMValueRef base_ptr = gen_parent_ptr(g, union_const_val, parent); | ||
| 3732 | |||
| 3733 | TypeTableEntry *u32 = g->builtin_types.entry_u32; | ||
| 3734 | LLVMValueRef indices[] = { | ||
| 3735 | LLVMConstNull(u32->type_ref), | ||
| 3736 | LLVMConstInt(u32->type_ref, 0, false), | ||
| 3737 | }; | ||
| 3738 | return LLVMConstInBoundsGEP(base_ptr, indices, 2); | ||
| 3739 | } | ||
| 3740 | |||
| 3640 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { | 3741 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 3641 | switch (const_val->special) { | 3742 | switch (const_val->special) { |
| 3642 | case ConstValSpecialRuntime: | 3743 | case ConstValSpecialRuntime: |
| ... | @@ -3872,10 +3973,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3872,10 +3973,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); | 3973 | return LLVMConstNamedStruct(type_entry->type_ref, fields, type_entry->data.structure.gen_field_count); |
| 3873 | } | 3974 | } |
| 3874 | } | 3975 | } |
| 3875 | case TypeTableEntryIdUnion: | ||
| 3876 | { | ||
| 3877 | zig_panic("TODO"); | ||
| 3878 | } | ||
| 3879 | case TypeTableEntryIdArray: | 3976 | case TypeTableEntryIdArray: |
| 3880 | { | 3977 | { |
| 3881 | uint64_t len = type_entry->data.array.len; | 3978 | uint64_t len = type_entry->data.array.len; |
| ... | @@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { | ... | @@ -3898,6 +3995,55 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) { |
| 3898 | return LLVMConstArray(element_type_ref, values, (unsigned)len); | 3995 | return LLVMConstArray(element_type_ref, values, (unsigned)len); |
| 3899 | } | 3996 | } |
| 3900 | } | 3997 | } |
| 3998 | case TypeTableEntryIdUnion: | ||
| 3999 | { | ||
| 4000 | LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref; | ||
| 4001 | ConstExprValue *payload_value = const_val->data.x_union.payload; | ||
| 4002 | assert(payload_value != nullptr); | ||
| 4003 | |||
| 4004 | if (!type_has_bits(payload_value->type)) { | ||
| 4005 | return LLVMGetUndef(union_type_ref); | ||
| 4006 | } | ||
| 4007 | |||
| 4008 | uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref); | ||
| 4009 | uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes; | ||
| 4010 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value); | ||
| 4011 | bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) || | ||
| 4012 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | ||
| 4013 | |||
| 4014 | LLVMValueRef union_value_ref; | ||
| 4015 | { | ||
| 4016 | if (pad_bytes == 0) { | ||
| 4017 | union_value_ref = correctly_typed_value; | ||
| 4018 | } else { | ||
| 4019 | LLVMValueRef fields[2]; | ||
| 4020 | fields[0] = correctly_typed_value; | ||
| 4021 | fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)); | ||
| 4022 | if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) { | ||
| 4023 | union_value_ref = LLVMConstStruct(fields, 2, false); | ||
| 4024 | } else { | ||
| 4025 | union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2); | ||
| 4026 | } | ||
| 4027 | } | ||
| 4028 | } | ||
| 4029 | |||
| 4030 | if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) { | ||
| 4031 | return union_value_ref; | ||
| 4032 | } | ||
| 4033 | |||
| 4034 | LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false); | ||
| 4035 | |||
| 4036 | LLVMValueRef fields[2]; | ||
| 4037 | fields[type_entry->data.unionation.gen_union_index] = union_value_ref; | ||
| 4038 | fields[type_entry->data.unionation.gen_tag_index] = tag_value; | ||
| 4039 | |||
| 4040 | if (make_unnamed_struct) { | ||
| 4041 | return LLVMConstStruct(fields, 2, false); | ||
| 4042 | } else { | ||
| 4043 | return LLVMConstNamedStruct(type_entry->type_ref, fields, 2); | ||
| 4044 | } | ||
| 4045 | |||
| 4046 | } | ||
| 3901 | case TypeTableEntryIdEnum: | 4047 | case TypeTableEntryIdEnum: |
| 3902 | { | 4048 | { |
| 3903 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; | 4049 | LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref; |
| ... | @@ -4376,6 +4522,9 @@ static void do_code_gen(CodeGen *g) { | ... | @@ -4376,6 +4522,9 @@ static void do_code_gen(CodeGen *g) { |
| 4376 | } else if (instruction->id == IrInstructionIdStructInit) { | 4522 | } else if (instruction->id == IrInstructionIdStructInit) { |
| 4377 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; | 4523 | IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; |
| 4378 | slot = &struct_init_instruction->tmp_ptr; | 4524 | slot = &struct_init_instruction->tmp_ptr; |
| 4525 | } else if (instruction->id == IrInstructionIdUnionInit) { | ||
| 4526 | IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; | ||
| 4527 | slot = &union_init_instruction->tmp_ptr; | ||
| 4379 | } else if (instruction->id == IrInstructionIdCall) { | 4528 | } else if (instruction->id == IrInstructionIdCall) { |
| 4380 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; | 4529 | IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; |
| 4381 | slot = &call_instruction->tmp_ptr; | 4530 | slot = &call_instruction->tmp_ptr; |
src/ir.cpp+161-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,71 @@ static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionR | ... | @@ -13033,9 +13118,71 @@ 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.payload = field_val; | ||
| 13162 | out_val->data.x_union.tag = type_field->value; | ||
| 13163 | |||
| 13164 | ConstParent *parent = get_const_val_parent(ira->codegen, field_val); | ||
| 13165 | if (parent != nullptr) { | ||
| 13166 | parent->id = ConstParentIdUnion; | ||
| 13167 | parent->data.p_union.union_val = out_val; | ||
| 13168 | } | ||
| 13169 | |||
| 13170 | return container_type; | ||
| 13171 | } | ||
| 13172 | |||
| 13173 | IrInstruction *new_instruction = ir_build_union_init_from(&ira->new_irb, instruction, | ||
| 13174 | container_type, type_field, casted_field_value); | ||
| 13175 | |||
| 13176 | ir_add_alloca(ira, new_instruction, container_type); | ||
| 13177 | return container_type; | ||
| 13178 | } | ||
| 13179 | |||
| 13036 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, | 13180 | static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, |
| 13037 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) | 13181 | TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) |
| 13038 | { | 13182 | { |
| 13183 | if (container_type->id == TypeTableEntryIdUnion) { | ||
| 13184 | return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, fields); | ||
| 13185 | } | ||
| 13039 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { | 13186 | if (container_type->id != TypeTableEntryIdStruct || is_slice(container_type)) { |
| 13040 | ir_add_error(ira, instruction, | 13187 | ir_add_error(ira, instruction, |
| 13041 | buf_sprintf("type '%s' does not support struct initialization syntax", | 13188 | buf_sprintf("type '%s' does not support struct initialization syntax", |
| ... | @@ -13043,8 +13190,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru | ... | @@ -13043,8 +13190,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13043 | return ira->codegen->builtin_types.entry_invalid; | 13190 | return ira->codegen->builtin_types.entry_invalid; |
| 13044 | } | 13191 | } |
| 13045 | 13192 | ||
| 13046 | if (!type_is_complete(container_type)) | 13193 | ensure_complete_type(ira->codegen, container_type); |
| 13047 | resolve_container_type(ira->codegen, container_type); | ||
| 13048 | 13194 | ||
| 13049 | size_t actual_field_count = container_type->data.structure.src_field_count; | 13195 | size_t actual_field_count = container_type->data.structure.src_field_count; |
| 13050 | 13196 | ||
| ... | @@ -13070,7 +13216,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru | ... | @@ -13070,7 +13216,7 @@ static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstru |
| 13070 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); | 13216 | TypeStructField *type_field = find_struct_type_field(container_type, field->name); |
| 13071 | if (!type_field) { | 13217 | if (!type_field) { |
| 13072 | ir_add_error_node(ira, field->source_node, | 13218 | ir_add_error_node(ira, field->source_node, |
| 13073 | buf_sprintf("no member named '%s' in '%s'", | 13219 | buf_sprintf("no member named '%s' in struct '%s'", |
| 13074 | buf_ptr(field->name), buf_ptr(&container_type->name))); | 13220 | buf_ptr(field->name), buf_ptr(&container_type->name))); |
| 13075 | return ira->codegen->builtin_types.entry_invalid; | 13221 | return ira->codegen->builtin_types.entry_invalid; |
| 13076 | } | 13222 | } |
| ... | @@ -15657,8 +15803,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi | ... | @@ -15657,8 +15803,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi |
| 15657 | case IrInstructionIdIntToErr: | 15803 | case IrInstructionIdIntToErr: |
| 15658 | case IrInstructionIdErrToInt: | 15804 | case IrInstructionIdErrToInt: |
| 15659 | case IrInstructionIdStructInit: | 15805 | case IrInstructionIdStructInit: |
| 15806 | case IrInstructionIdUnionInit: | ||
| 15660 | case IrInstructionIdStructFieldPtr: | 15807 | case IrInstructionIdStructFieldPtr: |
| 15661 | case IrInstructionIdEnumFieldPtr: | 15808 | case IrInstructionIdEnumFieldPtr: |
| 15809 | case IrInstructionIdUnionFieldPtr: | ||
| 15662 | case IrInstructionIdInitEnum: | 15810 | case IrInstructionIdInitEnum: |
| 15663 | case IrInstructionIdMaybeWrap: | 15811 | case IrInstructionIdMaybeWrap: |
| 15664 | case IrInstructionIdErrWrapCode: | 15812 | case IrInstructionIdErrWrapCode: |
| ... | @@ -15968,6 +16116,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15968,6 +16116,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15968 | case IrInstructionIdContainerInitList: | 16116 | case IrInstructionIdContainerInitList: |
| 15969 | case IrInstructionIdContainerInitFields: | 16117 | case IrInstructionIdContainerInitFields: |
| 15970 | case IrInstructionIdStructInit: | 16118 | case IrInstructionIdStructInit: |
| 16119 | case IrInstructionIdUnionInit: | ||
| 15971 | case IrInstructionIdFieldPtr: | 16120 | case IrInstructionIdFieldPtr: |
| 15972 | case IrInstructionIdElemPtr: | 16121 | case IrInstructionIdElemPtr: |
| 15973 | case IrInstructionIdVarPtr: | 16122 | case IrInstructionIdVarPtr: |
| ... | @@ -15977,6 +16126,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -15977,6 +16126,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 15977 | case IrInstructionIdArrayLen: | 16126 | case IrInstructionIdArrayLen: |
| 15978 | case IrInstructionIdStructFieldPtr: | 16127 | case IrInstructionIdStructFieldPtr: |
| 15979 | case IrInstructionIdEnumFieldPtr: | 16128 | case IrInstructionIdEnumFieldPtr: |
| 16129 | case IrInstructionIdUnionFieldPtr: | ||
| 15980 | case IrInstructionIdArrayType: | 16130 | case IrInstructionIdArrayType: |
| 15981 | case IrInstructionIdSliceType: | 16131 | case IrInstructionIdSliceType: |
| 15982 | case IrInstructionIdSizeOf: | 16132 | 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+44| ... | @@ -31,3 +31,47 @@ test "unions embedded in aggregate types" { | ... | @@ -31,3 +31,47 @@ 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 = Foo {.float = 12.34}; | ||
| 45 | assert(foo.float == 12.34); | ||
| 46 | } | ||
| 47 | |||
| 48 | test "init union with runtime value" { | ||
| 49 | var foo: Foo = undefined; | ||
| 50 | |||
| 51 | setFloat(&foo, 12.34); | ||
| 52 | assert(foo.float == 12.34); | ||
| 53 | |||
| 54 | setInt(&foo, 42); | ||
| 55 | assert(foo.int == 42); | ||
| 56 | } | ||
| 57 | |||
| 58 | fn setFloat(foo: &Foo, x: f64) { | ||
| 59 | *foo = Foo { .float = x }; | ||
| 60 | } | ||
| 61 | |||
| 62 | fn setInt(foo: &Foo, x: i32) { | ||
| 63 | *foo = Foo { .int = x }; | ||
| 64 | } | ||
| 65 | |||
| 66 | const FooExtern = extern union { | ||
| 67 | float: f64, | ||
| 68 | int: i32, | ||
| 69 | }; | ||
| 70 | |||
| 71 | test "basic extern unions" { | ||
| 72 | var foo = FooExtern { .int = 1 }; | ||
| 73 | assert(foo.int == 1); | ||
| 74 | foo.float = 12.34; | ||
| 75 | assert(foo.float == 12.34); | ||
| 76 | } | ||
| 77 |
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() { |
test/debug_safety.zig+20| ... | @@ -260,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) { | ... | @@ -260,4 +260,24 @@ pub fn addCases(cases: &tests.CompareOutputContext) { |
| 260 | \\ return int_slice[0]; | 260 | \\ return int_slice[0]; |
| 261 | \\} | 261 | \\} |
| 262 | ); | 262 | ); |
| 263 | |||
| 264 | cases.addDebugSafety("bad union field access", | ||
| 265 | \\pub fn panic(message: []const u8) -> noreturn { | ||
| 266 | \\ @import("std").os.exit(126); | ||
| 267 | \\} | ||
| 268 | \\ | ||
| 269 | \\const Foo = union { | ||
| 270 | \\ float: f32, | ||
| 271 | \\ int: u32, | ||
| 272 | \\}; | ||
| 273 | \\ | ||
| 274 | \\pub fn main() -> %void { | ||
| 275 | \\ var f = Foo { .int = 42 }; | ||
| 276 | \\ bar(&f); | ||
| 277 | \\} | ||
| 278 | \\ | ||
| 279 | \\fn bar(f: &Foo) { | ||
| 280 | \\ f.float = 12.34; | ||
| 281 | \\} | ||
| 282 | ); | ||
| 263 | } | 283 | } |