mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 04:48:20 +00:00
rework enums and unions and their relationship to each other
* @enumTagName renamed to @tagName and it works on enums and union-enums * Remove the EnumTag type. Now there is only enum and union, and the tag type of a union is always an enum. * unions support specifying the tag enum type, and they support inferring an enum tag type. * Enums no longer support field types but they do support setting the tag values. Likewise union-enums when inferring an enum tag type support setting the tag values. * It is now an error for enums and unions to have 0 fields. * switch statements support union-enums closes #618
This commit is contained in:
parent
137c8f5e8a
commit
0ad1239522
@ -136,7 +136,7 @@
|
||||
<li><a href="#builtin-divFloor">@divFloor</a></li>
|
||||
<li><a href="#builtin-divTrunc">@divTrunc</a></li>
|
||||
<li><a href="#builtin-embedFile">@embedFile</a></li>
|
||||
<li><a href="#builtin-enumTagName">@enumTagName</a></li>
|
||||
<li><a href="#builtin-tagName">@tagName</a></li>
|
||||
<li><a href="#builtin-EnumTagType">@EnumTagType</a></li>
|
||||
<li><a href="#builtin-errorName">@errorName</a></li>
|
||||
<li><a href="#builtin-fence">@fence</a></li>
|
||||
@ -2165,7 +2165,7 @@ test "enum variant switch" {
|
||||
};
|
||||
}
|
||||
|
||||
// The @enumTagName and @memberCount builtin functions can be used to
|
||||
// The @memberName and @memberCount builtin functions can be used to
|
||||
// the string representation and number of members respectively.
|
||||
const BuiltinType = enum {
|
||||
A: f32,
|
||||
@ -2174,8 +2174,8 @@ const BuiltinType = enum {
|
||||
};
|
||||
|
||||
test "enum builtins" {
|
||||
assert(mem.eql(u8, @enumTagName(BuiltinType.A { 0 }), "A"));
|
||||
assert(mem.eql(u8, @enumTagName(BuiltinType.C), "C"));
|
||||
assert(mem.eql(u8, @memberName(BuiltinType.A { 0 }), "A"));
|
||||
assert(mem.eql(u8, @memberName(BuiltinType.C), "C"));
|
||||
assert(@memberCount(BuiltinType) == 3);
|
||||
}</code></pre>
|
||||
<pre><code class="sh">$ zig test enum.zig
|
||||
@ -2189,8 +2189,9 @@ Test 4/4 enum builtins...OK</code></pre>
|
||||
</p>
|
||||
<p>See also:</p>
|
||||
<ul>
|
||||
<li><a href="#builtin-enumTagName">@enumTagName</a></li>
|
||||
<li><a href="#builtin-memberName">@memberName</a></li>
|
||||
<li><a href="#builtin-memberCount">@memberCount</a></li>
|
||||
<li><a href="#builtin-tagName">@tagName</a></li>
|
||||
</ul>
|
||||
<h2 id="union">union</h2>
|
||||
<p>TODO union documentation</p>
|
||||
@ -4252,10 +4253,10 @@ test.zig:6:2: error: found compile log statement
|
||||
<ul>
|
||||
<li><a href="#builtin-import">@import</a></li>
|
||||
</ul>
|
||||
<h3 id="builtin-enumTagName">@enumTagName</h3>
|
||||
<pre><code class="zig">@enumTagName(value: var) -> []const u8</code></pre>
|
||||
<h3 id="builtin-tagName">@tagName</h3>
|
||||
<pre><code class="zig">@tagName(value: var) -> []const u8</code></pre>
|
||||
<p>
|
||||
Converts an enum tag name to a slice of bytes.
|
||||
Converts an enum value or union value to a slice of bytes representing the name.
|
||||
</p>
|
||||
<h3 id="builtin-EnumTagType">@EnumTagType</h3>
|
||||
<pre><code class="zig">@EnumTagType(T: type) -> type</code></pre>
|
||||
@ -5843,7 +5844,9 @@ GroupedExpression = "(" Expression ")"
|
||||
|
||||
KeywordLiteral = "true" | "false" | "null" | "continue" | "undefined" | "error" | "this" | "unreachable"
|
||||
|
||||
ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"</code></pre>
|
||||
ContainerDecl = option("extern" | "packed")
|
||||
("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
|
||||
"{" many(ContainerMember) "}"</code></pre>
|
||||
<h2 id="zen">Zen</h2>
|
||||
<ul>
|
||||
<li>Communicate intent precisely.</li>
|
||||
|
||||
@ -97,11 +97,6 @@ struct ConstParent {
|
||||
} data;
|
||||
};
|
||||
|
||||
struct ConstEnumValue {
|
||||
BigInt tag;
|
||||
ConstExprValue *payload;
|
||||
};
|
||||
|
||||
struct ConstStructValue {
|
||||
ConstExprValue *fields;
|
||||
ConstParent parent;
|
||||
@ -249,7 +244,7 @@ struct ConstExprValue {
|
||||
ConstExprValue *x_maybe;
|
||||
ConstErrValue x_err_union;
|
||||
ErrorTableEntry *x_pure_err;
|
||||
ConstEnumValue x_enum;
|
||||
BigInt x_enum_tag;
|
||||
ConstStructValue x_struct;
|
||||
ConstUnionValue x_union;
|
||||
ConstArrayValue x_array;
|
||||
@ -345,15 +340,14 @@ struct TldCompTime {
|
||||
|
||||
struct TypeEnumField {
|
||||
Buf *name;
|
||||
TypeTableEntry *type_entry;
|
||||
BigInt value;
|
||||
uint32_t gen_index;
|
||||
uint32_t decl_index;
|
||||
};
|
||||
|
||||
struct TypeUnionField {
|
||||
Buf *name;
|
||||
TypeEnumField *enum_field;
|
||||
TypeTableEntry *type_entry;
|
||||
BigInt value;
|
||||
uint32_t gen_index;
|
||||
};
|
||||
|
||||
@ -773,7 +767,8 @@ struct AstNodeContainerDecl {
|
||||
ZigList<AstNode *> fields;
|
||||
ZigList<AstNode *> decls;
|
||||
ContainerLayout layout;
|
||||
AstNode *init_arg_expr; // enum(T) or struct(endianness)
|
||||
AstNode *init_arg_expr; // enum(T), struct(endianness), or union(T), or union(enum(T))
|
||||
bool auto_enum; // union(enum)
|
||||
};
|
||||
|
||||
struct AstNodeStructField {
|
||||
@ -1010,13 +1005,9 @@ struct TypeTableEntryEnum {
|
||||
AstNode *decl_node;
|
||||
ContainerLayout layout;
|
||||
uint32_t src_field_count;
|
||||
// number of fields in the union. 0 if enum with no payload
|
||||
uint32_t gen_field_count;
|
||||
TypeEnumField *fields;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
TypeTableEntry *tag_type;
|
||||
TypeTableEntry *tag_int_type;
|
||||
LLVMTypeRef union_type_ref;
|
||||
|
||||
ScopeDecls *decls_scope;
|
||||
|
||||
@ -1028,18 +1019,7 @@ struct TypeTableEntryEnum {
|
||||
|
||||
bool zero_bits_loop_flag;
|
||||
bool zero_bits_known;
|
||||
uint32_t abi_alignment; // also figured out with zero_bits pass
|
||||
|
||||
size_t gen_union_index;
|
||||
size_t gen_tag_index;
|
||||
|
||||
uint32_t union_size_bytes;
|
||||
TypeTableEntry *most_aligned_union_member;
|
||||
};
|
||||
|
||||
struct TypeTableEntryEnumTag {
|
||||
TypeTableEntry *enum_type;
|
||||
TypeTableEntry *int_type;
|
||||
bool generate_name_table;
|
||||
LLVMValueRef name_table;
|
||||
};
|
||||
@ -1054,7 +1034,7 @@ struct TypeTableEntryUnion {
|
||||
uint32_t gen_field_count;
|
||||
TypeUnionField *fields;
|
||||
bool is_invalid; // true if any fields are invalid
|
||||
TypeTableEntry *tag_type;
|
||||
TypeTableEntry *tag_type; // always an enum or null
|
||||
LLVMTypeRef union_type_ref;
|
||||
|
||||
ScopeDecls *decls_scope;
|
||||
@ -1119,7 +1099,6 @@ enum TypeTableEntryId {
|
||||
TypeTableEntryIdErrorUnion,
|
||||
TypeTableEntryIdPureError,
|
||||
TypeTableEntryIdEnum,
|
||||
TypeTableEntryIdEnumTag,
|
||||
TypeTableEntryIdUnion,
|
||||
TypeTableEntryIdFn,
|
||||
TypeTableEntryIdNamespace,
|
||||
@ -1148,7 +1127,6 @@ struct TypeTableEntry {
|
||||
TypeTableEntryMaybe maybe;
|
||||
TypeTableEntryError error;
|
||||
TypeTableEntryEnum enumeration;
|
||||
TypeTableEntryEnumTag enum_tag;
|
||||
TypeTableEntryUnion unionation;
|
||||
TypeTableEntryFn fn;
|
||||
TypeTableEntryBoundFn bound_fn;
|
||||
@ -1287,7 +1265,7 @@ enum BuiltinFnId {
|
||||
BuiltinFnIdBitCast,
|
||||
BuiltinFnIdIntToPtr,
|
||||
BuiltinFnIdPtrToInt,
|
||||
BuiltinFnIdEnumTagName,
|
||||
BuiltinFnIdTagName,
|
||||
BuiltinFnIdEnumTagType,
|
||||
BuiltinFnIdFieldParentPtr,
|
||||
BuiltinFnIdOffsetOf,
|
||||
@ -1832,7 +1810,6 @@ enum IrInstructionId {
|
||||
IrInstructionIdStorePtr,
|
||||
IrInstructionIdFieldPtr,
|
||||
IrInstructionIdStructFieldPtr,
|
||||
IrInstructionIdEnumFieldPtr,
|
||||
IrInstructionIdUnionFieldPtr,
|
||||
IrInstructionIdElemPtr,
|
||||
IrInstructionIdVarPtr,
|
||||
@ -1857,7 +1834,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdTestNonNull,
|
||||
IrInstructionIdUnwrapMaybe,
|
||||
IrInstructionIdMaybeWrap,
|
||||
IrInstructionIdEnumTag,
|
||||
IrInstructionIdUnionTag,
|
||||
IrInstructionIdClz,
|
||||
IrInstructionIdCtz,
|
||||
IrInstructionIdImport,
|
||||
@ -1896,7 +1873,6 @@ enum IrInstructionId {
|
||||
IrInstructionIdErrWrapPayload,
|
||||
IrInstructionIdFnProto,
|
||||
IrInstructionIdTestComptime,
|
||||
IrInstructionIdInitEnum,
|
||||
IrInstructionIdPtrCast,
|
||||
IrInstructionIdBitCast,
|
||||
IrInstructionIdWidenOrShorten,
|
||||
@ -2092,14 +2068,6 @@ struct IrInstructionStructFieldPtr {
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionEnumFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *enum_ptr;
|
||||
TypeEnumField *field;
|
||||
bool is_const;
|
||||
};
|
||||
|
||||
struct IrInstructionUnionFieldPtr {
|
||||
IrInstruction base;
|
||||
|
||||
@ -2303,7 +2271,7 @@ struct IrInstructionClz {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionEnumTag {
|
||||
struct IrInstructionUnionTag {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *value;
|
||||
@ -2573,15 +2541,6 @@ struct IrInstructionTestComptime {
|
||||
IrInstruction *value;
|
||||
};
|
||||
|
||||
struct IrInstructionInitEnum {
|
||||
IrInstruction base;
|
||||
|
||||
TypeTableEntry *enum_type;
|
||||
TypeEnumField *field;
|
||||
IrInstruction *init_value;
|
||||
LLVMValueRef tmp_ptr;
|
||||
};
|
||||
|
||||
struct IrInstructionPtrCast {
|
||||
IrInstruction base;
|
||||
|
||||
|
||||
607
src/analyze.cpp
607
src/analyze.cpp
@ -223,7 +223,6 @@ bool type_is_complete(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
return true;
|
||||
}
|
||||
@ -260,7 +259,6 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
return true;
|
||||
@ -1175,7 +1173,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
ensure_complete_type(g, type_entry);
|
||||
if (fn_type_id.cc == CallingConventionUnspecified && !type_is_copyable(g, type_entry)) {
|
||||
add_node_error(g, param_node->data.param_decl.type,
|
||||
@ -1239,7 +1236,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1263,22 +1259,6 @@ bool type_is_invalid(TypeTableEntry *type_entry) {
|
||||
}
|
||||
|
||||
|
||||
TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type) {
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnumTag);
|
||||
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "@EnumTagType(%s)", buf_ptr(&enum_type->name));
|
||||
|
||||
entry->is_copyable = true;
|
||||
entry->data.enum_tag.enum_type = enum_type;
|
||||
entry->data.enum_tag.int_type = int_type;
|
||||
entry->type_ref = int_type->type_ref;
|
||||
entry->di_type = int_type->di_type;
|
||||
entry->zero_bits = int_type->zero_bits;
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
@ -1308,14 +1288,6 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
assert(enum_type->data.enumeration.fields);
|
||||
ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
|
||||
|
||||
uint32_t gen_field_count = enum_type->data.enumeration.gen_field_count;
|
||||
ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count);
|
||||
|
||||
TypeTableEntry *most_aligned_union_member = nullptr;
|
||||
uint64_t size_of_most_aligned_member_in_bits = 0;
|
||||
uint64_t biggest_align_in_bits = 0;
|
||||
uint64_t biggest_size_in_bits = 0;
|
||||
|
||||
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
|
||||
ImportTableEntry *import = get_scope_import(scope);
|
||||
|
||||
@ -1323,49 +1295,17 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.embedded_in_current = true;
|
||||
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
|
||||
TypeTableEntry *field_type = type_enum_field->type_entry;
|
||||
TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
|
||||
|
||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
|
||||
|
||||
ensure_complete_type(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
|
||||
uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
|
||||
|
||||
assert(store_size_in_bits > 0);
|
||||
assert(abi_align_in_bits > 0);
|
||||
|
||||
union_inner_di_types[type_enum_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), buf_ptr(type_enum_field->name),
|
||||
import->di_file, (unsigned)(field_node->line + 1),
|
||||
store_size_in_bits,
|
||||
abi_align_in_bits,
|
||||
0,
|
||||
0, field_type->di_type);
|
||||
|
||||
biggest_size_in_bits = max(biggest_size_in_bits, store_size_in_bits);
|
||||
|
||||
if (!most_aligned_union_member || abi_align_in_bits > biggest_align_in_bits) {
|
||||
most_aligned_union_member = field_type;
|
||||
biggest_align_in_bits = abi_align_in_bits;
|
||||
size_of_most_aligned_member_in_bits = store_size_in_bits;
|
||||
}
|
||||
// TODO send patch to LLVM to support APInt in createEnumerator instead of int64_t
|
||||
// http://lists.llvm.org/pipermail/llvm-dev/2017-December/119456.html
|
||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(enum_field->name),
|
||||
bigint_as_signed(&enum_field->value));
|
||||
}
|
||||
|
||||
// unset temporary flag
|
||||
enum_type->data.enumeration.embedded_in_current = false;
|
||||
enum_type->data.enumeration.complete = true;
|
||||
enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
|
||||
enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
|
||||
|
||||
if (enum_type->data.enumeration.is_invalid)
|
||||
return;
|
||||
@ -1391,117 +1331,20 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
}
|
||||
|
||||
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
|
||||
TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits,
|
||||
tag_debug_align_in_bits,
|
||||
di_enumerators, field_count,
|
||||
tag_int_type->di_type, "");
|
||||
|
||||
if (most_aligned_union_member) {
|
||||
// create llvm type for union
|
||||
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
|
||||
LLVMTypeRef union_type_ref;
|
||||
if (padding_in_bits > 0) {
|
||||
TypeTableEntry *u8_type = get_int_type(g, false, 8);
|
||||
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
|
||||
LLVMTypeRef union_element_types[] = {
|
||||
most_aligned_union_member->type_ref,
|
||||
padding_array->type_ref,
|
||||
};
|
||||
union_type_ref = LLVMStructType(union_element_types, 2, false);
|
||||
} else {
|
||||
union_type_ref = most_aligned_union_member->type_ref;
|
||||
}
|
||||
enum_type->data.enumeration.union_type_ref = union_type_ref;
|
||||
|
||||
assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
|
||||
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
|
||||
|
||||
if (align_of_tag_in_bits >= biggest_align_in_bits) {
|
||||
enum_type->data.enumeration.gen_tag_index = 0;
|
||||
enum_type->data.enumeration.gen_union_index = 1;
|
||||
} else {
|
||||
enum_type->data.enumeration.gen_union_index = 0;
|
||||
enum_type->data.enumeration.gen_tag_index = 1;
|
||||
}
|
||||
|
||||
// create llvm type for root struct
|
||||
LLVMTypeRef root_struct_element_types[2];
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
|
||||
root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
|
||||
LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
|
||||
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
|
||||
tag_type_entry->di_type, "");
|
||||
|
||||
// create debug type for union
|
||||
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
|
||||
gen_field_count, 0, "");
|
||||
|
||||
// create debug types for members of root struct
|
||||
uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_tag_index);
|
||||
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits,
|
||||
tag_debug_align_in_bits,
|
||||
tag_offset_in_bits,
|
||||
0, tag_di_type);
|
||||
|
||||
uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
|
||||
enum_type->data.enumeration.gen_union_index);
|
||||
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(enum_type->di_type), "union_field",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
biggest_size_in_bits,
|
||||
biggest_align_in_bits,
|
||||
union_offset_in_bits,
|
||||
0, union_di_type);
|
||||
|
||||
// create debug type for root struct
|
||||
ZigLLVMDIType *di_root_members[2];
|
||||
di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
|
||||
di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
|
||||
ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file),
|
||||
buf_ptr(&enum_type->name),
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
debug_size_in_bits,
|
||||
debug_align_in_bits,
|
||||
0, nullptr, di_root_members, 2, 0, nullptr, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
|
||||
enum_type->di_type = replacement_di_type;
|
||||
} else {
|
||||
// create llvm type for root struct
|
||||
enum_type->type_ref = tag_type_entry->type_ref;
|
||||
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits,
|
||||
tag_debug_align_in_bits,
|
||||
di_enumerators, field_count,
|
||||
tag_type_entry->di_type, "");
|
||||
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
|
||||
enum_type->di_type = tag_di_type;
|
||||
}
|
||||
ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
|
||||
enum_type->di_type = tag_di_type;
|
||||
}
|
||||
|
||||
static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
||||
@ -1517,7 +1360,6 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
@ -1541,8 +1383,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) {
|
||||
return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn;
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
return type_entry->data.enumeration.gen_field_count == 0 &&
|
||||
type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
|
||||
return type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -1850,6 +1691,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
if (union_type->data.unionation.embedded_in_current) {
|
||||
if (!union_type->data.unionation.reported_infinite_err) {
|
||||
union_type->data.unionation.reported_infinite_err = true;
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
add_node_error(g, decl_node, buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name)));
|
||||
}
|
||||
return;
|
||||
@ -1871,8 +1713,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
uint64_t biggest_align_in_bits = 0;
|
||||
uint64_t biggest_size_in_bits = 0;
|
||||
|
||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
||||
ZigLLVMDIEnumerator **di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
|
||||
ZigLLVMDIEnumerator **di_enumerators;
|
||||
|
||||
Scope *scope = &union_type->data.unionation.decls_scope->base;
|
||||
ImportTableEntry *import = get_scope_import(scope);
|
||||
@ -1880,10 +1721,77 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
// set temporary flag
|
||||
union_type->data.unionation.embedded_in_current = true;
|
||||
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
|
||||
AstNode *enum_type_node = decl_node->data.container_decl.init_arg_expr;
|
||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
||||
bool want_safety = (field_count >= 2) && (auto_layout || enum_type_node != nullptr);
|
||||
TypeTableEntry *tag_type;
|
||||
bool create_enum_type = decl_node->data.container_decl.auto_enum || (enum_type_node == nullptr && want_safety);
|
||||
bool *covered_enum_fields;
|
||||
if (create_enum_type) {
|
||||
occupied_tag_values.init(field_count);
|
||||
|
||||
di_enumerators = allocate<ZigLLVMDIEnumerator*>(field_count);
|
||||
|
||||
TypeTableEntry *tag_int_type;
|
||||
if (enum_type_node != nullptr) {
|
||||
tag_int_type = analyze_type_expr(g, scope, enum_type_node);
|
||||
if (type_is_invalid(tag_int_type)) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
if (tag_int_type->id != TypeTableEntryIdInt) {
|
||||
add_node_error(g, enum_type_node,
|
||||
buf_sprintf("expected integer tag type, found '%s'", buf_ptr(&tag_int_type->name)));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
}
|
||||
|
||||
tag_type = new_type_table_entry(TypeTableEntryIdEnum);
|
||||
buf_resize(&tag_type->name, 0);
|
||||
buf_appendf(&tag_type->name, "@EnumTagType(%s)", buf_ptr(&union_type->name));
|
||||
tag_type->is_copyable = true;
|
||||
tag_type->type_ref = tag_int_type->type_ref;
|
||||
tag_type->zero_bits = tag_int_type->zero_bits;
|
||||
|
||||
tag_type->data.enumeration.tag_int_type = tag_int_type;
|
||||
tag_type->data.enumeration.zero_bits_known = true;
|
||||
tag_type->data.enumeration.decl_node = decl_node;
|
||||
tag_type->data.enumeration.layout = ContainerLayoutAuto;
|
||||
tag_type->data.enumeration.src_field_count = field_count;
|
||||
tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope;
|
||||
tag_type->data.enumeration.complete = true;
|
||||
} else if (enum_type_node != nullptr) {
|
||||
TypeTableEntry *enum_type = analyze_type_expr(g, scope, enum_type_node);
|
||||
if (type_is_invalid(enum_type)) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
union_type->data.unionation.embedded_in_current = false;
|
||||
return;
|
||||
}
|
||||
if (enum_type->id != TypeTableEntryIdEnum) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
union_type->data.unionation.embedded_in_current = false;
|
||||
add_node_error(g, enum_type_node,
|
||||
buf_sprintf("expected enum tag type, found '%s'", buf_ptr(&enum_type->name)));
|
||||
return;
|
||||
}
|
||||
tag_type = enum_type;
|
||||
covered_enum_fields = allocate<bool>(enum_type->data.enumeration.src_field_count);
|
||||
} else {
|
||||
tag_type = nullptr;
|
||||
}
|
||||
union_type->data.unionation.tag_type = tag_type;
|
||||
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
||||
TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
|
||||
TypeTableEntry *field_type = type_union_field->type_entry;
|
||||
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
|
||||
Buf *field_name = field_node->data.struct_field.name;
|
||||
TypeTableEntry *field_type = union_field->type_entry;
|
||||
|
||||
ensure_complete_type(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
@ -1891,19 +1799,68 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (create_enum_type) {
|
||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(field_name), i);
|
||||
union_field->enum_field = &tag_type->data.enumeration.fields[i];
|
||||
union_field->enum_field->name = field_name;
|
||||
union_field->enum_field->decl_index = i;
|
||||
|
||||
AstNode *tag_value = field_node->data.struct_field.value;
|
||||
// In this first pass we resolve explicit tag values.
|
||||
// In a second pass we will fill in the unspecified ones.
|
||||
if (tag_value != nullptr) {
|
||||
TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
|
||||
IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
|
||||
if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
assert(result_inst->value.special != ConstValSpecialRuntime);
|
||||
assert(result_inst->value.type->id == TypeTableEntryIdInt);
|
||||
auto entry = occupied_tag_values.put_unique(result_inst->value.data.x_bigint, tag_value);
|
||||
if (entry == nullptr) {
|
||||
bigint_init_bigint(&union_field->enum_field->value, &result_inst->value.data.x_bigint);
|
||||
} else {
|
||||
Buf *val_buf = buf_alloc();
|
||||
bigint_append_buf(val_buf, &result_inst->value.data.x_bigint, 10);
|
||||
|
||||
ErrorMsg *msg = add_node_error(g, tag_value,
|
||||
buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
|
||||
add_error_note(g, msg, entry->value,
|
||||
buf_sprintf("other occurrence here"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (enum_type_node != nullptr) {
|
||||
union_field->enum_field = find_enum_type_field(tag_type, field_name);
|
||||
if (union_field->enum_field == nullptr) {
|
||||
ErrorMsg *msg = add_node_error(g, field_node,
|
||||
buf_sprintf("enum field not found: '%s'", buf_ptr(field_name)));
|
||||
add_error_note(g, msg, tag_type->data.enumeration.decl_node,
|
||||
buf_sprintf("enum declared here"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
covered_enum_fields[union_field->enum_field->decl_index] = true;
|
||||
} else {
|
||||
union_field->enum_field = allocate<TypeEnumField>(1);
|
||||
union_field->enum_field->name = field_name;
|
||||
union_field->enum_field->decl_index = i;
|
||||
bigint_init_unsigned(&union_field->enum_field->value, i);
|
||||
}
|
||||
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_union_field->name), i);
|
||||
|
||||
uint64_t store_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, field_type->type_ref);
|
||||
uint64_t abi_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, field_type->type_ref);
|
||||
|
||||
assert(store_size_in_bits > 0);
|
||||
assert(abi_align_in_bits > 0);
|
||||
|
||||
union_inner_di_types[type_union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), buf_ptr(type_union_field->name),
|
||||
union_inner_di_types[union_field->gen_index] = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), buf_ptr(union_field->enum_field->name),
|
||||
import->di_file, (unsigned)(field_node->line + 1),
|
||||
store_size_in_bits,
|
||||
abi_align_in_bits,
|
||||
@ -1919,6 +1876,49 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
}
|
||||
}
|
||||
|
||||
if (create_enum_type) {
|
||||
// Now iterate again and populate the unspecified tag values
|
||||
uint32_t next_maybe_unoccupied_index = 0;
|
||||
|
||||
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
|
||||
TypeUnionField *union_field = &union_type->data.unionation.fields[field_i];
|
||||
AstNode *tag_value = field_node->data.struct_field.value;
|
||||
|
||||
if (tag_value == nullptr) {
|
||||
if (occupied_tag_values.size() == 0) {
|
||||
bigint_init_unsigned(&union_field->enum_field->value, next_maybe_unoccupied_index);
|
||||
next_maybe_unoccupied_index += 1;
|
||||
} else {
|
||||
BigInt proposed_value;
|
||||
for (;;) {
|
||||
bigint_init_unsigned(&proposed_value, next_maybe_unoccupied_index);
|
||||
next_maybe_unoccupied_index += 1;
|
||||
auto entry = occupied_tag_values.put_unique(proposed_value, field_node);
|
||||
if (entry != nullptr) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
bigint_init_bigint(&union_field->enum_field->value, &proposed_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (enum_type_node != nullptr) {
|
||||
for (uint32_t i = 0; i < tag_type->data.enumeration.src_field_count; i += 1) {
|
||||
TypeEnumField *enum_field = &tag_type->data.enumeration.fields[i];
|
||||
if (!covered_enum_fields[i]) {
|
||||
AstNode *enum_decl_node = tag_type->data.enumeration.decl_node;
|
||||
AstNode *field_node = enum_decl_node->data.container_decl.fields.at(i);
|
||||
ErrorMsg *msg = add_node_error(g, decl_node,
|
||||
buf_sprintf("enum field missing: '%s'", buf_ptr(enum_field->name)));
|
||||
add_error_note(g, msg, field_node,
|
||||
buf_sprintf("declared here"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// unset temporary flag
|
||||
union_type->data.unionation.embedded_in_current = false;
|
||||
union_type->data.unionation.complete = true;
|
||||
@ -1950,11 +1950,9 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
|
||||
assert(most_aligned_union_member != nullptr);
|
||||
|
||||
bool want_safety = auto_layout && (field_count >= 2);
|
||||
uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
|
||||
|
||||
|
||||
if (!want_safety) {
|
||||
if (tag_type == nullptr) {
|
||||
if (padding_in_bits > 0) {
|
||||
TypeTableEntry *u8_type = get_int_type(g, false, 8);
|
||||
TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
|
||||
@ -1994,6 +1992,8 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
padding_array->type_ref,
|
||||
};
|
||||
union_type_ref = LLVMStructType(union_element_types, 2, false);
|
||||
} else if (most_aligned_union_member == nullptr) {
|
||||
zig_panic("TODO zero bit payload");
|
||||
} else {
|
||||
union_type_ref = most_aligned_union_member->type_ref;
|
||||
}
|
||||
@ -2003,9 +2003,7 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
|
||||
|
||||
// create llvm type for root struct
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
TypeTableEntry *tag_type_entry = tag_int_type;
|
||||
union_type->data.unionation.tag_type = tag_type_entry;
|
||||
TypeTableEntry *tag_int_type = tag_type->data.enumeration.tag_int_type;
|
||||
uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
|
||||
if (align_of_tag_in_bits >= biggest_align_in_bits) {
|
||||
@ -2017,21 +2015,24 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
}
|
||||
|
||||
LLVMTypeRef root_struct_element_types[2];
|
||||
root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type_entry->type_ref;
|
||||
root_struct_element_types[union_type->data.unionation.gen_tag_index] = tag_type->type_ref;
|
||||
root_struct_element_types[union_type->data.unionation.gen_union_index] = union_type_ref;
|
||||
LLVMStructSetBody(union_type->type_ref, root_struct_element_types, 2, false);
|
||||
|
||||
|
||||
// create debug type for root struct
|
||||
|
||||
// create debug type for tag
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
|
||||
tag_type_entry->di_type, "");
|
||||
uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type->type_ref);
|
||||
uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type->type_ref);
|
||||
if (create_enum_type) {
|
||||
// create debug type for tag
|
||||
ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), "AnonEnum",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
|
||||
tag_type->di_type, "");
|
||||
tag_type->di_type = tag_di_type;
|
||||
}
|
||||
|
||||
// create debug type for union
|
||||
ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
|
||||
@ -2046,19 +2047,19 @@ static void resolve_union_type(CodeGen *g, TypeTableEntry *union_type) {
|
||||
union_type->data.unionation.gen_tag_index);
|
||||
|
||||
ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), "union_field",
|
||||
ZigLLVMTypeToScope(union_type->di_type), "payload",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
biggest_size_in_bits,
|
||||
biggest_align_in_bits,
|
||||
union_offset_in_bits,
|
||||
0, union_di_type);
|
||||
ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
|
||||
ZigLLVMTypeToScope(union_type->di_type), "tag_field",
|
||||
ZigLLVMTypeToScope(union_type->di_type), "tag",
|
||||
import->di_file, (unsigned)(decl_node->line + 1),
|
||||
tag_debug_size_in_bits,
|
||||
tag_debug_align_in_bits,
|
||||
tag_offset_in_bits,
|
||||
0, tag_di_type);
|
||||
0, tag_type->di_type);
|
||||
|
||||
ZigLLVMDIType *di_root_members[2];
|
||||
di_root_members[union_type->data.unionation.gen_tag_index] = tag_member_di_type;
|
||||
@ -2104,7 +2105,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.fields = nullptr;
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
enum_type->data.enumeration.zero_bits_loop_flag = false;
|
||||
enum_type->data.enumeration.gen_field_count = 0;
|
||||
enum_type->data.enumeration.zero_bits_known = true;
|
||||
return;
|
||||
}
|
||||
@ -2112,8 +2112,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
enum_type->data.enumeration.src_field_count = field_count;
|
||||
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
|
||||
uint32_t biggest_align_bytes = 0;
|
||||
|
||||
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
|
||||
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
@ -2143,14 +2141,20 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
}
|
||||
}
|
||||
enum_type->data.enumeration.tag_int_type = tag_int_type;
|
||||
enum_type->type_ref = tag_int_type->type_ref;
|
||||
|
||||
uint32_t gen_field_index = 0;
|
||||
for (uint32_t field_i = 0; field_i < field_count; field_i += 1) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(field_i);
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_i];
|
||||
type_enum_field->name = field_node->data.struct_field.name;
|
||||
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
type_enum_field->type_entry = field_type;
|
||||
type_enum_field->decl_index = field_i;
|
||||
|
||||
if (field_node->data.struct_field.type != nullptr) {
|
||||
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.type,
|
||||
buf_sprintf("structs and unions, not enums, support field types"));
|
||||
add_error_note(g, msg, decl_node,
|
||||
buf_sprintf("consider 'union(enum)' here"));
|
||||
}
|
||||
|
||||
AstNode *tag_value = field_node->data.struct_field.value;
|
||||
|
||||
@ -2179,23 +2183,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
type_ensure_zero_bits_known(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
type_enum_field->gen_index = gen_field_index;
|
||||
gen_field_index += 1;
|
||||
|
||||
uint32_t field_align_bytes = get_abi_alignment(g, field_type);
|
||||
if (field_align_bytes > biggest_align_bytes) {
|
||||
biggest_align_bytes = field_align_bytes;
|
||||
}
|
||||
}
|
||||
|
||||
// Now iterate again and populate the unspecified tag values
|
||||
@ -2227,15 +2214,8 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
}
|
||||
|
||||
enum_type->data.enumeration.zero_bits_loop_flag = false;
|
||||
enum_type->data.enumeration.gen_field_count = gen_field_index;
|
||||
enum_type->zero_bits = (gen_field_index == 0 && field_count < 2);
|
||||
enum_type->zero_bits = (field_count < 2);
|
||||
enum_type->data.enumeration.zero_bits_known = true;
|
||||
|
||||
// also compute abi_alignment
|
||||
if (!enum_type->zero_bits) {
|
||||
uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
|
||||
enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
@ -2279,6 +2259,13 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
||||
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
|
||||
type_struct_field->name = field_node->data.struct_field.name;
|
||||
|
||||
if (field_node->data.struct_field.type == nullptr) {
|
||||
add_node_error(g, field_node, buf_sprintf("struct field missing type"));
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
type_struct_field->type_entry = field_type;
|
||||
type_struct_field->src_index = i;
|
||||
@ -2338,6 +2325,16 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
|
||||
assert(!union_type->data.unionation.fields);
|
||||
uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length;
|
||||
if (field_count == 0) {
|
||||
add_node_error(g, decl_node, buf_sprintf("unions must have 1 or more fields"));
|
||||
|
||||
union_type->data.unionation.src_field_count = field_count;
|
||||
union_type->data.unionation.fields = nullptr;
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
union_type->data.unionation.zero_bits_loop_flag = false;
|
||||
union_type->data.unionation.zero_bits_known = true;
|
||||
return;
|
||||
}
|
||||
union_type->data.unionation.src_field_count = field_count;
|
||||
union_type->data.unionation.fields = allocate<TypeUnionField>(field_count);
|
||||
|
||||
@ -2348,17 +2345,23 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
uint32_t gen_field_index = 0;
|
||||
for (uint32_t i = 0; i < field_count; i += 1) {
|
||||
AstNode *field_node = decl_node->data.container_decl.fields.at(i);
|
||||
TypeUnionField *type_union_field = &union_type->data.unionation.fields[i];
|
||||
type_union_field->name = field_node->data.struct_field.name;
|
||||
TypeUnionField *union_field = &union_type->data.unionation.fields[i];
|
||||
union_field->name = field_node->data.struct_field.name;
|
||||
|
||||
if (field_node->data.struct_field.type == nullptr) {
|
||||
add_node_error(g, field_node, buf_sprintf("union field missing type"));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
type_union_field->type_entry = field_type;
|
||||
union_field->type_entry = field_type;
|
||||
|
||||
// TODO look for enum arg to union
|
||||
bigint_init_unsigned(&type_union_field->value, i);
|
||||
|
||||
if (field_node->data.struct_field.value != nullptr) {
|
||||
add_node_error(g, field_node->data.struct_field.value,
|
||||
buf_sprintf("enums, not unions, support field assignment"));
|
||||
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
|
||||
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
|
||||
buf_sprintf("non-enum union field assignment"));
|
||||
add_error_note(g, msg, decl_node,
|
||||
buf_sprintf("consider 'union(enum)' here"));
|
||||
}
|
||||
|
||||
type_ensure_zero_bits_known(g, field_type);
|
||||
@ -2370,7 +2373,7 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
if (!type_has_bits(field_type))
|
||||
continue;
|
||||
|
||||
type_union_field->gen_index = gen_field_index;
|
||||
union_field->gen_index = gen_field_index;
|
||||
gen_field_index += 1;
|
||||
|
||||
uint32_t field_align_bytes = get_abi_alignment(g, field_type);
|
||||
@ -2379,11 +2382,32 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
}
|
||||
}
|
||||
|
||||
bool auto_layout = (union_type->data.unionation.layout == ContainerLayoutAuto);
|
||||
bool src_have_tag = decl_node->data.container_decl.auto_enum ||
|
||||
decl_node->data.container_decl.init_arg_expr != nullptr;
|
||||
|
||||
if (src_have_tag && union_type->data.unionation.layout != ContainerLayoutAuto) {
|
||||
const char *qual_str;
|
||||
switch (union_type->data.unionation.layout) {
|
||||
case ContainerLayoutAuto:
|
||||
zig_unreachable();
|
||||
case ContainerLayoutPacked:
|
||||
qual_str = "packed";
|
||||
break;
|
||||
case ContainerLayoutExtern:
|
||||
qual_str = "extern";
|
||||
break;
|
||||
}
|
||||
AstNode *source_node = (decl_node->data.container_decl.init_arg_expr != nullptr) ?
|
||||
decl_node->data.container_decl.init_arg_expr : decl_node;
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("%s union does not support enum tag type", qual_str));
|
||||
union_type->data.unionation.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
union_type->data.unionation.zero_bits_loop_flag = false;
|
||||
union_type->data.unionation.gen_field_count = gen_field_index;
|
||||
union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !auto_layout));
|
||||
union_type->zero_bits = (gen_field_index == 0 && (field_count < 2 || !src_have_tag));
|
||||
union_type->data.unionation.zero_bits_known = true;
|
||||
|
||||
// also compute abi_alignment
|
||||
@ -2848,7 +2872,6 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return type_entry;
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -3265,19 +3288,20 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
|
||||
assert(type_entry->data.unionation.complete);
|
||||
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
|
||||
TypeUnionField *field = &type_entry->data.unionation.fields[i];
|
||||
if (buf_eql_buf(field->name, name)) {
|
||||
if (buf_eql_buf(field->enum_field->name, name)) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
|
||||
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
|
||||
assert(type_entry->id == TypeTableEntryIdUnion);
|
||||
assert(type_entry->data.unionation.complete);
|
||||
assert(type_entry->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
for (uint32_t i = 0; i < type_entry->data.unionation.src_field_count; i += 1) {
|
||||
TypeUnionField *field = &type_entry->data.unionation.fields[i];
|
||||
if (bigint_cmp(&field->value, tag) == CmpEQ) {
|
||||
if (bigint_cmp(&field->enum_field->value, tag) == CmpEQ) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
@ -3323,7 +3347,6 @@ static bool is_container(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
return false;
|
||||
@ -3374,7 +3397,6 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
zig_unreachable();
|
||||
@ -3828,7 +3850,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdEnum:
|
||||
return false;
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
@ -3836,9 +3858,6 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
|
||||
return type_has_bits(type_entry);
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
return type_has_bits(type_entry->data.error.child_type);
|
||||
case TypeTableEntryIdEnum:
|
||||
assert(type_entry->data.enumeration.complete);
|
||||
return type_entry->data.enumeration.gen_field_count != 0;
|
||||
case TypeTableEntryIdMaybe:
|
||||
return type_has_bits(type_entry->data.maybe.child_type) &&
|
||||
type_entry->data.maybe.child_type->id != TypeTableEntryIdPointer &&
|
||||
@ -3980,7 +3999,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
return (uint32_t)4149439618;
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
{
|
||||
uint32_t result = 1331471175;
|
||||
for (size_t i = 0; i < const_val->data.x_bigint.digit_count; i += 1) {
|
||||
@ -3989,6 +4007,15 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
uint32_t result = 31643936;
|
||||
for (size_t i = 0; i < const_val->data.x_enum_tag.digit_count; i += 1) {
|
||||
uint64_t digit = bigint_ptr(&const_val->data.x_enum_tag)[i];
|
||||
result ^= ((uint32_t)(digit >> 32)) ^ (uint32_t)(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
case TypeTableEntryIdFloat:
|
||||
switch (const_val->type->data.floating.bit_count) {
|
||||
case 32:
|
||||
@ -4089,9 +4116,6 @@ static uint32_t hash_const_val(ConstExprValue *const_val) {
|
||||
case TypeTableEntryIdPureError:
|
||||
// TODO better hashing algorithm
|
||||
return 2630160122;
|
||||
case TypeTableEntryIdEnum:
|
||||
// TODO better hashing algorithm
|
||||
return 31643936;
|
||||
case TypeTableEntryIdFn:
|
||||
return 4133894920 ^ hash_ptr(const_val->data.x_fn.fn_entry);
|
||||
case TypeTableEntryIdNamespace:
|
||||
@ -4224,7 +4248,6 @@ bool type_requires_comptime(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
return false;
|
||||
@ -4295,6 +4318,7 @@ ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint)
|
||||
return const_val;
|
||||
}
|
||||
|
||||
|
||||
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = type;
|
||||
@ -4358,18 +4382,19 @@ ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
|
||||
return const_val;
|
||||
}
|
||||
|
||||
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
|
||||
void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = type;
|
||||
bigint_init_bigint(&const_val->data.x_enum.tag, tag);
|
||||
bigint_init_bigint(&const_val->data.x_enum_tag, tag);
|
||||
}
|
||||
|
||||
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag) {
|
||||
ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag) {
|
||||
ConstExprValue *const_val = create_const_vals(1);
|
||||
init_const_enum_tag(const_val, type, tag);
|
||||
init_const_enum(const_val, type, tag);
|
||||
return const_val;
|
||||
}
|
||||
|
||||
|
||||
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = g->builtin_types.entry_bool;
|
||||
@ -4567,20 +4592,8 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
switch (a->type->id) {
|
||||
case TypeTableEntryIdOpaque:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdEnum: {
|
||||
ConstEnumValue *enum1 = &a->data.x_enum;
|
||||
ConstEnumValue *enum2 = &b->data.x_enum;
|
||||
if (bigint_cmp(&enum1->tag, &enum2->tag) == CmpEQ) {
|
||||
TypeEnumField *field = find_enum_field_by_tag(a->type, &enum1->tag);
|
||||
assert(field != nullptr);
|
||||
if (type_has_bits(field->type_entry)) {
|
||||
zig_panic("TODO const expr analyze enum field value for equality");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
return bigint_cmp(&a->data.x_enum_tag, &b->data.x_enum_tag) == CmpEQ;
|
||||
case TypeTableEntryIdUnion: {
|
||||
ConstUnionValue *union1 = &a->data.x_union;
|
||||
ConstUnionValue *union2 = &b->data.x_union;
|
||||
@ -4622,7 +4635,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
return bigfloat_cmp(&a->data.x_bigfloat, &b->data.x_bigfloat) == CmpEQ;
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ;
|
||||
case TypeTableEntryIdPointer:
|
||||
if (a->data.x_ptr.special != b->data.x_ptr.special)
|
||||
@ -4949,7 +4961,8 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
buf_appendf(buf, "(enum %s constant)", buf_ptr(&type_entry->name));
|
||||
TypeEnumField *field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum_tag);
|
||||
buf_appendf(buf, "%s.%s", buf_ptr(&type_entry->name), buf_ptr(field->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
@ -4967,14 +4980,6 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
buf_appendf(buf, "(pure error constant)");
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdEnumTag:
|
||||
{
|
||||
TypeTableEntry *enum_type = type_entry->data.enum_tag.enum_type;
|
||||
size_t field_index = bigint_as_unsigned(&const_val->data.x_bigint);
|
||||
TypeEnumField *field = &enum_type->data.enumeration.fields[field_index];
|
||||
buf_appendf(buf, "%s.%s", buf_ptr(&enum_type->name), buf_ptr(field->name));
|
||||
return;
|
||||
}
|
||||
case TypeTableEntryIdArgTuple:
|
||||
{
|
||||
buf_appendf(buf, "(args value)");
|
||||
@ -5036,7 +5041,6 @@ uint32_t type_id_hash(TypeId x) {
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
@ -5081,7 +5085,6 @@ bool type_id_eql(TypeId a, TypeId b) {
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
@ -5196,7 +5199,6 @@ static const TypeTableEntryId all_type_ids[] = {
|
||||
TypeTableEntryIdErrorUnion,
|
||||
TypeTableEntryIdPureError,
|
||||
TypeTableEntryIdEnum,
|
||||
TypeTableEntryIdEnumTag,
|
||||
TypeTableEntryIdUnion,
|
||||
TypeTableEntryIdFn,
|
||||
TypeTableEntryIdNamespace,
|
||||
@ -5254,22 +5256,20 @@ size_t type_id_index(TypeTableEntryId id) {
|
||||
return 15;
|
||||
case TypeTableEntryIdEnum:
|
||||
return 16;
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return 17;
|
||||
case TypeTableEntryIdUnion:
|
||||
return 18;
|
||||
return 17;
|
||||
case TypeTableEntryIdFn:
|
||||
return 19;
|
||||
return 18;
|
||||
case TypeTableEntryIdNamespace:
|
||||
return 20;
|
||||
return 19;
|
||||
case TypeTableEntryIdBlock:
|
||||
return 21;
|
||||
return 20;
|
||||
case TypeTableEntryIdBoundFn:
|
||||
return 22;
|
||||
return 21;
|
||||
case TypeTableEntryIdArgTuple:
|
||||
return 23;
|
||||
return 22;
|
||||
case TypeTableEntryIdOpaque:
|
||||
return 24;
|
||||
return 23;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -5313,8 +5313,6 @@ const char *type_id_name(TypeTableEntryId id) {
|
||||
return "Error";
|
||||
case TypeTableEntryIdEnum:
|
||||
return "Enum";
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return "EnumTag";
|
||||
case TypeTableEntryIdUnion:
|
||||
return "Union";
|
||||
case TypeTableEntryIdFn:
|
||||
@ -5381,9 +5379,6 @@ uint32_t get_abi_alignment(CodeGen *g, TypeTableEntry *type_entry) {
|
||||
if (type_entry->id == TypeTableEntryIdStruct) {
|
||||
assert(type_entry->data.structure.abi_alignment != 0);
|
||||
return type_entry->data.structure.abi_alignment;
|
||||
} else if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
assert(type_entry->data.enumeration.abi_alignment != 0);
|
||||
return type_entry->data.enumeration.abi_alignment;
|
||||
} else if (type_entry->id == TypeTableEntryIdUnion) {
|
||||
assert(type_entry->data.unionation.abi_alignment != 0);
|
||||
return type_entry->data.unionation.abi_alignment;
|
||||
|
||||
@ -65,6 +65,7 @@ ScopeDecls *get_container_scope(TypeTableEntry *type_entry);
|
||||
TypeEnumField *find_enum_type_field(TypeTableEntry *enum_type, Buf *name);
|
||||
TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name);
|
||||
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag);
|
||||
TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag);
|
||||
|
||||
bool is_container_ref(TypeTableEntry *type_entry);
|
||||
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||
@ -126,8 +127,8 @@ ConstExprValue *create_const_usize(CodeGen *g, uint64_t x);
|
||||
void init_const_float(ConstExprValue *const_val, TypeTableEntry *type, double value);
|
||||
ConstExprValue *create_const_float(TypeTableEntry *type, double value);
|
||||
|
||||
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
|
||||
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag);
|
||||
void init_const_enum(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag);
|
||||
ConstExprValue *create_const_enum(TypeTableEntry *type, const BigInt *tag);
|
||||
|
||||
void init_const_bool(CodeGen *g, ConstExprValue *const_val, bool value);
|
||||
ConstExprValue *create_const_bool(CodeGen *g, bool value);
|
||||
@ -163,7 +164,6 @@ ConstExprValue *create_const_vals(size_t count);
|
||||
|
||||
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits);
|
||||
ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value);
|
||||
TypeTableEntry *create_enum_tag_type(CodeGen *g, TypeTableEntry *enum_type, TypeTableEntry *int_type);
|
||||
void expand_undef_array(CodeGen *g, ConstExprValue *const_val);
|
||||
void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value);
|
||||
|
||||
|
||||
@ -661,11 +661,18 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
const char *layout_str = layout_string(node->data.container_decl.layout);
|
||||
const char *container_str = container_string(node->data.container_decl.kind);
|
||||
fprintf(ar->f, "%s%s", layout_str, container_str);
|
||||
if (node->data.container_decl.auto_enum) {
|
||||
fprintf(ar->f, "(enum");
|
||||
}
|
||||
if (node->data.container_decl.init_arg_expr != nullptr) {
|
||||
fprintf(ar->f, "(");
|
||||
render_node_grouped(ar, node->data.container_decl.init_arg_expr);
|
||||
fprintf(ar->f, ")");
|
||||
}
|
||||
if (node->data.container_decl.auto_enum) {
|
||||
fprintf(ar->f, ")");
|
||||
}
|
||||
|
||||
fprintf(ar->f, " {\n");
|
||||
ar->indent += ar->indent_size;
|
||||
for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
|
||||
|
||||
245
src/codegen.cpp
245
src/codegen.cpp
@ -1631,12 +1631,8 @@ static LLVMValueRef ir_render_bin_op(CodeGen *g, IrExecutable *executable,
|
||||
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, type_entry->data.integral.is_signed);
|
||||
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
|
||||
} else if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
if (type_entry->data.enumeration.gen_field_count == 0) {
|
||||
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
|
||||
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
LLVMIntPredicate pred = cmp_op_to_int_predicate(op_id, false);
|
||||
return LLVMBuildICmp(g->builder, pred, op1_value, op2_value, "");
|
||||
} else if (type_entry->id == TypeTableEntryIdPureError ||
|
||||
type_entry->id == TypeTableEntryIdPointer ||
|
||||
type_entry->id == TypeTableEntryIdBool)
|
||||
@ -1920,9 +1916,7 @@ static LLVMValueRef ir_render_widen_or_shorten(CodeGen *g, IrExecutable *executa
|
||||
// enum_tag to the underlying int type
|
||||
TypeTableEntry *int_type;
|
||||
if (actual_type->id == TypeTableEntryIdEnum) {
|
||||
TypeTableEntry *tag_type = actual_type->data.enumeration.tag_type;
|
||||
assert(tag_type->id == TypeTableEntryIdEnumTag);
|
||||
int_type = tag_type->data.enum_tag.int_type;
|
||||
int_type = actual_type->data.enumeration.tag_int_type;
|
||||
} else {
|
||||
int_type = actual_type;
|
||||
}
|
||||
@ -1946,19 +1940,11 @@ static LLVMValueRef ir_render_ptr_to_int(CodeGen *g, IrExecutable *executable, I
|
||||
static LLVMValueRef ir_render_int_to_enum(CodeGen *g, IrExecutable *executable, IrInstructionIntToEnum *instruction) {
|
||||
TypeTableEntry *wanted_type = instruction->base.value.type;
|
||||
assert(wanted_type->id == TypeTableEntryIdEnum);
|
||||
TypeTableEntry *tag_type = wanted_type->data.enumeration.tag_type;
|
||||
TypeTableEntry *wanted_int_type;
|
||||
if (tag_type->id == TypeTableEntryIdEnumTag) {
|
||||
wanted_int_type = tag_type->data.enum_tag.int_type;
|
||||
} else if (tag_type->id == TypeTableEntryIdInt) {
|
||||
wanted_int_type = tag_type;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
TypeTableEntry *tag_int_type = wanted_type->data.enumeration.tag_int_type;
|
||||
|
||||
LLVMValueRef target_val = ir_llvm_value(g, instruction->target);
|
||||
return gen_widen_or_shorten(g, ir_want_debug_safety(g, &instruction->base),
|
||||
instruction->target->value.type, wanted_int_type, target_val);
|
||||
instruction->target->value.type, tag_int_type, target_val);
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_int_to_err(CodeGen *g, IrExecutable *executable, IrInstructionIntToErr *instruction) {
|
||||
@ -2378,27 +2364,6 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa
|
||||
return LLVMBuildStructGEP(g->builder, struct_ptr, (unsigned)field->gen_index, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionEnumFieldPtr *instruction)
|
||||
{
|
||||
TypeTableEntry *enum_ptr_type = instruction->enum_ptr->value.type;
|
||||
assert(enum_ptr_type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *enum_type = enum_ptr_type->data.pointer.child_type;
|
||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
TypeEnumField *field = instruction->field;
|
||||
|
||||
if (!type_has_bits(field->type_entry))
|
||||
return nullptr;
|
||||
|
||||
LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr);
|
||||
LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_type->data.enumeration.gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, "");
|
||||
|
||||
return bitcasted_union_field_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionUnionFieldPtr *instruction)
|
||||
{
|
||||
@ -2427,7 +2392,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
|
||||
|
||||
|
||||
LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
|
||||
&field->value);
|
||||
&field->enum_field->value);
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckOk");
|
||||
LLVMBasicBlockRef bad_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnionCheckFail");
|
||||
LLVMValueRef ok_val = LLVMBuildICmp(g->builder, LLVMIntEQ, tag_value, expected_tag_value, "");
|
||||
@ -2754,19 +2719,19 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI
|
||||
static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable,
|
||||
IrInstructionEnumTagName *instruction)
|
||||
{
|
||||
TypeTableEntry *enum_tag_type = instruction->target->value.type;
|
||||
assert(enum_tag_type->data.enum_tag.generate_name_table);
|
||||
TypeTableEntry *enum_type = instruction->target->value.type;
|
||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||
assert(enum_type->data.enumeration.generate_name_table);
|
||||
|
||||
TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type;
|
||||
LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target);
|
||||
if (ir_want_debug_safety(g, &instruction->base)) {
|
||||
TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
|
||||
size_t field_count = enum_type->data.enumeration.src_field_count;
|
||||
|
||||
// if the field_count can't fit in the bits of the enum_tag_type, then it can't possibly
|
||||
// if the field_count can't fit in the bits of the enum_type, then it can't possibly
|
||||
// be the wrong value
|
||||
BigInt field_bi;
|
||||
bigint_init_unsigned(&field_bi, field_count);
|
||||
TypeTableEntry *tag_int_type = enum_tag_type->data.enum_tag.int_type;
|
||||
if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) {
|
||||
LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false);
|
||||
add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val);
|
||||
@ -2775,10 +2740,10 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable
|
||||
|
||||
LLVMValueRef indices[] = {
|
||||
LLVMConstNull(g->builtin_types.entry_usize->type_ref),
|
||||
gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type,
|
||||
gen_widen_or_shorten(g, false, tag_int_type,
|
||||
g->builtin_types.entry_usize, enum_tag_value),
|
||||
};
|
||||
return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, "");
|
||||
return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable,
|
||||
@ -3352,48 +3317,24 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa
|
||||
return instruction->tmp_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrInstructionEnumTag *instruction) {
|
||||
TypeTableEntry *enum_type = instruction->value->value.type;
|
||||
TypeTableEntry *tag_type = enum_type->data.enumeration.tag_type;
|
||||
static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) {
|
||||
TypeTableEntry *union_type = instruction->value->value.type;
|
||||
assert(union_type->data.unionation.gen_tag_index != SIZE_MAX);
|
||||
|
||||
TypeTableEntry *tag_type = union_type->data.unionation.tag_type;
|
||||
if (!type_has_bits(tag_type))
|
||||
return nullptr;
|
||||
|
||||
LLVMValueRef enum_val = ir_llvm_value(g, instruction->value);
|
||||
if (enum_type->data.enumeration.gen_field_count == 0)
|
||||
return enum_val;
|
||||
LLVMValueRef union_val = ir_llvm_value(g, instruction->value);
|
||||
if (union_type->data.unionation.gen_field_count == 0)
|
||||
return union_val;
|
||||
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, enum_val, enum_type->data.enumeration.gen_tag_index, "");
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_val,
|
||||
union_type->data.unionation.gen_tag_index, "");
|
||||
TypeTableEntry *ptr_type = get_pointer_to_type(g, tag_type, false);
|
||||
return get_handle_value(g, tag_field_ptr, tag_type, ptr_type);
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
|
||||
TypeTableEntry *enum_type = instruction->enum_type;
|
||||
LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
|
||||
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &instruction->field->value);
|
||||
|
||||
if (enum_type->data.enumeration.gen_field_count == 0)
|
||||
return tag_value;
|
||||
|
||||
LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr;
|
||||
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_tag_index, "");
|
||||
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
|
||||
|
||||
TypeTableEntry *union_val_type = instruction->field->type_entry;
|
||||
if (type_has_bits(union_val_type)) {
|
||||
LLVMValueRef new_union_val = ir_llvm_value(g, instruction->init_value);
|
||||
LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, enum_type->data.enumeration.gen_union_index, "");
|
||||
LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr,
|
||||
LLVMPointerType(union_val_type->type_ref, 0), "");
|
||||
|
||||
gen_assign_raw(g, bitcasted_union_field_ptr, get_pointer_to_type(g, union_val_type, false), new_union_val);
|
||||
}
|
||||
|
||||
return tmp_struct_ptr;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) {
|
||||
for (size_t i = 0; i < instruction->field_count; i += 1) {
|
||||
IrInstructionStructInitField *field = &instruction->fields[i];
|
||||
@ -3436,7 +3377,7 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
|
||||
union_type->data.unionation.gen_tag_index, "");
|
||||
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
|
||||
&type_union_field->value);
|
||||
&type_union_field->enum_field->value);
|
||||
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
|
||||
|
||||
uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
|
||||
@ -3573,8 +3514,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_call(g, executable, (IrInstructionCall *)instruction);
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction);
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
|
||||
case IrInstructionIdAsm:
|
||||
@ -3629,10 +3568,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction);
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction);
|
||||
case IrInstructionIdEnumTag:
|
||||
return ir_render_enum_tag(g, executable, (IrInstructionEnumTag *)instruction);
|
||||
case IrInstructionIdInitEnum:
|
||||
return ir_render_init_enum(g, executable, (IrInstructionInitEnum *)instruction);
|
||||
case IrInstructionIdUnionTag:
|
||||
return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction);
|
||||
case IrInstructionIdStructInit:
|
||||
return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction);
|
||||
case IrInstructionIdUnionInit:
|
||||
@ -3768,7 +3705,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
@ -3780,7 +3716,6 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con
|
||||
return LLVMConstInt(big_int_type_ref, const_val->data.x_bool ? 1 : 0, false);
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
assert(type_entry->data.enumeration.gen_field_count == 0);
|
||||
assert(type_entry->data.enumeration.decl_node->data.container_decl.init_arg_expr != nullptr);
|
||||
LLVMValueRef int_val = gen_const_val(g, const_val);
|
||||
return LLVMConstZExt(int_val, big_int_type_ref);
|
||||
@ -3852,7 +3787,6 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_bigint);
|
||||
case TypeTableEntryIdPureError:
|
||||
assert(const_val->data.x_pure_err);
|
||||
@ -4015,34 +3949,48 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
ConstExprValue *payload_value = const_val->data.x_union.payload;
|
||||
assert(payload_value != nullptr);
|
||||
|
||||
if (!type_has_bits(payload_value->type)) {
|
||||
return LLVMGetUndef(union_type_ref);
|
||||
}
|
||||
|
||||
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
|
||||
uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
|
||||
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
|
||||
bool make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
|
||||
payload_value->type != type_entry->data.unionation.most_aligned_union_member;
|
||||
|
||||
LLVMValueRef union_value_ref;
|
||||
{
|
||||
if (pad_bytes == 0) {
|
||||
union_value_ref = correctly_typed_value;
|
||||
if (type_entry->data.unionation.gen_field_count == 0) {
|
||||
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
|
||||
return nullptr;
|
||||
} else {
|
||||
LLVMValueRef fields[2];
|
||||
fields[0] = correctly_typed_value;
|
||||
fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
|
||||
if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
|
||||
union_value_ref = LLVMConstStruct(fields, 2, false);
|
||||
} else {
|
||||
union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
|
||||
}
|
||||
return bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
|
||||
&const_val->data.x_union.tag);
|
||||
}
|
||||
}
|
||||
|
||||
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
|
||||
return union_value_ref;
|
||||
LLVMValueRef union_value_ref;
|
||||
bool make_unnamed_struct;
|
||||
if (!type_has_bits(payload_value->type)) {
|
||||
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX)
|
||||
return LLVMGetUndef(type_entry->type_ref);
|
||||
|
||||
union_value_ref = LLVMGetUndef(type_entry->data.unionation.most_aligned_union_member->type_ref);
|
||||
make_unnamed_struct = false;
|
||||
} else {
|
||||
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref, payload_value->type->type_ref);
|
||||
uint64_t pad_bytes = type_entry->data.unionation.union_size_bytes - field_type_bytes;
|
||||
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
|
||||
make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
|
||||
payload_value->type != type_entry->data.unionation.most_aligned_union_member;
|
||||
|
||||
{
|
||||
if (pad_bytes == 0) {
|
||||
union_value_ref = correctly_typed_value;
|
||||
} else {
|
||||
LLVMValueRef fields[2];
|
||||
fields[0] = correctly_typed_value;
|
||||
fields[1] = LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes));
|
||||
if (make_unnamed_struct || type_entry->data.unionation.gen_tag_index != SIZE_MAX) {
|
||||
union_value_ref = LLVMConstStruct(fields, 2, false);
|
||||
} else {
|
||||
union_value_ref = LLVMConstNamedStruct(union_type_ref, fields, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (type_entry->data.unionation.gen_tag_index == SIZE_MAX) {
|
||||
return union_value_ref;
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
|
||||
@ -4059,55 +4007,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
LLVMTypeRef tag_type_ref = type_entry->data.enumeration.tag_type->type_ref;
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(tag_type_ref, &const_val->data.x_enum.tag);
|
||||
if (type_entry->data.enumeration.gen_field_count == 0) {
|
||||
return tag_value;
|
||||
} else {
|
||||
LLVMTypeRef union_type_ref = type_entry->data.enumeration.union_type_ref;
|
||||
TypeEnumField *enum_field = find_enum_field_by_tag(type_entry, &const_val->data.x_enum.tag);
|
||||
assert(bigint_cmp(&enum_field->value, &const_val->data.x_enum.tag) == CmpEQ);
|
||||
LLVMValueRef union_value;
|
||||
|
||||
bool make_unnamed_struct;
|
||||
|
||||
if (type_has_bits(enum_field->type_entry)) {
|
||||
uint64_t field_type_bytes = LLVMStoreSizeOfType(g->target_data_ref,
|
||||
enum_field->type_entry->type_ref);
|
||||
uint64_t pad_bytes = type_entry->data.enumeration.union_size_bytes - field_type_bytes;
|
||||
|
||||
ConstExprValue *payload_value = const_val->data.x_enum.payload;
|
||||
LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value);
|
||||
|
||||
make_unnamed_struct = is_llvm_value_unnamed_type(payload_value->type, correctly_typed_value) ||
|
||||
payload_value->type != type_entry->data.enumeration.most_aligned_union_member;
|
||||
|
||||
if (pad_bytes == 0) {
|
||||
union_value = correctly_typed_value;
|
||||
} else {
|
||||
LLVMValueRef fields[] = {
|
||||
correctly_typed_value,
|
||||
LLVMGetUndef(LLVMArrayType(LLVMInt8Type(), (unsigned)pad_bytes)),
|
||||
};
|
||||
union_value = LLVMConstStruct(fields, 2, false);
|
||||
}
|
||||
} else {
|
||||
make_unnamed_struct = false;
|
||||
union_value = LLVMGetUndef(union_type_ref);
|
||||
}
|
||||
LLVMValueRef fields[2];
|
||||
fields[type_entry->data.enumeration.gen_tag_index] = tag_value;
|
||||
fields[type_entry->data.enumeration.gen_union_index] = union_value;
|
||||
|
||||
if (make_unnamed_struct) {
|
||||
return LLVMConstStruct(fields, 2, false);
|
||||
} else {
|
||||
return LLVMConstNamedStruct(type_entry->type_ref, fields, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bigint_to_llvm_const(type_entry->type_ref, &const_val->data.x_enum_tag);
|
||||
case TypeTableEntryIdFn:
|
||||
return fn_llvm_value(g, const_val->data.x_fn.fn_entry);
|
||||
case TypeTableEntryIdPointer:
|
||||
@ -4318,9 +4220,8 @@ static void generate_enum_name_tables(CodeGen *g) {
|
||||
|
||||
|
||||
for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) {
|
||||
TypeTableEntry *enum_tag_type = g->name_table_enums.at(enum_i);
|
||||
assert(enum_tag_type->id == TypeTableEntryIdEnumTag);
|
||||
TypeTableEntry *enum_type = enum_tag_type->data.enum_tag.enum_type;
|
||||
TypeTableEntry *enum_type = g->name_table_enums.at(enum_i);
|
||||
assert(enum_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
size_t field_count = enum_type->data.enumeration.src_field_count;
|
||||
LLVMValueRef *values = allocate<LLVMValueRef>(field_count);
|
||||
@ -4351,7 +4252,7 @@ static void generate_enum_name_tables(CodeGen *g) {
|
||||
LLVMSetGlobalConstant(name_table, true);
|
||||
LLVMSetUnnamedAddr(name_table, true);
|
||||
LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init)));
|
||||
enum_tag_type->data.enum_tag.name_table = name_table;
|
||||
enum_type->data.enumeration.name_table = name_table;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4555,9 +4456,6 @@ static void do_code_gen(CodeGen *g) {
|
||||
} else if (instruction->id == IrInstructionIdErrWrapCode) {
|
||||
IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction;
|
||||
slot = &err_wrap_code_instruction->tmp_ptr;
|
||||
} else if (instruction->id == IrInstructionIdInitEnum) {
|
||||
IrInstructionInitEnum *init_enum_instruction = (IrInstructionInitEnum *)instruction;
|
||||
slot = &init_enum_instruction->tmp_ptr;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -5054,7 +4952,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdTruncate, "truncate", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdCompileErr, "compileError", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
|
||||
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdIntType, "IntType", 2); // TODO rename to Int
|
||||
create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSetFloatMode, "setFloatMode", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
|
||||
@ -5064,7 +4962,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn(g, BuiltinFnIdBitCast, "bitCast", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdIntToPtr, "intToPtr", 2);
|
||||
create_builtin_fn(g, BuiltinFnIdPtrToInt, "ptrToInt", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdEnumTagName, "enumTagName", 1); // TODO rename to memberName
|
||||
create_builtin_fn(g, BuiltinFnIdTagName, "tagName", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdEnumTagType, "EnumTagType", 1);
|
||||
create_builtin_fn(g, BuiltinFnIdFieldParentPtr, "fieldParentPtr", 3);
|
||||
create_builtin_fn(g, BuiltinFnIdOffsetOf, "offsetOf", 2);
|
||||
@ -5681,7 +5579,6 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) {
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO implement get_c_type for more types");
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdMetaType:
|
||||
|
||||
488
src/ir.cpp
488
src/ir.cpp
@ -223,10 +223,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructFieldPtr *
|
||||
return IrInstructionIdStructFieldPtr;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) {
|
||||
return IrInstructionIdEnumFieldPtr;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionFieldPtr *) {
|
||||
return IrInstructionIdUnionFieldPtr;
|
||||
}
|
||||
@ -319,8 +315,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCtz *) {
|
||||
return IrInstructionIdCtz;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumTag *) {
|
||||
return IrInstructionIdEnumTag;
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionTag *) {
|
||||
return IrInstructionIdUnionTag;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionImport *) {
|
||||
@ -479,10 +475,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestComptime *)
|
||||
return IrInstructionIdTestComptime;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionInitEnum *) {
|
||||
return IrInstructionIdInitEnum;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCast *) {
|
||||
return IrInstructionIdPtrCast;
|
||||
}
|
||||
@ -913,27 +905,6 @@ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstructi
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *enum_ptr, TypeEnumField *field)
|
||||
{
|
||||
IrInstructionEnumFieldPtr *instruction = ir_build_instruction<IrInstructionEnumFieldPtr>(irb, scope, source_node);
|
||||
instruction->enum_ptr = enum_ptr;
|
||||
instruction->field = field;
|
||||
|
||||
ir_ref_instruction(enum_ptr, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
IrInstruction *enum_ptr, TypeEnumField *type_enum_field)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->scope,
|
||||
old_instruction->source_node, enum_ptr, type_enum_field);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *union_ptr, TypeUnionField *field)
|
||||
{
|
||||
@ -1528,8 +1499,8 @@ static IrInstruction *ir_build_switch_var(IrBuilder *irb, Scope *scope, AstNode
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
|
||||
IrInstructionEnumTag *instruction = ir_build_instruction<IrInstructionEnumTag>(irb, scope, source_node);
|
||||
static IrInstruction *ir_build_union_tag(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) {
|
||||
IrInstructionUnionTag *instruction = ir_build_instruction<IrInstructionUnionTag>(irb, scope, source_node);
|
||||
instruction->value = value;
|
||||
|
||||
ir_ref_instruction(value, irb->current_basic_block);
|
||||
@ -1537,13 +1508,6 @@ static IrInstruction *ir_build_enum_tag(IrBuilder *irb, Scope *scope, AstNode *s
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_enum_tag_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction *value) {
|
||||
IrInstruction *new_instruction = ir_build_enum_tag(irb, old_instruction->scope,
|
||||
old_instruction->source_node, value);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_import(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *name) {
|
||||
IrInstructionImport *instruction = ir_build_instruction<IrInstructionImport>(irb, scope, source_node);
|
||||
instruction->name = name;
|
||||
@ -2033,28 +1997,6 @@ static IrInstruction *ir_build_test_comptime(IrBuilder *irb, Scope *scope, AstNo
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_init_enum(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
|
||||
{
|
||||
IrInstructionInitEnum *instruction = ir_build_instruction<IrInstructionInitEnum>(irb, scope, source_node);
|
||||
instruction->enum_type = enum_type;
|
||||
instruction->field = field;
|
||||
instruction->init_value = init_value;
|
||||
|
||||
ir_ref_instruction(init_value, irb->current_basic_block);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_init_enum_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
TypeTableEntry *enum_type, TypeEnumField *field, IrInstruction *init_value)
|
||||
{
|
||||
IrInstruction *new_instruction = ir_build_init_enum(irb, old_instruction->scope, old_instruction->source_node,
|
||||
enum_type, field, init_value);
|
||||
ir_link_new_instruction(new_instruction, old_instruction);
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_ptr_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *dest_type, IrInstruction *ptr)
|
||||
{
|
||||
@ -2481,13 +2423,6 @@ static IrInstruction *ir_instruction_structfieldptr_get_dep(IrInstructionStructF
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_enumfieldptr_get_dep(IrInstructionEnumFieldPtr *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->enum_ptr;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_unionfieldptr_get_dep(IrInstructionUnionFieldPtr *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->union_ptr;
|
||||
@ -2657,7 +2592,7 @@ static IrInstruction *ir_instruction_maybewrap_get_dep(IrInstructionMaybeWrap *i
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_enumtag_get_dep(IrInstructionEnumTag *instruction, size_t index) {
|
||||
static IrInstruction *ir_instruction_uniontag_get_dep(IrInstructionUnionTag *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->value;
|
||||
default: return nullptr;
|
||||
@ -2943,13 +2878,6 @@ static IrInstruction *ir_instruction_testcomptime_get_dep(IrInstructionTestCompt
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_initenum_get_dep(IrInstructionInitEnum *instruction, size_t index) {
|
||||
switch (index) {
|
||||
case 0: return instruction->init_value;
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_instruction_ptrcast_get_dep(IrInstructionPtrCast *instruction,
|
||||
size_t index)
|
||||
{
|
||||
@ -3184,8 +3112,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_fieldptr_get_dep((IrInstructionFieldPtr *) instruction, index);
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
return ir_instruction_structfieldptr_get_dep((IrInstructionStructFieldPtr *) instruction, index);
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
return ir_instruction_enumfieldptr_get_dep((IrInstructionEnumFieldPtr *) instruction, index);
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
return ir_instruction_unionfieldptr_get_dep((IrInstructionUnionFieldPtr *) instruction, index);
|
||||
case IrInstructionIdElemPtr:
|
||||
@ -3234,8 +3160,8 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_unwrapmaybe_get_dep((IrInstructionUnwrapMaybe *) instruction, index);
|
||||
case IrInstructionIdMaybeWrap:
|
||||
return ir_instruction_maybewrap_get_dep((IrInstructionMaybeWrap *) instruction, index);
|
||||
case IrInstructionIdEnumTag:
|
||||
return ir_instruction_enumtag_get_dep((IrInstructionEnumTag *) instruction, index);
|
||||
case IrInstructionIdUnionTag:
|
||||
return ir_instruction_uniontag_get_dep((IrInstructionUnionTag *) instruction, index);
|
||||
case IrInstructionIdClz:
|
||||
return ir_instruction_clz_get_dep((IrInstructionClz *) instruction, index);
|
||||
case IrInstructionIdCtz:
|
||||
@ -3312,8 +3238,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
|
||||
return ir_instruction_fnproto_get_dep((IrInstructionFnProto *) instruction, index);
|
||||
case IrInstructionIdTestComptime:
|
||||
return ir_instruction_testcomptime_get_dep((IrInstructionTestComptime *) instruction, index);
|
||||
case IrInstructionIdInitEnum:
|
||||
return ir_instruction_initenum_get_dep((IrInstructionInitEnum *) instruction, index);
|
||||
case IrInstructionIdPtrCast:
|
||||
return ir_instruction_ptrcast_get_dep((IrInstructionPtrCast *) instruction, index);
|
||||
case IrInstructionIdBitCast:
|
||||
@ -4695,14 +4619,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
|
||||
|
||||
return ir_build_ptr_to_int(irb, scope, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdEnumTagName:
|
||||
case BuiltinFnIdTagName:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
IrInstruction *actual_tag = ir_build_enum_tag(irb, scope, node, arg0_value);
|
||||
IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value);
|
||||
return ir_build_enum_tag_name(irb, scope, node, actual_tag);
|
||||
}
|
||||
case BuiltinFnIdEnumTagType:
|
||||
@ -8381,13 +8305,28 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
|
||||
{
|
||||
assert(wanted_type->id == TypeTableEntryIdInt);
|
||||
|
||||
TypeTableEntry *actual_type = target->value.type;
|
||||
ensure_complete_type(ira->codegen, actual_type);
|
||||
if (type_is_invalid(actual_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (wanted_type != actual_type->data.enumeration.tag_int_type) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
|
||||
buf_ptr(&wanted_type->name),
|
||||
buf_ptr(&actual_type->data.enumeration.tag_int_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
assert(actual_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
init_const_bigint(&result->value, wanted_type, &val->data.x_enum.tag);
|
||||
init_const_bigint(&result->value, wanted_type, &val->data.x_enum_tag);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -8397,6 +8336,31 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_union_to_tag(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *target, TypeTableEntry *wanted_type)
|
||||
{
|
||||
assert(target->value.type->id == TypeTableEntryIdUnion);
|
||||
assert(wanted_type->id == TypeTableEntryIdEnum);
|
||||
assert(wanted_type == target->value.type->data.unionation.tag_type);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
|
||||
if (!val)
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
result->value.special = ConstValSpecialStatic;
|
||||
result->value.type = wanted_type;
|
||||
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_union.tag);
|
||||
return result;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, target);
|
||||
result->value.type = wanted_type;
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruction *source_instr,
|
||||
IrInstruction *target, TypeTableEntry *wanted_type)
|
||||
{
|
||||
@ -8452,6 +8416,22 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
|
||||
{
|
||||
assert(wanted_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
TypeTableEntry *actual_type = target->value.type;
|
||||
|
||||
ensure_complete_type(ira->codegen, wanted_type);
|
||||
if (type_is_invalid(wanted_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (actual_type != wanted_type->data.enumeration.tag_int_type) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
|
||||
buf_ptr(&actual_type->name),
|
||||
buf_ptr(&wanted_type->data.enumeration.tag_int_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
assert(actual_type->id == TypeTableEntryIdInt);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, target, UndefBad);
|
||||
if (!val)
|
||||
@ -8469,7 +8449,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour
|
||||
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
bigint_init_bigint(&result->value.data.x_enum.tag, &val->data.x_bigint);
|
||||
bigint_init_bigint(&result->value.data.x_enum_tag, &val->data.x_bigint);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -8907,39 +8887,24 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst
|
||||
}
|
||||
|
||||
// explicit cast from integer to enum type with no payload
|
||||
if (actual_type->id == TypeTableEntryIdInt &&
|
||||
wanted_type->id == TypeTableEntryIdEnum &&
|
||||
wanted_type->data.enumeration.gen_field_count == 0)
|
||||
{
|
||||
ensure_complete_type(ira->codegen, wanted_type);
|
||||
if (type_is_invalid(wanted_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (actual_type == wanted_type->data.enumeration.tag_type->data.enum_tag.int_type) {
|
||||
return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("integer to enum cast from '%s' instead of its tag type, '%s'",
|
||||
buf_ptr(&actual_type->name),
|
||||
buf_ptr(&wanted_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdEnum) {
|
||||
return ir_analyze_int_to_enum(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
|
||||
// explicit cast from enum type with no payload to integer
|
||||
if (wanted_type->id == TypeTableEntryIdInt &&
|
||||
actual_type->id == TypeTableEntryIdEnum &&
|
||||
actual_type->data.enumeration.gen_field_count == 0)
|
||||
{
|
||||
ensure_complete_type(ira->codegen, actual_type);
|
||||
if (wanted_type->id == TypeTableEntryIdInt && actual_type->id == TypeTableEntryIdEnum) {
|
||||
return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
|
||||
// explicit cast from union to the enum type of the union
|
||||
if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
|
||||
type_ensure_zero_bits_known(ira->codegen, actual_type);
|
||||
if (type_is_invalid(actual_type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
if (wanted_type == actual_type->data.enumeration.tag_type->data.enum_tag.int_type) {
|
||||
return ir_analyze_enum_to_int(ira, source_instr, value, wanted_type);
|
||||
|
||||
if (actual_type->data.unionation.tag_type == wanted_type) {
|
||||
return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
|
||||
}
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("enum to integer cast to '%s' instead of its tag type, '%s'",
|
||||
buf_ptr(&wanted_type->name),
|
||||
buf_ptr(&actual_type->data.enumeration.tag_type->data.enum_tag.int_type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
// explicit cast from undefined to anything
|
||||
@ -9148,7 +9113,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
*out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9168,7 +9133,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
*out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum_tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9188,7 +9153,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
*out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum_tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9400,7 +9365,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
|
||||
break;
|
||||
|
||||
case TypeTableEntryIdEnum:
|
||||
if (!is_equality_cmp || resolved_type->data.enumeration.gen_field_count != 0) {
|
||||
if (!is_equality_cmp) {
|
||||
ir_add_error_node(ira, source_node,
|
||||
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
@ -9419,9 +9384,6 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp
|
||||
buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO implement comparison for enum tag type");
|
||||
|
||||
case TypeTableEntryIdVar:
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -10170,7 +10132,6 @@ static VarClassRequired get_var_class_required(TypeTableEntry *type_entry) {
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
return VarClassRequiredAny;
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
@ -10913,7 +10874,6 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
{
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
|
||||
TypeTableEntry *result_type = get_error_type(ira->codegen, meta_type);
|
||||
@ -11001,7 +10961,6 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
{
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base);
|
||||
@ -11662,15 +11621,8 @@ static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field
|
||||
field_ptr_instruction, container_ptr, container_type);
|
||||
}
|
||||
} else if (bare_type->id == TypeTableEntryIdEnum) {
|
||||
TypeEnumField *field = find_enum_type_field(bare_type, field_name);
|
||||
if (field) {
|
||||
ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field);
|
||||
return get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile,
|
||||
get_abi_alignment(ira->codegen, field->type_entry), 0, 0);
|
||||
} else {
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
field_ptr_instruction, container_ptr, container_type);
|
||||
}
|
||||
return ir_analyze_container_member_access_inner(ira, bare_type, field_name,
|
||||
field_ptr_instruction, container_ptr, container_type);
|
||||
} else if (bare_type->id == TypeTableEntryIdUnion) {
|
||||
TypeUnionField *field = find_union_type_field(bare_type, field_name);
|
||||
if (field) {
|
||||
@ -11841,20 +11793,27 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
|
||||
TypeEnumField *field = find_enum_type_field(child_type, field_name);
|
||||
if (field) {
|
||||
if (field->type_entry->id == TypeTableEntryIdVoid) {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_enum_tag(child_type, &field->value), child_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
} else {
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_bigint(child_type->data.enumeration.tag_type, &field->value),
|
||||
child_type->data.enumeration.tag_type,
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_enum(child_type, &field->value), child_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
} else if (child_type->id == TypeTableEntryIdUnion &&
|
||||
(child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr ||
|
||||
child_type->data.unionation.decl_node->data.container_decl.auto_enum))
|
||||
{
|
||||
ensure_complete_type(ira->codegen, child_type);
|
||||
if (type_is_invalid(child_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
TypeUnionField *field = find_union_type_field(child_type, field_name);
|
||||
if (field) {
|
||||
TypeTableEntry *enum_type = child_type->data.unionation.tag_type;
|
||||
bool ptr_is_const = true;
|
||||
bool ptr_is_volatile = false;
|
||||
return ir_analyze_const_ptr(ira, &field_ptr_instruction->base,
|
||||
create_const_enum(enum_type, &field->enum_field->value), enum_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
}
|
||||
}
|
||||
ScopeDecls *container_scope = get_container_scope(child_type);
|
||||
@ -12163,7 +12122,6 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
case TypeTableEntryIdOpaque:
|
||||
{
|
||||
@ -12511,7 +12469,6 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
{
|
||||
type_ensure_zero_bits_known(ira->codegen, child_type);
|
||||
TypeTableEntry *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type,
|
||||
@ -12620,7 +12577,6 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
{
|
||||
TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base);
|
||||
@ -12671,7 +12627,6 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira,
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdFn:
|
||||
{
|
||||
uint64_t size_in_bytes = type_size(ira->codegen, type_entry);
|
||||
@ -12824,17 +12779,22 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC
|
||||
}
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
|
||||
static IrInstruction *ir_analyze_union_tag(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value) {
|
||||
if (type_is_invalid(value->value.type))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (value->value.type->id != TypeTableEntryIdEnum) {
|
||||
if (value->value.type->id == TypeTableEntryIdEnum) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value->value.type->id != TypeTableEntryIdUnion) {
|
||||
ir_add_error(ira, source_instr,
|
||||
buf_sprintf("expected enum type, found '%s'", buf_ptr(&value->value.type->name)));
|
||||
buf_sprintf("expected enum or union type, found '%s'", buf_ptr(&value->value.type->name)));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
TypeTableEntry *tag_type = value->value.type->data.enumeration.tag_type;
|
||||
TypeTableEntry *tag_type = value->value.type->data.unionation.tag_type;
|
||||
assert(tag_type->id == TypeTableEntryIdEnum);
|
||||
|
||||
if (instr_is_comptime(value)) {
|
||||
ConstExprValue *val = ir_resolve_const(ira, value, UndefBad);
|
||||
@ -12845,11 +12805,11 @@ static IrInstruction *ir_analyze_enum_tag(IrAnalyze *ira, IrInstruction *source_
|
||||
source_instr->scope, source_instr->source_node);
|
||||
const_instruction->base.value.type = tag_type;
|
||||
const_instruction->base.value.special = ConstValSpecialStatic;
|
||||
bigint_init_bigint(&const_instruction->base.value.data.x_bigint, &val->data.x_enum.tag);
|
||||
bigint_init_bigint(&const_instruction->base.value.data.x_enum_tag, &val->data.x_union.tag);
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_enum_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
|
||||
IrInstruction *result = ir_build_union_tag(&ira->new_irb, source_instr->scope, source_instr->source_node, value);
|
||||
result->value.type = tag_type;
|
||||
return result;
|
||||
}
|
||||
@ -12880,7 +12840,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
|
||||
return ir_unreach_error(ira);
|
||||
|
||||
if (case_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
case_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, case_value);
|
||||
case_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, case_value);
|
||||
if (type_is_invalid(case_value->value.type))
|
||||
return ir_unreach_error(ira);
|
||||
}
|
||||
@ -12927,7 +12887,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira,
|
||||
continue;
|
||||
|
||||
if (new_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
new_value = ir_analyze_enum_tag(ira, &switch_br_instruction->base, new_value);
|
||||
new_value = ir_analyze_union_tag(ira, &switch_br_instruction->base, new_value);
|
||||
if (type_is_invalid(new_value->value.type))
|
||||
continue;
|
||||
}
|
||||
@ -13009,34 +12969,54 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
|
||||
ir_build_load_ptr_from(&ira->new_irb, &switch_target_instruction->base, target_value_ptr);
|
||||
return target_type;
|
||||
case TypeTableEntryIdEnum:
|
||||
{
|
||||
TypeTableEntry *tag_type = target_type->data.enumeration.tag_type;
|
||||
assert(tag_type != nullptr);
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
|
||||
bigint_init_bigint(&out_val->data.x_bigint, &pointee_val->data.x_enum.tag);
|
||||
return tag_type;
|
||||
}
|
||||
|
||||
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
|
||||
switch_target_instruction->base.source_node, target_value_ptr);
|
||||
enum_value->value.type = target_type;
|
||||
ir_build_enum_tag_from(&ira->new_irb, &switch_target_instruction->base, enum_value);
|
||||
case TypeTableEntryIdUnion: {
|
||||
if (target_type->data.unionation.gen_tag_index == SIZE_MAX) {
|
||||
ErrorMsg *msg = ir_add_error(ira, target_value_ptr,
|
||||
buf_sprintf("switch on union which has no attached enum"));
|
||||
add_error_note(ira->codegen, msg, target_type->data.unionation.decl_node,
|
||||
buf_sprintf("union declared here"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeTableEntry *tag_type = target_type->data.unionation.tag_type;
|
||||
assert(tag_type != nullptr);
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
|
||||
bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_union.tag);
|
||||
return tag_type;
|
||||
}
|
||||
|
||||
IrInstruction *union_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
|
||||
switch_target_instruction->base.source_node, target_value_ptr);
|
||||
union_value->value.type = target_type;
|
||||
|
||||
IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope,
|
||||
switch_target_instruction->base.source_node, union_value);
|
||||
union_tag_inst->value.type = tag_type;
|
||||
ir_link_new_instruction(union_tag_inst, &switch_target_instruction->base);
|
||||
return tag_type;
|
||||
}
|
||||
case TypeTableEntryIdEnum: {
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
|
||||
bigint_init_bigint(&out_val->data.x_enum_tag, &pointee_val->data.x_enum_tag);
|
||||
return target_type;
|
||||
}
|
||||
|
||||
IrInstruction *enum_value = ir_build_load_ptr(&ira->new_irb, switch_target_instruction->base.scope,
|
||||
switch_target_instruction->base.source_node, target_value_ptr);
|
||||
enum_value->value.type = target_type;
|
||||
ir_link_new_instruction(enum_value, &switch_target_instruction->base);
|
||||
return target_type;
|
||||
}
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
// see https://github.com/andrewrk/zig/issues/83
|
||||
// see https://github.com/andrewrk/zig/issues/632
|
||||
zig_panic("TODO switch on error union");
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO switch on enum tag type");
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdBlock:
|
||||
case TypeTableEntryIdBoundFn:
|
||||
case TypeTableEntryIdArgTuple:
|
||||
@ -13059,19 +13039,13 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
|
||||
|
||||
assert(target_value_ptr->value.type->id == TypeTableEntryIdPointer);
|
||||
TypeTableEntry *target_type = target_value_ptr->value.type->data.pointer.child_type;
|
||||
if (target_type->id == TypeTableEntryIdEnum) {
|
||||
if (target_type->id == TypeTableEntryIdUnion) {
|
||||
ConstExprValue *prong_val = ir_resolve_const(ira, prong_value, UndefBad);
|
||||
if (!prong_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
TypeEnumField *field;
|
||||
if (prong_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
field = find_enum_field_by_tag(target_type, &prong_val->data.x_bigint);
|
||||
} else if (prong_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
field = find_enum_field_by_tag(target_type, &prong_val->data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
assert(prong_value->value.type->id == TypeTableEntryIdEnum);
|
||||
TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag);
|
||||
|
||||
if (instr_is_comptime(target_value_ptr)) {
|
||||
ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad);
|
||||
@ -13082,11 +13056,11 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_ptr.special = ConstPtrSpecialRef;
|
||||
out_val->data.x_ptr.mut = target_val_ptr->data.x_ptr.mut;
|
||||
out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_enum.payload;
|
||||
out_val->data.x_ptr.data.ref.pointee = pointee_val->data.x_union.payload;
|
||||
return get_pointer_to_type(ira->codegen, field->type_entry, target_val_ptr->type->data.pointer.is_const);
|
||||
}
|
||||
|
||||
ir_build_enum_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
|
||||
ir_build_union_field_ptr_from(&ira->new_irb, &instruction->base, target_value_ptr, field);
|
||||
return get_pointer_to_type(ira->codegen, field->type_entry,
|
||||
target_value_ptr->value.type->data.pointer.is_const);
|
||||
} else {
|
||||
@ -13096,10 +13070,10 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_enum_tag(IrAnalyze *ira, IrInstructionEnumTag *enum_tag_instruction) {
|
||||
IrInstruction *value = enum_tag_instruction->value->other;
|
||||
IrInstruction *new_instruction = ir_analyze_enum_tag(ira, &enum_tag_instruction->base, value);
|
||||
ir_link_new_instruction(new_instruction, &enum_tag_instruction->base);
|
||||
static TypeTableEntry *ir_analyze_instruction_union_tag(IrAnalyze *ira, IrInstructionUnionTag *instruction) {
|
||||
IrInstruction *value = instruction->value->other;
|
||||
IrInstruction *new_instruction = ir_analyze_union_tag(ira, &instruction->base, value);
|
||||
ir_link_new_instruction(new_instruction, &instruction->base);
|
||||
return new_instruction->value.type;
|
||||
}
|
||||
|
||||
@ -13255,7 +13229,7 @@ static TypeTableEntry *ir_analyze_container_init_fields_union(IrAnalyze *ira, Ir
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, instruction);
|
||||
out_val->data.x_union.payload = field_val;
|
||||
out_val->data.x_union.tag = type_field->value;
|
||||
out_val->data.x_union.tag = type_field->enum_field->value;
|
||||
|
||||
ConstParent *parent = get_const_val_parent(ira->codegen, field_val);
|
||||
if (parent != nullptr) {
|
||||
@ -13502,46 +13476,9 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
|
||||
buf_ptr(&container_type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (container_type_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
if (elem_count != 1) {
|
||||
ir_add_error(ira, &instruction->base, buf_sprintf("enum initialization requires exactly one element"));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
ConstExprValue *tag_value = ir_resolve_const(ira, container_type_value, UndefBad);
|
||||
if (!tag_value)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type;
|
||||
|
||||
TypeEnumField *field = find_enum_field_by_tag(enum_type, &tag_value->data.x_bigint);
|
||||
assert(field != nullptr);
|
||||
TypeTableEntry *this_field_type = field->type_entry;
|
||||
|
||||
IrInstruction *init_value = instruction->items[0]->other;
|
||||
if (type_is_invalid(init_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, this_field_type);
|
||||
if (casted_init_value == ira->codegen->invalid_instruction)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (instr_is_comptime(casted_init_value)) {
|
||||
ConstExprValue *init_val = ir_resolve_const(ira, casted_init_value, UndefOk);
|
||||
if (!init_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_bigint(&out_val->data.x_enum.tag, &tag_value->data.x_bigint);
|
||||
out_val->data.x_enum.payload = init_val;
|
||||
return enum_type;
|
||||
}
|
||||
|
||||
IrInstruction *new_instruction = ir_build_init_enum_from(&ira->new_irb, &instruction->base,
|
||||
enum_type, field, casted_init_value);
|
||||
ir_add_alloca(ira, new_instruction, enum_type);
|
||||
return enum_type;
|
||||
} else {
|
||||
ir_add_error(ira, container_type_value,
|
||||
buf_sprintf("expected type, found '%s'", buf_ptr(&container_type_value->value.type->name)));
|
||||
buf_sprintf("expected type, found '%s' value", buf_ptr(&container_type_value->value.type->name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
@ -13584,8 +13521,8 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
|
||||
eval_min_max_value(ira->codegen, target_type, out_val, is_max);
|
||||
return target_type;
|
||||
}
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO min/max value for enum tag type");
|
||||
case TypeTableEntryIdEnum:
|
||||
zig_panic("TODO min/max value for enum type");
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
@ -13599,7 +13536,6 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
@ -13707,20 +13643,18 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn
|
||||
if (type_is_invalid(target->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
assert(target->value.type->id == TypeTableEntryIdEnumTag);
|
||||
assert(target->value.type->id == TypeTableEntryIdEnum);
|
||||
|
||||
if (instr_is_comptime(target)) {
|
||||
TypeTableEntry *enum_type = target->value.type->data.enum_tag.enum_type;
|
||||
uint64_t tag_value = bigint_as_unsigned(&target->value.data.x_bigint);
|
||||
TypeEnumField *field = &enum_type->data.enumeration.fields[tag_value];
|
||||
TypeEnumField *field = find_enum_field_by_tag(target->value.type, &target->value.data.x_bigint);
|
||||
ConstExprValue *array_val = create_const_str_lit(ira->codegen, field->name);
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_slice(ira->codegen, out_val, array_val, 0, buf_len(field->name), true);
|
||||
return out_val->type;
|
||||
}
|
||||
|
||||
if (!target->value.type->data.enum_tag.generate_name_table) {
|
||||
target->value.type->data.enum_tag.generate_name_table = true;
|
||||
if (!target->value.type->data.enumeration.generate_name_table) {
|
||||
target->value.type->data.enumeration.generate_name_table = true;
|
||||
ira->codegen->name_table_enums.append(target->value.type);
|
||||
}
|
||||
|
||||
@ -13869,7 +13803,7 @@ static TypeTableEntry *ir_analyze_instruction_type_id(IrAnalyze *ira,
|
||||
TypeTableEntry *result_type = var_value->data.x_type;
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_enum.tag, type_id_index(type_entry->id));
|
||||
bigint_init_unsigned(&out_val->data.x_enum_tag, type_id_index(type_entry->id));
|
||||
return result_type;
|
||||
}
|
||||
|
||||
@ -14698,14 +14632,14 @@ static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInst
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = field->type_entry;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
} else if (container_type->id == TypeTableEntryIdEnum) {
|
||||
if (member_index >= container_type->data.enumeration.src_field_count) {
|
||||
} else if (container_type->id == TypeTableEntryIdUnion) {
|
||||
if (member_index >= container_type->data.unionation.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
|
||||
TypeUnionField *field = &container_type->data.unionation.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = field->type_entry;
|
||||
@ -14749,6 +14683,18 @@ static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInst
|
||||
}
|
||||
TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, field->name);
|
||||
return out_val->type;
|
||||
} else if (container_type->id == TypeTableEntryIdUnion) {
|
||||
if (member_index >= container_type->data.unionation.src_field_count) {
|
||||
ir_add_error(ira, index_value,
|
||||
buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
|
||||
member_index, buf_ptr(&container_type->name), container_type->data.unionation.src_field_count));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
TypeUnionField *field = &container_type->data.unionation.fields[member_index];
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
init_const_str_lit(ira->codegen, out_val, field->name);
|
||||
return out_val->type;
|
||||
@ -14819,7 +14765,6 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdEnumTag:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
{
|
||||
@ -15125,10 +15070,9 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
if (type_is_invalid(switch_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
if (switch_type->id == TypeTableEntryIdEnumTag) {
|
||||
TypeTableEntry *enum_type = switch_type->data.enum_tag.enum_type;
|
||||
if (switch_type->id == TypeTableEntryIdEnum) {
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> field_prev_uses = {};
|
||||
field_prev_uses.init(enum_type->data.enumeration.src_field_count);
|
||||
field_prev_uses.init(switch_type->data.enumeration.src_field_count);
|
||||
|
||||
for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
|
||||
IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
|
||||
@ -15141,22 +15085,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
if (type_is_invalid(end_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
assert(start_value->value.type->id == TypeTableEntryIdEnum);
|
||||
BigInt start_index;
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_enum_tag);
|
||||
|
||||
assert(end_value->value.type->id == TypeTableEntryIdEnum);
|
||||
BigInt end_index;
|
||||
if (start_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_bigint);
|
||||
} else if (start_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
if (end_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
bigint_init_bigint(&end_index, &end_value->value.data.x_bigint);
|
||||
} else if (end_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
bigint_init_bigint(&end_index, &end_value->value.data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
bigint_init_bigint(&end_index, &end_value->value.data.x_enum_tag);
|
||||
|
||||
BigInt field_index;
|
||||
bigint_init_bigint(&field_index, &start_index);
|
||||
@ -15168,10 +15103,10 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
auto entry = field_prev_uses.put_unique(field_index, start_value->source_node);
|
||||
if (entry) {
|
||||
AstNode *prev_node = entry->value;
|
||||
TypeEnumField *enum_field = find_enum_field_by_tag(enum_type, &field_index);
|
||||
TypeEnumField *enum_field = find_enum_field_by_tag(switch_type, &field_index);
|
||||
assert(enum_field != nullptr);
|
||||
ErrorMsg *msg = ir_add_error(ira, start_value,
|
||||
buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&enum_type->name),
|
||||
buf_sprintf("duplicate switch value: '%s.%s'", buf_ptr(&switch_type->name),
|
||||
buf_ptr(enum_field->name)));
|
||||
add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
|
||||
}
|
||||
@ -15179,13 +15114,13 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
}
|
||||
}
|
||||
if (!instruction->have_else_prong) {
|
||||
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
|
||||
TypeEnumField *enum_field = &enum_type->data.enumeration.fields[i];
|
||||
for (uint32_t i = 0; i < switch_type->data.enumeration.src_field_count; i += 1) {
|
||||
TypeEnumField *enum_field = &switch_type->data.enumeration.fields[i];
|
||||
|
||||
auto entry = field_prev_uses.maybe_get(enum_field->value);
|
||||
if (!entry) {
|
||||
ir_add_error(ira, &instruction->base,
|
||||
buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&enum_type->name),
|
||||
buf_sprintf("enumeration value '%s.%s' not handled in switch", buf_ptr(&switch_type->name),
|
||||
buf_ptr(enum_field->name)));
|
||||
}
|
||||
}
|
||||
@ -15481,8 +15416,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
zig_panic("TODO buf_write_value_bytes pure error type");
|
||||
case TypeTableEntryIdEnum:
|
||||
zig_panic("TODO buf_write_value_bytes enum type");
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO buf_write_value_bytes enum tag type");
|
||||
case TypeTableEntryIdFn:
|
||||
zig_panic("TODO buf_write_value_bytes fn type");
|
||||
case TypeTableEntryIdUnion:
|
||||
@ -15541,8 +15474,6 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue
|
||||
zig_panic("TODO buf_read_value_bytes pure error type");
|
||||
case TypeTableEntryIdEnum:
|
||||
zig_panic("TODO buf_read_value_bytes enum type");
|
||||
case TypeTableEntryIdEnumTag:
|
||||
zig_panic("TODO buf_read_value_bytes enum tag type");
|
||||
case TypeTableEntryIdFn:
|
||||
zig_panic("TODO buf_read_value_bytes fn type");
|
||||
case TypeTableEntryIdUnion:
|
||||
@ -15920,11 +15851,8 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_type(IrAnalyze *ira, IrIn
|
||||
if (type_is_invalid(enum_type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
TypeTableEntry *non_int_tag_type = enum_type->data.enumeration.tag_type;
|
||||
assert(non_int_tag_type->id == TypeTableEntryIdEnumTag);
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_type = non_int_tag_type->data.enum_tag.int_type;
|
||||
out_val->data.x_type = enum_type->data.enumeration.tag_int_type;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
}
|
||||
|
||||
@ -15938,9 +15866,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
case IrInstructionIdStructInit:
|
||||
case IrInstructionIdUnionInit:
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
case IrInstructionIdInitEnum:
|
||||
case IrInstructionIdMaybeWrap:
|
||||
case IrInstructionIdErrWrapCode:
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
@ -16012,8 +15938,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_switch_target(ira, (IrInstructionSwitchTarget *)instruction);
|
||||
case IrInstructionIdSwitchVar:
|
||||
return ir_analyze_instruction_switch_var(ira, (IrInstructionSwitchVar *)instruction);
|
||||
case IrInstructionIdEnumTag:
|
||||
return ir_analyze_instruction_enum_tag(ira, (IrInstructionEnumTag *)instruction);
|
||||
case IrInstructionIdUnionTag:
|
||||
return ir_analyze_instruction_union_tag(ira, (IrInstructionUnionTag *)instruction);
|
||||
case IrInstructionIdImport:
|
||||
return ir_analyze_instruction_import(ira, (IrInstructionImport *)instruction);
|
||||
case IrInstructionIdArrayLen:
|
||||
@ -16260,7 +16186,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdPtrTypeChild:
|
||||
case IrInstructionIdArrayLen:
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
case IrInstructionIdArrayType:
|
||||
case IrInstructionIdSliceType:
|
||||
@ -16271,7 +16196,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdCtz:
|
||||
case IrInstructionIdSwitchVar:
|
||||
case IrInstructionIdSwitchTarget:
|
||||
case IrInstructionIdEnumTag:
|
||||
case IrInstructionIdUnionTag:
|
||||
case IrInstructionIdRef:
|
||||
case IrInstructionIdMinValue:
|
||||
case IrInstructionIdMaxValue:
|
||||
@ -16293,7 +16218,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdErrWrapPayload:
|
||||
case IrInstructionIdFnProto:
|
||||
case IrInstructionIdTestComptime:
|
||||
case IrInstructionIdInitEnum:
|
||||
case IrInstructionIdPtrCast:
|
||||
case IrInstructionIdBitCast:
|
||||
case IrInstructionIdWidenOrShorten:
|
||||
|
||||
@ -291,7 +291,7 @@ static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruct
|
||||
}
|
||||
|
||||
static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) {
|
||||
Buf *field_name = instruction->field->name;
|
||||
Buf *field_name = instruction->field->enum_field->name;
|
||||
|
||||
fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name));
|
||||
fprintf(irp->f, ".%s = ", buf_ptr(field_name));
|
||||
@ -361,17 +361,10 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) {
|
||||
fprintf(irp->f, "@EnumFieldPtr(&");
|
||||
ir_print_other_instruction(irp, instruction->enum_ptr);
|
||||
fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_union_field_ptr(IrPrint *irp, IrInstructionUnionFieldPtr *instruction) {
|
||||
fprintf(irp->f, "@UnionFieldPtr(&");
|
||||
ir_print_other_instruction(irp, instruction->union_ptr);
|
||||
fprintf(irp->f, ".%s", buf_ptr(instruction->field->name));
|
||||
fprintf(irp->f, ".%s", buf_ptr(instruction->field->enum_field->name));
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
@ -509,8 +502,8 @@ static void ir_print_switch_target(IrPrint *irp, IrInstructionSwitchTarget *inst
|
||||
ir_print_other_instruction(irp, instruction->target_value_ptr);
|
||||
}
|
||||
|
||||
static void ir_print_enum_tag(IrPrint *irp, IrInstructionEnumTag *instruction) {
|
||||
fprintf(irp->f, "enumtag ");
|
||||
static void ir_print_union_tag(IrPrint *irp, IrInstructionUnionTag *instruction) {
|
||||
fprintf(irp->f, "uniontag ");
|
||||
ir_print_other_instruction(irp, instruction->value);
|
||||
}
|
||||
|
||||
@ -799,12 +792,6 @@ static void ir_print_test_comptime(IrPrint *irp, IrInstructionTestComptime *inst
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_init_enum(IrPrint *irp, IrInstructionInitEnum *instruction) {
|
||||
fprintf(irp->f, "%s.%s {", buf_ptr(&instruction->enum_type->name), buf_ptr(instruction->field->name));
|
||||
ir_print_other_instruction(irp, instruction->init_value);
|
||||
fprintf(irp->f, "}");
|
||||
}
|
||||
|
||||
static void ir_print_ptr_cast(IrPrint *irp, IrInstructionPtrCast *instruction) {
|
||||
fprintf(irp->f, "@ptrCast(");
|
||||
if (instruction->dest_type) {
|
||||
@ -1078,9 +1065,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdEnumFieldPtr:
|
||||
ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction);
|
||||
break;
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
ir_print_union_field_ptr(irp, (IrInstructionUnionFieldPtr *)instruction);
|
||||
break;
|
||||
@ -1123,8 +1107,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdSwitchTarget:
|
||||
ir_print_switch_target(irp, (IrInstructionSwitchTarget *)instruction);
|
||||
break;
|
||||
case IrInstructionIdEnumTag:
|
||||
ir_print_enum_tag(irp, (IrInstructionEnumTag *)instruction);
|
||||
case IrInstructionIdUnionTag:
|
||||
ir_print_union_tag(irp, (IrInstructionUnionTag *)instruction);
|
||||
break;
|
||||
case IrInstructionIdImport:
|
||||
ir_print_import(irp, (IrInstructionImport *)instruction);
|
||||
@ -1237,9 +1221,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdTestComptime:
|
||||
ir_print_test_comptime(irp, (IrInstructionTestComptime *)instruction);
|
||||
break;
|
||||
case IrInstructionIdInitEnum:
|
||||
ir_print_init_enum(irp, (IrInstructionInitEnum *)instruction);
|
||||
break;
|
||||
case IrInstructionIdPtrCast:
|
||||
ir_print_ptr_cast(irp, (IrInstructionPtrCast *)instruction);
|
||||
break;
|
||||
|
||||
@ -2377,7 +2377,9 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
|
||||
}
|
||||
|
||||
/*
|
||||
ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
|
||||
ContainerDecl = option("extern" | "packed")
|
||||
("struct" option(GroupedExpression) | "union" option("enum" option(GroupedExpression) | GroupedExpression) | ("enum" option(GroupedExpression)))
|
||||
"{" many(ContainerMember) "}"
|
||||
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
|
||||
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
|
||||
*/
|
||||
@ -2414,7 +2416,28 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
|
||||
AstNode *node = ast_create_node(pc, NodeTypeContainerDecl, first_token);
|
||||
node->data.container_decl.layout = layout;
|
||||
node->data.container_decl.kind = kind;
|
||||
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
|
||||
|
||||
if (kind == ContainerKindUnion) {
|
||||
Token *lparen_token = &pc->tokens->at(*token_index);
|
||||
if (lparen_token->id == TokenIdLParen) {
|
||||
Token *enum_token = &pc->tokens->at(*token_index + 1);
|
||||
if (enum_token->id == TokenIdKeywordEnum) {
|
||||
Token *paren_token = &pc->tokens->at(*token_index + 2);
|
||||
if (paren_token->id == TokenIdLParen) {
|
||||
node->data.container_decl.auto_enum = true;
|
||||
*token_index += 2;
|
||||
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, true);
|
||||
ast_eat_token(pc, token_index, TokenIdRParen);
|
||||
} else if (paren_token->id == TokenIdRParen) {
|
||||
node->data.container_decl.auto_enum = true;
|
||||
*token_index += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!node->data.container_decl.auto_enum) {
|
||||
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
|
||||
}
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdLBrace);
|
||||
|
||||
@ -2461,8 +2484,6 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
|
||||
if (colon_token->id == TokenIdColon) {
|
||||
*token_index += 1;
|
||||
field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
} else {
|
||||
field_node->data.struct_field.type = ast_create_void_type_node(pc, colon_token);
|
||||
}
|
||||
Token *eq_token = &pc->tokens->at(*token_index);
|
||||
if (eq_token->id == TokenIdEq) {
|
||||
|
||||
@ -69,8 +69,8 @@ pub const Builder = struct {
|
||||
used: bool,
|
||||
};
|
||||
|
||||
const UserValue = enum {
|
||||
Flag,
|
||||
const UserValue = union(enum) {
|
||||
Flag: void,
|
||||
Scalar: []const u8,
|
||||
List: ArrayList([]const u8),
|
||||
};
|
||||
@ -450,7 +450,7 @@ pub const Builder = struct {
|
||||
pub fn addUserInputOption(self: &Builder, name: []const u8, value: []const u8) -> bool {
|
||||
if (%%self.user_input_options.put(name, UserInputOption {
|
||||
.name = name,
|
||||
.value = UserValue.Scalar { value },
|
||||
.value = UserValue { .Scalar = value },
|
||||
.used = false,
|
||||
})) |*prev_value| {
|
||||
// option already exists
|
||||
@ -462,7 +462,7 @@ pub const Builder = struct {
|
||||
%%list.append(value);
|
||||
_ = %%self.user_input_options.put(name, UserInputOption {
|
||||
.name = name,
|
||||
.value = UserValue.List { list },
|
||||
.value = UserValue { .List = list },
|
||||
.used = false,
|
||||
});
|
||||
},
|
||||
@ -471,7 +471,7 @@ pub const Builder = struct {
|
||||
%%list.append(value);
|
||||
_ = %%self.user_input_options.put(name, UserInputOption {
|
||||
.name = name,
|
||||
.value = UserValue.List { *list },
|
||||
.value = UserValue { .List = *list },
|
||||
.used = false,
|
||||
});
|
||||
},
|
||||
@ -487,7 +487,7 @@ pub const Builder = struct {
|
||||
pub fn addUserInputFlag(self: &Builder, name: []const u8) -> bool {
|
||||
if (%%self.user_input_options.put(name, UserInputOption {
|
||||
.name = name,
|
||||
.value = UserValue.Flag,
|
||||
.value = UserValue {.Flag = {} },
|
||||
.used = false,
|
||||
})) |*prev_value| {
|
||||
switch (prev_value.value) {
|
||||
@ -685,8 +685,8 @@ const CrossTarget = struct {
|
||||
environ: builtin.Environ,
|
||||
};
|
||||
|
||||
const Target = enum {
|
||||
Native,
|
||||
const Target = union(enum) {
|
||||
Native: void,
|
||||
Cross: CrossTarget,
|
||||
|
||||
pub fn oFileExt(self: &const Target) -> []const u8 {
|
||||
@ -844,7 +844,7 @@ pub const LibExeObjStep = struct {
|
||||
.kind = kind,
|
||||
.root_src = root_src,
|
||||
.name = name,
|
||||
.target = Target.Native,
|
||||
.target = Target { .Native = {} },
|
||||
.linker_script = null,
|
||||
.link_libs = BufSet.init(builder.allocator),
|
||||
.frameworks = BufSet.init(builder.allocator),
|
||||
@ -879,7 +879,7 @@ pub const LibExeObjStep = struct {
|
||||
.kind = kind,
|
||||
.version = *version,
|
||||
.static = static,
|
||||
.target = Target.Native,
|
||||
.target = Target { .Native = {} },
|
||||
.cflags = ArrayList([]const u8).init(builder.allocator),
|
||||
.source_files = ArrayList([]const u8).init(builder.allocator),
|
||||
.object_files = ArrayList([]const u8).init(builder.allocator),
|
||||
@ -948,8 +948,8 @@ pub const LibExeObjStep = struct {
|
||||
pub fn setTarget(self: &LibExeObjStep, target_arch: builtin.Arch, target_os: builtin.Os,
|
||||
target_environ: builtin.Environ)
|
||||
{
|
||||
self.target = Target.Cross {
|
||||
CrossTarget {
|
||||
self.target = Target {
|
||||
.Cross = CrossTarget {
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
@ -1186,13 +1186,13 @@ pub const LibExeObjStep = struct {
|
||||
Target.Native => {},
|
||||
Target.Cross => |cross_target| {
|
||||
%%zig_args.append("--target-arch");
|
||||
%%zig_args.append(@enumTagName(cross_target.arch));
|
||||
%%zig_args.append(@tagName(cross_target.arch));
|
||||
|
||||
%%zig_args.append("--target-os");
|
||||
%%zig_args.append(@enumTagName(cross_target.os));
|
||||
%%zig_args.append(@tagName(cross_target.os));
|
||||
|
||||
%%zig_args.append("--target-environ");
|
||||
%%zig_args.append(@enumTagName(cross_target.environ));
|
||||
%%zig_args.append(@tagName(cross_target.environ));
|
||||
},
|
||||
}
|
||||
|
||||
@ -1553,7 +1553,7 @@ pub const TestStep = struct {
|
||||
.name_prefix = "",
|
||||
.filter = null,
|
||||
.link_libs = BufSet.init(builder.allocator),
|
||||
.target = Target.Native,
|
||||
.target = Target { .Native = {} },
|
||||
.exec_cmd_args = null,
|
||||
}
|
||||
}
|
||||
@ -1581,8 +1581,8 @@ pub const TestStep = struct {
|
||||
pub fn setTarget(self: &TestStep, target_arch: builtin.Arch, target_os: builtin.Os,
|
||||
target_environ: builtin.Environ)
|
||||
{
|
||||
self.target = Target.Cross {
|
||||
CrossTarget {
|
||||
self.target = Target {
|
||||
.Cross = CrossTarget {
|
||||
.arch = target_arch,
|
||||
.os = target_os,
|
||||
.environ = target_environ,
|
||||
@ -1620,13 +1620,13 @@ pub const TestStep = struct {
|
||||
Target.Native => {},
|
||||
Target.Cross => |cross_target| {
|
||||
%%zig_args.append("--target-arch");
|
||||
%%zig_args.append(@enumTagName(cross_target.arch));
|
||||
%%zig_args.append(@tagName(cross_target.arch));
|
||||
|
||||
%%zig_args.append("--target-os");
|
||||
%%zig_args.append(@enumTagName(cross_target.os));
|
||||
%%zig_args.append(@tagName(cross_target.os));
|
||||
|
||||
%%zig_args.append("--target-environ");
|
||||
%%zig_args.append(@enumTagName(cross_target.environ));
|
||||
%%zig_args.append(@tagName(cross_target.environ));
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -280,7 +280,7 @@ const AbbrevAttr = struct {
|
||||
form_id: u64,
|
||||
};
|
||||
|
||||
const FormValue = enum {
|
||||
const FormValue = union(enum) {
|
||||
Address: u64,
|
||||
Block: []u8,
|
||||
Const: Constant,
|
||||
@ -475,7 +475,7 @@ fn readAllocBytes(allocator: &mem.Allocator, in_stream: &io.InStream, size: usiz
|
||||
|
||||
fn parseFormValueBlockLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
|
||||
const buf = %return readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue.Block { buf };
|
||||
return FormValue { .Block = buf };
|
||||
}
|
||||
|
||||
fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
|
||||
@ -484,7 +484,7 @@ fn parseFormValueBlock(allocator: &mem.Allocator, in_stream: &io.InStream, size:
|
||||
}
|
||||
|
||||
fn parseFormValueConstant(allocator: &mem.Allocator, in_stream: &io.InStream, signed: bool, size: usize) -> %FormValue {
|
||||
FormValue.Const { Constant {
|
||||
FormValue { .Const = Constant {
|
||||
.signed = signed,
|
||||
.payload = %return readAllocBytes(allocator, in_stream, size),
|
||||
}}
|
||||
@ -510,7 +510,7 @@ fn parseFormValueTargetAddrSize(in_stream: &io.InStream) -> %u64 {
|
||||
|
||||
fn parseFormValueRefLen(allocator: &mem.Allocator, in_stream: &io.InStream, size: usize) -> %FormValue {
|
||||
const buf = %return readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue.Ref { buf };
|
||||
return FormValue { .Ref = buf };
|
||||
}
|
||||
|
||||
fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptime T: type) -> %FormValue {
|
||||
@ -520,7 +520,7 @@ fn parseFormValueRef(allocator: &mem.Allocator, in_stream: &io.InStream, comptim
|
||||
|
||||
fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u64, is_64: bool) -> %FormValue {
|
||||
return switch (form_id) {
|
||||
DW.FORM_addr => FormValue.Address { %return parseFormValueTargetAddrSize(in_stream) },
|
||||
DW.FORM_addr => FormValue { .Address = %return parseFormValueTargetAddrSize(in_stream) },
|
||||
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
|
||||
DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
|
||||
DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
|
||||
@ -540,13 +540,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
||||
DW.FORM_exprloc => {
|
||||
const size = %return readULeb128(in_stream);
|
||||
const buf = %return readAllocBytes(allocator, in_stream, size);
|
||||
return FormValue.ExprLoc { buf };
|
||||
},
|
||||
DW.FORM_flag => FormValue.Flag { (%return in_stream.readByte()) != 0 },
|
||||
DW.FORM_flag_present => FormValue.Flag { true },
|
||||
DW.FORM_sec_offset => FormValue.SecOffset {
|
||||
%return parseFormValueDwarfOffsetSize(in_stream, is_64)
|
||||
return FormValue { .ExprLoc = buf };
|
||||
},
|
||||
DW.FORM_flag => FormValue { .Flag = (%return in_stream.readByte()) != 0 },
|
||||
DW.FORM_flag_present => FormValue { .Flag = true },
|
||||
DW.FORM_sec_offset => FormValue { .SecOffset = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
|
||||
DW.FORM_ref1 => parseFormValueRef(allocator, in_stream, u8),
|
||||
DW.FORM_ref2 => parseFormValueRef(allocator, in_stream, u16),
|
||||
@ -557,11 +555,11 @@ fn parseFormValue(allocator: &mem.Allocator, in_stream: &io.InStream, form_id: u
|
||||
parseFormValueRefLen(allocator, in_stream, ref_len)
|
||||
},
|
||||
|
||||
DW.FORM_ref_addr => FormValue.RefAddr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_ref_sig8 => FormValue.RefSig8 { %return in_stream.readIntLe(u64) },
|
||||
DW.FORM_ref_addr => FormValue { .RefAddr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_ref_sig8 => FormValue { .RefSig8 = %return in_stream.readIntLe(u64) },
|
||||
|
||||
DW.FORM_string => FormValue.String { %return readStringRaw(allocator, in_stream) },
|
||||
DW.FORM_strp => FormValue.StrPtr { %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_string => FormValue { .String = %return readStringRaw(allocator, in_stream) },
|
||||
DW.FORM_strp => FormValue { .StrPtr = %return parseFormValueDwarfOffsetSize(in_stream, is_64) },
|
||||
DW.FORM_indirect => {
|
||||
const child_form_id = %return readULeb128(in_stream);
|
||||
parseFormValue(allocator, in_stream, child_form_id, is_64)
|
||||
|
||||
@ -58,7 +58,7 @@ pub const ChildProcess = struct {
|
||||
err_pipe: if (is_windows) void else [2]i32,
|
||||
llnode: if (is_windows) void else LinkedList(&ChildProcess).Node,
|
||||
|
||||
pub const Term = enum {
|
||||
pub const Term = union(enum) {
|
||||
Exited: i32,
|
||||
Signal: i32,
|
||||
Stopped: i32,
|
||||
@ -281,13 +281,13 @@ pub const ChildProcess = struct {
|
||||
|
||||
fn statusToTerm(status: i32) -> Term {
|
||||
return if (posix.WIFEXITED(status)) {
|
||||
Term.Exited { posix.WEXITSTATUS(status) }
|
||||
Term { .Exited = posix.WEXITSTATUS(status) }
|
||||
} else if (posix.WIFSIGNALED(status)) {
|
||||
Term.Signal { posix.WTERMSIG(status) }
|
||||
Term { .Signal = posix.WTERMSIG(status) }
|
||||
} else if (posix.WIFSTOPPED(status)) {
|
||||
Term.Stopped { posix.WSTOPSIG(status) }
|
||||
Term { .Stopped = posix.WSTOPSIG(status) }
|
||||
} else {
|
||||
Term.Unknown { status }
|
||||
Term { .Unknown = status }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -1016,7 +1016,7 @@ pub fn real(allocator: &Allocator, pathname: []const u8) -> %[]u8 {
|
||||
|
||||
return os.readLink(allocator, proc_path);
|
||||
},
|
||||
else => @compileError("TODO implement os.path.real for " ++ @enumTagName(builtin.os)),
|
||||
else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
const E = enum { A: [9]u8, B: u64, };
|
||||
const E = union(enum) { A: [9]u8, B: u64, };
|
||||
const S = struct { x: u8, y: E, };
|
||||
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
test "bug 394 fixed" {
|
||||
const x = S { .x = 3, .y = E.B {1} };
|
||||
const x = S { .x = 3, .y = E {.B = 1 } };
|
||||
assert(x.x == 3);
|
||||
}
|
||||
|
||||
@ -2,8 +2,8 @@ const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
|
||||
test "enum type" {
|
||||
const foo1 = Foo.One {13};
|
||||
const foo2 = Foo.Two { Point { .x = 1234, .y = 5678, }};
|
||||
const foo1 = Foo{ .One = 13};
|
||||
const foo2 = Foo{. Two = Point { .x = 1234, .y = 5678, }};
|
||||
const bar = Bar.B;
|
||||
|
||||
assert(bar == Bar.B);
|
||||
@ -24,12 +24,12 @@ const Point = struct {
|
||||
x: u64,
|
||||
y: u64,
|
||||
};
|
||||
const Foo = enum {
|
||||
const Foo = union(enum) {
|
||||
One: i32,
|
||||
Two: Point,
|
||||
Three: void,
|
||||
};
|
||||
const FooNoVoid = enum {
|
||||
const FooNoVoid = union(enum) {
|
||||
One: i32,
|
||||
Two: Point,
|
||||
};
|
||||
@ -41,13 +41,13 @@ const Bar = enum {
|
||||
};
|
||||
|
||||
fn returnAnInt(x: i32) -> Foo {
|
||||
Foo.One { x }
|
||||
Foo { .One = x }
|
||||
}
|
||||
|
||||
|
||||
test "constant enum with payload" {
|
||||
var empty = AnEnumWithPayload.Empty;
|
||||
var full = AnEnumWithPayload.Full {13};
|
||||
var empty = AnEnumWithPayload {.Empty = {}};
|
||||
var full = AnEnumWithPayload {.Full = 13};
|
||||
shouldBeEmpty(empty);
|
||||
shouldBeNotEmpty(full);
|
||||
}
|
||||
@ -66,8 +66,8 @@ fn shouldBeNotEmpty(x: &const AnEnumWithPayload) {
|
||||
}
|
||||
}
|
||||
|
||||
const AnEnumWithPayload = enum {
|
||||
Empty,
|
||||
const AnEnumWithPayload = union(enum) {
|
||||
Empty: void,
|
||||
Full: i32,
|
||||
};
|
||||
|
||||
@ -109,13 +109,13 @@ const IntToEnumNumber = enum {
|
||||
};
|
||||
|
||||
|
||||
test "@enumTagName" {
|
||||
test "@tagName" {
|
||||
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
||||
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
|
||||
}
|
||||
|
||||
fn testEnumTagNameBare(n: BareNumber) -> []const u8 {
|
||||
return @enumTagName(n);
|
||||
return @tagName(n);
|
||||
}
|
||||
|
||||
const BareNumber = enum {
|
||||
@ -132,7 +132,7 @@ test "enum alignment" {
|
||||
}
|
||||
}
|
||||
|
||||
const AlignTestEnum = enum {
|
||||
const AlignTestEnum = union(enum) {
|
||||
A: [9]u8,
|
||||
B: u64,
|
||||
};
|
||||
|
||||
@ -2,7 +2,7 @@ const assert = @import("std").debug.assert;
|
||||
const mem = @import("std").mem;
|
||||
const fmt = @import("std").fmt;
|
||||
|
||||
const ET = enum {
|
||||
const ET = union(enum) {
|
||||
SINT: i32,
|
||||
UINT: u32,
|
||||
|
||||
@ -15,8 +15,8 @@ const ET = enum {
|
||||
};
|
||||
|
||||
test "enum with members" {
|
||||
const a = ET.SINT { -42 };
|
||||
const b = ET.UINT { 42 };
|
||||
const a = ET { .SINT = -42 };
|
||||
const b = ET { .UINT = 42 };
|
||||
var buf: [20]u8 = undefined;
|
||||
|
||||
assert(%%a.print(buf[0..]) == 3);
|
||||
|
||||
@ -324,8 +324,8 @@ test "constant enum initialization with differing sizes" {
|
||||
test3_1(test3_foo);
|
||||
test3_2(test3_bar);
|
||||
}
|
||||
const Test3Foo = enum {
|
||||
One,
|
||||
const Test3Foo = union(enum) {
|
||||
One: void,
|
||||
Two: f32,
|
||||
Three: Test3Point,
|
||||
};
|
||||
@ -333,8 +333,8 @@ const Test3Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
};
|
||||
const test3_foo = Test3Foo.Three{Test3Point {.x = 3, .y = 4}};
|
||||
const test3_bar = Test3Foo.Two{13};
|
||||
const test3_foo = Test3Foo { .Three = Test3Point {.x = 3, .y = 4}};
|
||||
const test3_bar = Test3Foo { .Two = 13};
|
||||
fn test3_1(f: &const Test3Foo) {
|
||||
switch (*f) {
|
||||
Test3Foo.Three => |pt| {
|
||||
@ -449,7 +449,8 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
|
||||
const Tid = builtin.TypeId;
|
||||
const AStruct = struct { x: i32, };
|
||||
const AnEnum = enum { One, Two, };
|
||||
const AnEnumWithPayload = enum { One: i32, Two, };
|
||||
const AUnionEnum = union(enum) { One: i32, Two: void, };
|
||||
const AUnion = union { One: void, Two: void };
|
||||
|
||||
test "@typeId" {
|
||||
comptime {
|
||||
@ -474,8 +475,9 @@ test "@typeId" {
|
||||
assert(@typeId(%i32) == Tid.ErrorUnion);
|
||||
assert(@typeId(error) == Tid.Error);
|
||||
assert(@typeId(AnEnum) == Tid.Enum);
|
||||
assert(@typeId(@typeOf(AnEnumWithPayload.One)) == Tid.EnumTag);
|
||||
// TODO union
|
||||
assert(@typeId(@typeOf(AUnionEnum.One)) == Tid.Enum);
|
||||
assert(@typeId(AUnionEnum) == Tid.Union);
|
||||
assert(@typeId(AUnion) == Tid.Union);
|
||||
assert(@typeId(fn()) == Tid.Fn);
|
||||
assert(@typeId(@typeOf(builtin)) == Tid.Namespace);
|
||||
assert(@typeId(@typeOf({this})) == Tid.Block);
|
||||
|
||||
@ -62,8 +62,8 @@ const Foo = struct {
|
||||
three: void,
|
||||
};
|
||||
|
||||
const Bar = enum {
|
||||
One,
|
||||
const Bar = union(enum) {
|
||||
One: void,
|
||||
Two: i32,
|
||||
Three: bool,
|
||||
Four: f64,
|
||||
|
||||
@ -83,14 +83,14 @@ const SwitchStatmentFoo = enum {
|
||||
|
||||
|
||||
test "switch prong with variable" {
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum.One {13});
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum.Two {13.0});
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum.Meh);
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum { .One = 13});
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum { .Two = 13.0});
|
||||
switchProngWithVarFn(SwitchProngWithVarEnum { .Meh = {}});
|
||||
}
|
||||
const SwitchProngWithVarEnum = enum {
|
||||
const SwitchProngWithVarEnum = union(enum) {
|
||||
One: i32,
|
||||
Two: f32,
|
||||
Meh,
|
||||
Meh: void,
|
||||
};
|
||||
fn switchProngWithVarFn(a: &const SwitchProngWithVarEnum) {
|
||||
switch(*a) {
|
||||
@ -112,7 +112,7 @@ test "switch on enum using pointer capture" {
|
||||
}
|
||||
|
||||
fn testSwitchEnumPtrCapture() {
|
||||
var value = SwitchProngWithVarEnum.One { 1234 };
|
||||
var value = SwitchProngWithVarEnum { .One = 1234 };
|
||||
switch (value) {
|
||||
SwitchProngWithVarEnum.One => |*x| *x += 1,
|
||||
else => unreachable,
|
||||
@ -136,13 +136,13 @@ fn returnsFive() -> i32 {
|
||||
}
|
||||
|
||||
|
||||
const Number = enum {
|
||||
const Number = union(enum) {
|
||||
One: u64,
|
||||
Two: u8,
|
||||
Three: f32,
|
||||
};
|
||||
|
||||
const number = Number.Three { 1.23 };
|
||||
const number = Number { .Three = 1.23 };
|
||||
|
||||
fn returnsFalse() -> bool {
|
||||
switch (number) {
|
||||
|
||||
@ -9,14 +9,14 @@ fn readOnce() -> %u64 {
|
||||
|
||||
error InvalidDebugInfo;
|
||||
|
||||
const FormValue = enum {
|
||||
const FormValue = union(enum) {
|
||||
Address: u64,
|
||||
Other: bool,
|
||||
};
|
||||
|
||||
fn doThing(form_id: u64) -> %FormValue {
|
||||
return switch (form_id) {
|
||||
17 => FormValue.Address { %return readOnce() },
|
||||
17 => FormValue { .Address = %return readOnce() },
|
||||
else => error.InvalidDebugInfo,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
const FormValue = enum {
|
||||
One,
|
||||
const FormValue = union(enum) {
|
||||
One: void,
|
||||
Two: bool,
|
||||
};
|
||||
|
||||
@ -9,8 +9,8 @@ error Whatever;
|
||||
|
||||
fn foo(id: u64) -> %FormValue {
|
||||
switch (id) {
|
||||
2 => FormValue.Two { true },
|
||||
1 => FormValue.One,
|
||||
2 => FormValue { .Two = true },
|
||||
1 => FormValue { .One = {} },
|
||||
else => return error.Whatever,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const assert = @import("std").debug.assert;
|
||||
|
||||
const Value = enum {
|
||||
const Value = union(enum) {
|
||||
Int: u64,
|
||||
Array: [9]u8,
|
||||
};
|
||||
@ -10,8 +10,8 @@ const Agg = struct {
|
||||
val2: Value,
|
||||
};
|
||||
|
||||
const v1 = Value.Int { 1234 };
|
||||
const v2 = Value.Array { []u8{3} ** 9 };
|
||||
const v1 = Value { .Int = 1234 };
|
||||
const v2 = Value { .Array = []u8{3} ** 9 };
|
||||
|
||||
const err = (%Agg)(Agg {
|
||||
.val1 = v1,
|
||||
@ -75,3 +75,32 @@ test "basic extern unions" {
|
||||
assert(foo.float == 12.34);
|
||||
}
|
||||
|
||||
|
||||
const Letter = enum {
|
||||
A,
|
||||
B,
|
||||
C,
|
||||
};
|
||||
const Payload = union(Letter) {
|
||||
A: i32,
|
||||
B: f64,
|
||||
C: bool,
|
||||
};
|
||||
|
||||
test "union with specified enum tag" {
|
||||
doTest();
|
||||
comptime doTest();
|
||||
}
|
||||
|
||||
fn doTest() {
|
||||
assert(bar(Payload {.A = 1234}) == -10);
|
||||
}
|
||||
|
||||
fn bar(value: &const Payload) -> i32 {
|
||||
assert(Letter(*value) == Letter.A);
|
||||
return switch (*value) {
|
||||
Payload.A => |x| return x - 1244,
|
||||
Payload.B => |x| if (x == 12.34) i32(20) else 21,
|
||||
Payload.C => |x| if (x) i32(30) else 31,
|
||||
};
|
||||
}
|
||||
|
||||
@ -930,8 +930,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\fn bad_eql_1(a: []u8, b: []u8) -> bool {
|
||||
\\ a == b
|
||||
\\}
|
||||
\\const EnumWithData = enum {
|
||||
\\ One,
|
||||
\\const EnumWithData = union(enum) {
|
||||
\\ One: void,
|
||||
\\ Two: i32,
|
||||
\\};
|
||||
\\fn bad_eql_2(a: &const EnumWithData, b: &const EnumWithData) -> bool {
|
||||
@ -1145,19 +1145,19 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\const JasonHM = u8;
|
||||
\\const JasonList = &JsonNode;
|
||||
\\
|
||||
\\const JsonOA = enum {
|
||||
\\const JsonOA = union(enum) {
|
||||
\\ JSONArray: JsonList,
|
||||
\\ JSONObject: JasonHM,
|
||||
\\};
|
||||
\\
|
||||
\\const JsonType = enum {
|
||||
\\const JsonType = union(enum) {
|
||||
\\ JSONNull: void,
|
||||
\\ JSONInteger: isize,
|
||||
\\ JSONDouble: f64,
|
||||
\\ JSONBool: bool,
|
||||
\\ JSONString: []u8,
|
||||
\\ JSONArray,
|
||||
\\ JSONObject,
|
||||
\\ JSONArray: void,
|
||||
\\ JSONObject: void,
|
||||
\\};
|
||||
\\
|
||||
\\pub const JsonNode = struct {
|
||||
@ -2138,7 +2138,7 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\
|
||||
\\const MdText = ArrayList(u8);
|
||||
\\
|
||||
\\const MdNode = enum {
|
||||
\\const MdNode = union(enum) {
|
||||
\\ Header: struct {
|
||||
\\ text: MdText,
|
||||
\\ weight: HeaderValue,
|
||||
@ -2297,6 +2297,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
,
|
||||
".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
|
||||
|
||||
cases.add("@memberType on enum",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 0);
|
||||
\\}
|
||||
\\const Foo = enum {A,};
|
||||
,
|
||||
".tmp_source.zig:2:21: error: type 'Foo' does not support @memberType");
|
||||
|
||||
cases.add("@memberType struct out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 0);
|
||||
@ -2305,11 +2313,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
|
||||
cases.add("@memberType enum out of bounds",
|
||||
cases.add("@memberType union out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 1);
|
||||
\\}
|
||||
\\const Foo = enum {A,};
|
||||
\\const Foo = union {A: void,};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
|
||||
|
||||
@ -2336,6 +2344,14 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
|
||||
|
||||
cases.add("@memberName union out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberName(Foo, 1);
|
||||
\\}
|
||||
\\const Foo = union {A:i32,};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
|
||||
|
||||
cases.add("calling var args extern function, passing array instead of pointer",
|
||||
\\export fn entry() {
|
||||
\\ foo("hello");
|
||||
@ -2466,7 +2482,8 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\ var x: MultipleChoice = undefined;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:14: error: enums, not unions, support field assignment");
|
||||
".tmp_source.zig:2:14: error: non-enum union field assignment",
|
||||
".tmp_source.zig:1:24: note: consider 'union(enum)' here");
|
||||
|
||||
cases.add("enum with 0 fields",
|
||||
\\const Foo = enum {};
|
||||
@ -2490,4 +2507,21 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
,
|
||||
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
|
||||
".tmp_source.zig:4:9: note: other occurrence here");
|
||||
|
||||
cases.add("union with specified enum omits field",
|
||||
\\const Letter = enum {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ C,
|
||||
\\};
|
||||
\\const Payload = union(Letter) {
|
||||
\\ A: i32,
|
||||
\\ B: f64,
|
||||
\\};
|
||||
\\export fn entry() -> usize {
|
||||
\\ return @sizeOf(Payload);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:17: error: enum field missing: 'C'",
|
||||
".tmp_source.zig:4:5: note: declared here");
|
||||
}
|
||||
|
||||
@ -150,8 +150,8 @@ pub fn addPkgTests(b: &build.Builder, test_filter: ?[]const u8, root_src: []cons
|
||||
continue;
|
||||
}
|
||||
const these_tests = b.addTest(root_src);
|
||||
these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @enumTagName(test_target.os),
|
||||
@enumTagName(test_target.arch), @enumTagName(mode), if (link_libc) "c" else "bare"));
|
||||
these_tests.setNamePrefix(b.fmt("{}-{}-{}-{}-{} ", name, @tagName(test_target.os),
|
||||
@tagName(test_target.arch), @tagName(mode), if (link_libc) "c" else "bare"));
|
||||
these_tests.setFilter(test_filter);
|
||||
these_tests.setBuildMode(mode);
|
||||
if (!is_native) {
|
||||
@ -428,7 +428,7 @@ pub const CompareOutputContext = struct {
|
||||
Special.None => {
|
||||
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
|
||||
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} {} ({})",
|
||||
"compare-output", case.name, @enumTagName(mode));
|
||||
"compare-output", case.name, @tagName(mode));
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null)
|
||||
continue;
|
||||
@ -682,7 +682,7 @@ pub const CompileErrorContext = struct {
|
||||
|
||||
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
|
||||
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "compile-error {} ({})",
|
||||
case.name, @enumTagName(mode));
|
||||
case.name, @tagName(mode));
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null)
|
||||
continue;
|
||||
@ -750,7 +750,7 @@ pub const BuildExamplesContext = struct {
|
||||
|
||||
for ([]Mode{Mode.Debug, Mode.ReleaseSafe, Mode.ReleaseFast}) |mode| {
|
||||
const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "build {} ({})",
|
||||
root_src, @enumTagName(mode));
|
||||
root_src, @tagName(mode));
|
||||
if (self.test_filter) |filter| {
|
||||
if (mem.indexOf(u8, annotated_case_name, filter) == null)
|
||||
continue;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user