authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-15 22:52:47-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-15 22:52:47-05:00
log018cbff438cedc19d0ad18021619ec7ede997307
treee21110319947f172100bda3b62685d2857c1fcdb
parentf276fd0f3728bf1a43b185e3e2d33d593309cb2f

unions have a secret field for the type

See #144

4 files changed, 193 insertions(+), 29 deletions(-)

src/all_types.hpp+11-1
...@@ -1037,6 +1037,9 @@ struct TypeTableEntryEnumTag {...@@ -1037,6 +1037,9 @@ struct TypeTableEntryEnumTag {
1037 LLVMValueRef name_table;1037 LLVMValueRef name_table;
1038};1038};
10391039
1040uint32_t type_ptr_hash(const TypeTableEntry *ptr);
1041bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b);
1042
1040struct TypeTableEntryUnion {1043struct TypeTableEntryUnion {
1041 AstNode *decl_node;1044 AstNode *decl_node;
1042 ContainerLayout layout;1045 ContainerLayout layout;
...@@ -1044,6 +1047,8 @@ struct TypeTableEntryUnion {...@@ -1044,6 +1047,8 @@ struct TypeTableEntryUnion {
1044 uint32_t gen_field_count;1047 uint32_t gen_field_count;
1045 TypeUnionField *fields;1048 TypeUnionField *fields;
1046 bool is_invalid; // true if any fields are invalid1049 bool is_invalid; // true if any fields are invalid
1050 TypeTableEntry *tag_type;
1051 LLVMTypeRef union_type_ref;
10471052
1048 ScopeDecls *decls_scope;1053 ScopeDecls *decls_scope;
10491054
...@@ -1057,8 +1062,13 @@ struct TypeTableEntryUnion {...@@ -1057,8 +1062,13 @@ struct TypeTableEntryUnion {
1057 bool zero_bits_known;1062 bool zero_bits_known;
1058 uint32_t abi_alignment; // also figured out with zero_bits pass1063 uint32_t abi_alignment; // also figured out with zero_bits pass
10591064
1060 uint32_t size_bytes;1065 size_t gen_union_index;
1066 size_t gen_tag_index;
1067
1068 uint32_t union_size_bytes;
1061 TypeTableEntry *most_aligned_union_member;1069 TypeTableEntry *most_aligned_union_member;
1070
1071 HashMap<const TypeTableEntry *, uint32_t, type_ptr_hash, type_ptr_eql> distinct_types = {};
1062};1072};
10631073
1064struct FnGenParamInfo {1074struct FnGenParamInfo {
src/analyze.cpp+128-12
...@@ -992,26 +992,23 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi...@@ -992,26 +992,23 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKi
992 TypeTableEntryId type_id = container_to_type(kind);992 TypeTableEntryId type_id = container_to_type(kind);
993 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope);993 TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, scope);
994994
995 unsigned dwarf_kind;
996 switch (kind) {995 switch (kind) {
997 case ContainerKindStruct:996 case ContainerKindStruct:
998 entry->data.structure.decl_node = decl_node;997 entry->data.structure.decl_node = decl_node;
999 entry->data.structure.layout = layout;998 entry->data.structure.layout = layout;
1000 dwarf_kind = ZigLLVMTag_DW_structure_type();
1001 break;999 break;
1002 case ContainerKindEnum:1000 case ContainerKindEnum:
1003 entry->data.enumeration.decl_node = decl_node;1001 entry->data.enumeration.decl_node = decl_node;
1004 entry->data.enumeration.layout = layout;1002 entry->data.enumeration.layout = layout;
1005 dwarf_kind = ZigLLVMTag_DW_structure_type();
1006 break;1003 break;
1007 case ContainerKindUnion:1004 case ContainerKindUnion:
1008 entry->data.unionation.decl_node = decl_node;1005 entry->data.unionation.decl_node = decl_node;
1009 entry->data.unionation.layout = layout;1006 entry->data.unionation.layout = layout;
1010 dwarf_kind = ZigLLVMTag_DW_union_type();
1011 break;1007 break;
1012 }1008 }
10131009
1014 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();
10151012
1016 ImportTableEntry *import = get_scope_import(scope);1013 ImportTableEntry *import = get_scope_import(scope);
1017 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);1014 entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), name);
...@@ -1873,6 +1870,11 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1873,6 +1870,11 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1873 uint64_t biggest_align_in_bits = 0;1870 uint64_t biggest_align_in_bits = 0;
1874 uint64_t biggest_size_in_bits = 0;1871 uint64_t biggest_size_in_bits = 0;
18751872
1873 bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
1874 ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
1875 auto distinct_types = &union_type->data.unionation.distinct_types;
1876 distinct_types->init(4);
1877
1876 Scope *scope = &union_type->data.unionation.decls_scope->base;1878 Scope *scope = &union_type->data.unionation.decls_scope->base;
1877 ImportTableEntry *import = get_scope_import(scope);1879 ImportTableEntry *import = get_scope_import(scope);
18781880
...@@ -1893,6 +1895,11 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1893,6 +1895,11 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1893 if (!type_has_bits(field_type))1895 if (!type_has_bits(field_type))
1894 continue;1896 continue;
18951897
1898 size_t distinct_type_index = distinct_types->size();
1899 if (distinct_types->put_unique(field_type, distinct_type_index) == nullptr) {
1900 di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(&field_type->name), distinct_type_index);
1901 }
1902
1896 uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);1903 uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
1897 uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);1904 uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
18981905
...@@ -1919,7 +1926,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1919,7 +1926,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1919 // unset temporary flag1926 // unset temporary flag
1920 union_type->data.unionation.embedded_in_current = false;1927 union_type->data.unionation.embedded_in_current = false;
1921 union_type->data.unionation.complete = true;1928 union_type->data.unionation.complete = true;
1922 union_type->data.unionation.size_bytes = biggest_size_in_bits / 8;1929 union_type->data.unionation.union_size_bytes = biggest_size_in_bits / 8;
1923 union_type->data.unionation.most_aligned_union_member = most_aligned_union_member;1930 union_type->data.unionation.most_aligned_union_member = most_aligned_union_member;
19241931
1925 if (union_type->data.unionation.is_invalid)1932 if (union_type->data.unionation.is_invalid)
...@@ -1947,8 +1954,42 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1947,8 +1954,42 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
19471954
1948 assert(most_aligned_union_member != nullptr);1955 assert(most_aligned_union_member != nullptr);
19491956
1950 // create llvm type for union1957 bool want_safety = (distinct_types->size() > 1) && auto_layout;
1951 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;1958 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1959
1960
1961 if (!want_safety) {
1962 if (padding_in_bits > 0) {
1963 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1964 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1965 LLVMTypeRef union_element_types[] = {
1966 most_aligned_union_member->type_ref,
1967 padding_array->type_ref,
1968 };
1969 LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false);
1970 } else {
1971 LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false);
1972 }
1973 union_type->data.unionation.union_type_ref = union_type->type_ref;
1974 union_type->data.unionation.gen_tag_index = SIZE_MAX;
1975 union_type->data.unionation.gen_union_index = SIZE_MAX;
1976
1977 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits);
1978 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits);
1979
1980 // create debug type for union
1981 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1982 ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),
1983 import->di_file, (unsigned)(decl_node->line + 1),
1984 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1985 gen_field_count, 0, "");
1986
1987 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
1988 union_type->di_type = replacement_di_type;
1989 return;
1990 }
1991
1992 LLVMTypeRef union_type_ref;
1952 if (padding_in_bits > 0) {1993 if (padding_in_bits > 0) {
1953 TypeTableEntry *u8_type = get_int_type(g, false, 8);1994 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1954 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);1995 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
...@@ -1956,20 +1997,87 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {...@@ -1956,20 +1997,87 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
1956 most_aligned_union_member->type_ref,1997 most_aligned_union_member->type_ref,
1957 padding_array->type_ref,1998 padding_array->type_ref,
1958 };1999 };
1959 LLVMStructSetBody(union_type->type_ref, union_element_types, 2, false);2000 union_type_ref = LLVMStructType(union_element_types, 2, false);
2001 } else {
2002 union_type_ref = most_aligned_union_member->type_ref;
2003 }
2004 union_type->data.unionation.union_type_ref = union_type_ref;
2005
2006 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
2007 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
2008
2009 // create llvm type for root struct
2010 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, distinct_types->size() - 1);
2011 TypeTableEntry *tag_type_entry = tag_int_type;
2012 union_type->data.unionation.tag_type = tag_type_entry;
2013 uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
2014
2015 if (align_of_tag_in_bits >= biggest_align_in_bits) {
2016 union_type->data.unionation.gen_tag_index = 0;
2017 union_type->data.unionation.gen_union_index = 1;
1960 } else {2018 } else {
1961 LLVMStructSetBody(union_type->type_ref, &most_aligned_union_member->type_ref, 1, false);2019 union_type->data.unionation.gen_union_index = 0;
2020 union_type->data.unionation.gen_tag_index = 1;
1962 }2021 }
19632022
1964 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type->type_ref) >= biggest_align_in_bits);2023 LLVMTypeRef root_struct_element_types[2];
1965 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref) >= biggest_size_in_bits);2024 root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref;
2025 root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
2026 LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
2027
2028
2029 // create debug type for root struct
2030
2031 // create debug type for tag
2032 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
2033 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
2034 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
2035 ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
2036 import->di_file, (unsigned)(decl_node->line + 1),
2037 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, distinct_types->size(),
2038 tag_type_entry->di_type, "");
19662039
1967 // create debug type for union2040 // create debug type for union
1968 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,2041 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1969 ZigLLVMFileToScope(import->di_file), buf_ptr(&union_type->name),2042 ZigLLVMTypeToScope(union_type->di_type), "AnonUnion",
1970 import->di_file, (unsigned)(decl_node->line + 1),2043 import->di_file, (unsigned)(decl_node->line + 1),
1971 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,2044 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1972 gen_field_count, 0, "");2045 gen_field_count, 0, "");
2046
2047 uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
2048 union_type->data.unionation.gen_union_index);
2049 uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->type_ref,
2050 union_type->data.unionation.gen_tag_index);
2051
2052 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
2053 ZigLLVMTypeToScope(union_type->di_type), "union_field",
2054 import->di_file, (unsigned)(decl_node->line + 1),
2055 biggest_size_in_bits,
2056 biggest_align_in_bits,
2057 union_offset_in_bits,
2058 0, union_di_type);
2059 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
2060 ZigLLVMTypeToScope(union_type->di_type), "tag_field",
2061 import->di_file, (unsigned)(decl_node->line + 1),
2062 tag_debug_size_in_bits,
2063 tag_debug_align_in_bits,
2064 tag_offset_in_bits,
2065 0, tag_di_type);
2066
2067 ZigLLVMDIType *di_root_members[2];
2068 di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
2069 di_root_members[union_type->data.unionation.gen_union_index] = union_member_di_type;
2070
2071 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, union_type->type_ref);
2072 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, union_type->type_ref);
2073 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
2074 ZigLLVMFileToScope(import->di_file),
2075 buf_ptr(&union_type->name),
2076 import->di_file, (unsigned)(decl_node->line + 1),
2077 debug_size_in_bits,
2078 debug_align_in_bits,
2079 0, nullptr, di_root_members, 2, 0, nullptr, "");
2080
1973 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);2081 ZigLLVMReplaceTemporary(g->dbuilder, union_type->di_type, replacement_di_type);
1974 union_type->di_type = replacement_di_type;2082 union_type->di_type = replacement_di_type;
1975}2083}
...@@ -5140,3 +5248,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) {...@@ -5140,3 +5248,11 @@ TypeTableEntry *get_align_amt_type(CodeGen *g) {
5140 }5248 }
5141 return g->align_amt_type;5249 return g->align_amt_type;
5142}5250}
5251
5252uint32_t type_ptr_hash(const TypeTableEntry *ptr) {
5253 return hash_ptr((void*)ptr);
5254}
5255
5256bool type_ptr_eql(const TypeTableEntry *a, const TypeTableEntry *b) {
5257 return a == b;
5258}
src/codegen.cpp+41-16
...@@ -2408,9 +2408,15 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab...@@ -2408,9 +2408,15 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
24082408
2409 LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);2409 LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr);
2410 LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);2410 LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
2411 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, "");
2412 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
24132411
2412 if (union_type->data.unionation.gen_tag_index == SIZE_MAX) {
2413 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, 0, "");
2414 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
2415 return bitcasted_union_field_ptr;
2416 }
2417
2418 LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_union_index, "");
2419 LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
2414 return bitcasted_union_field_ptr;2420 return bitcasted_union_field_ptr;
2415}2421}
24162422
...@@ -3955,7 +3961,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3955,7 +3961,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3955 }3961 }
3956 case TypeTableEntryIdUnion:3962 case TypeTableEntryIdUnion:
3957 {3963 {
3958 LLVMTypeRef union_type_ref = type_entry->type_ref;3964 LLVMTypeRef union_type_ref = type_entry->data.unionation.union_type_ref;
3959 ConstExprValue *payload_value = const_val->data.x_union.value;3965 ConstExprValue *payload_value = const_val->data.x_union.value;
3960 assert(payload_value != nullptr);3966 assert(payload_value != nullptr);
39613967
...@@ -3964,29 +3970,48 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {...@@ -3964,29 +3970,48 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
3964 }3970 }
39653971
3966 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);3972 uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
3967 uint64_t pad_bytes = type_entry->data.unionation.size_bytes - field_type_bytes;3973 uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
3968
3969 LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);3974 LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
3970
3971 bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||3975 bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
3972 payload_value->type != type_entry->data.unionation.most_aligned_union_member;3976 payload_value->type != type_entry->data.unionation.most_aligned_union_member;
39733977
3974 unsigned field_count;3978 LLVMValueRef union_value_ref;
3975 LLVMValueRef fields[2];3979 {
3976 fields[0] = correctly_typed_value;3980 unsigned field_count;
3977 if (pad_bytes == 0) {3981 LLVMValueRef fields[2];
3978 field_count = 1;
3979 } else {
3980 fields[0] = correctly_typed_value;3982 fields[0] = correctly_typed_value;
3981 fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));3983 if (pad_bytes == 0) {
3982 field_count = 2;3984 field_count = 1;
3985 } else {
3986 fields[0] = correctly_typed_value;
3987 fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
3988 field_count = 2;
3989 }
3990
3991 if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
3992 union_value_ref = LLVMConstStruct(fields, field_count, false);
3993 } else {
3994 union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, field_count);
3995 }
3996 }
3997
3998 if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
3999 return union_value_ref;
3983 }4000 }
39844001
4002 size_t distinct_type_index = type_entry->data.unionation.distinct_types.get(const_val->data.x_union.value->type);
4003 LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, distinct_type_index, false);
4004
4005 LLVMValueRef fields[2];
4006 fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
4007 fields[type_entry->data.unionation.gen_tag_index] = tag_value;
4008
3985 if (make_unnamed_struct) {4009 if (make_unnamed_struct) {
3986 return LLVMConstStruct(fields, field_count, false);4010 return LLVMConstStruct(fields, 2, false);
3987 } else {4011 } else {
3988 return LLVMConstNamedStruct(type_entry->type_ref, fields, field_count);4012 return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
3989 }4013 }
4014
3990 }4015 }
3991 case TypeTableEntryIdEnum:4016 case TypeTableEntryIdEnum:
3992 {4017 {
test/cases/union.zig+13
...@@ -44,3 +44,16 @@ test "basic unions" {...@@ -44,3 +44,16 @@ test "basic unions" {
44 foo.float = 12.34;44 foo.float = 12.34;
45 assert(foo.float == 12.34);45 assert(foo.float == 12.34);
46}46}
47
48
49const FooExtern = extern union {
50 float: f64,
51 int: i32,
52};
53
54test "basic extern unions" {
55 var foo = FooExtern { .int = 1 };
56 assert(foo.int == 1);
57 foo.float = 12.34;
58 assert(foo.float == 12.34);
59}