authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-16 22:14:50-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-16 22:14:50-05:00
logd1086893829d91d0e1335e14b0434a23ff0e8999
tree17e55b50e624ae06a93522a38aba3c0e83edf37e
parent7a74dbadd79d2b26a449027dd83753ae4d2a8032
parent1473eb9ae0196db729716aa0d29f5ce263412307

Merge branch 'unions'

closes #144

12 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;
2194const builtin = @import("builtin");2198const 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>
51195123
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};
7778
78struct ConstParent {79struct 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};
9296
...@@ -100,6 +104,12 @@ struct ConstStructValue {...@@ -100,6 +104,12 @@ struct ConstStructValue {
100 ConstParent parent;104 ConstParent parent;
101};105};
102106
107struct ConstUnionValue {
108 uint64_t tag;
109 ConstExprValue *payload;
110 ConstParent parent;
111};
112
103enum ConstArraySpecial {113enum 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};
338349
350struct TypeUnionField {
351 Buf *name;
352 TypeTableEntry *type_entry;
353 uint32_t value;
354 uint32_t gen_index;
355};
356
339enum NodeType {357enum 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};
10231041
1042uint32_t type_ptr_hash(const TypeTableEntry *ptr);
1043bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b);
1044
1024struct TypeTableEntryUnion {1045struct 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 invalid1051 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;
10331056
1034 // set this flag temporarily to detect infinite loops1057 // set this flag temporarily to detect infinite loops
...@@ -1039,6 +1062,13 @@ struct TypeTableEntryUnion {...@@ -1039,6 +1062,13 @@ struct TypeTableEntryUnion {
10391062
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};
10431073
1044struct FnGenParamInfo {1074struct 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,
12901321
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};
20622095
2096struct IrInstructionUnionFieldPtr {
2097 IrInstruction base;
2098
2099 IrInstruction *union_ptr;
2100 TypeUnionField *field;
2101 bool is_const;
2102};
2103
2063struct IrInstructionElemPtr {2104struct IrInstructionElemPtr {
2064 IrInstruction base;2105 IrInstruction base;
20652106
...@@ -2150,6 +2191,15 @@ struct IrInstructionStructInit {...@@ -2150,6 +2191,15 @@ struct IrInstructionStructInit {
2150 LLVMValueRef tmp_ptr;2191 LLVMValueRef tmp_ptr;
2151};2192};
21522193
2194struct IrInstructionUnionInit {
2195 IrInstruction base;
2196
2197 TypeTableEntry *union_type;
2198 TypeUnionField *field;
2199 IrInstruction *init_value;
2200 LLVMValueRef tmp_ptr;
2201};
2202
2153struct IrInstructionUnreachable {2203struct 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 }
10091009
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();
10111012
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));
10171018
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;
12861287
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;
12901291
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}
18351836
1836static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {1837static 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}
18392079
1840static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {2080static 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;
18742114
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}
19812221
1982static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {2222static 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}
19852287
1986static void get_fully_qualified_decl_name_internal(Buf *buf, Scope *scope, uint8_t sep) {2288static 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}
28533155
3156TypeUnionField *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
2854static bool is_container(TypeTableEntry *type_entry) {3168static 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
5250uint32_t type_ptr_hash(const TypeTableEntry *ptr) {
5251 return hash_ptr((void*)ptr);
5252}
5253
5254bool 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);
63TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);63TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
64ScopeDecls *get_container_scope(TypeTableEntry *type_entry);64ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
65TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);65TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
66TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
66bool is_container_ref(TypeTableEntry *type_entry);67bool is_container_ref(TypeTableEntry *type_entry);
67void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);68void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
68void scan_import(CodeGen *g, ImportTableEntry *import);69void 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}
23952397
2398static 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
2396static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) {2442static 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}
33673413
3414static 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
3368static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable,3450static 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) {
35953681
3596static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);3682static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ConstExprValue *struct_const_val, size_t field_index);
3597static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);3683static LLVMValueRef gen_const_ptr_array_recursive(CodeGen *g, ConstExprValue *array_const_val, size_t index);
3684static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *array_const_val);
35983685
3599static LLVMValueRef gen_parent_ptr(CodeGen *g, ConstExprValue *val, ConstParent *parent) {3686static 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}
36393728
3729static 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
3640static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) {3741static 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}
229229
230static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
231 return IrInstructionIdUnionFieldPtr;
232}
233
230static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) {234static 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}
353357
358static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) {
359 return IrInstructionIdUnionInit;
360}
361
354static constexpr IrInstructionId ir_instruction_id(IrInstructionMinValue *) {362static 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}
924932
933static 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
945static 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
925static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node,954static 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}
11141143
1144static 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
1157static 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
1115static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) {1166static 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}
24242475
2476static 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
2425static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instruction, size_t index) {2483static 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}
24872545
2546static 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
2488static IrInstruction *ir_instruction_unreachable_get_dep(IrInstructionUnreachable *instruction, size_t index) {2553static 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}
1142411505
...@@ -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;
1143111514
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}
1303513120
13121static 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
13036static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction,13180static 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 }
1304513192
13046 if (!type_is_complete(container_type))13193 ensure_complete_type(ira->codegen, container_type);
13047 resolve_container_type(ira->codegen, container_type);
1304813194
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;
1305013196
...@@ -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}
292292
293static 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
293static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) {302static 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}
361370
371static 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
362static void ir_print_set_debug_safety(IrPrint *irp, IrInstructionSetDebugSafety *instruction) {378static 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}
405405
406unsigned ZigLLVMTag_DW_union_type(void) {
407 return dwarf::DW_TAG_union_type;
408}
409
406ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved) {410ZigLLVMDIBuilder *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);
117unsigned ZigLLVMLang_DW_LANG_C99(void);117unsigned ZigLLVMLang_DW_LANG_C99(void);
118unsigned ZigLLVMTag_DW_variable(void);118unsigned ZigLLVMTag_DW_variable(void);
119unsigned ZigLLVMTag_DW_structure_type(void);119unsigned ZigLLVMTag_DW_structure_type(void);
120unsigned ZigLLVMTag_DW_union_type(void);
120121
121ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);122ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
122void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);123void 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
36const Foo = union {
37 float: f64,
38 int: i32,
39};
40
41test "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
48test "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
58fn setFloat(foo: &Foo, x: f64) {
59 *foo = Foo { .float = x };
60}
61
62fn setInt(foo: &Foo, x: i32) {
63 *foo = Foo { .int = x };
64}
65
66const FooExtern = extern union {
67 float: f64,
68 int: i32,
69};
70
71test "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'");
394394
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'");
458458
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}