mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
ability to set tag values of enums
also remove support for enums with 0 values closes #305
This commit is contained in:
parent
98237f7c0b
commit
137c8f5e8a
@ -5709,7 +5709,7 @@ VariableDeclaration = option("comptime") ("var" | "const") Symbol option(":" Typ
|
||||
|
||||
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
|
||||
|
||||
ContainerField = Symbol option(":" Expression) ","
|
||||
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
|
||||
|
||||
UseDecl = "use" Expression ";"
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ struct ConstParent {
|
||||
};
|
||||
|
||||
struct ConstEnumValue {
|
||||
uint64_t tag;
|
||||
BigInt tag;
|
||||
ConstExprValue *payload;
|
||||
};
|
||||
|
||||
@ -108,7 +108,7 @@ struct ConstStructValue {
|
||||
};
|
||||
|
||||
struct ConstUnionValue {
|
||||
uint64_t tag;
|
||||
BigInt tag;
|
||||
ConstExprValue *payload;
|
||||
ConstParent parent;
|
||||
};
|
||||
@ -346,14 +346,14 @@ struct TldCompTime {
|
||||
struct TypeEnumField {
|
||||
Buf *name;
|
||||
TypeTableEntry *type_entry;
|
||||
uint32_t value;
|
||||
BigInt value;
|
||||
uint32_t gen_index;
|
||||
};
|
||||
|
||||
struct TypeUnionField {
|
||||
Buf *name;
|
||||
TypeTableEntry *type_entry;
|
||||
uint32_t value;
|
||||
BigInt value;
|
||||
uint32_t gen_index;
|
||||
};
|
||||
|
||||
@ -780,6 +780,7 @@ struct AstNodeStructField {
|
||||
VisibMod visib_mod;
|
||||
Buf *name;
|
||||
AstNode *type;
|
||||
AstNode *value;
|
||||
};
|
||||
|
||||
struct AstNodeStringLiteral {
|
||||
@ -1014,6 +1015,7 @@ struct TypeTableEntryEnum {
|
||||
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;
|
||||
|
||||
234
src/analyze.cpp
234
src/analyze.cpp
@ -1390,30 +1390,7 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
return;
|
||||
}
|
||||
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
if (decl_node->data.container_decl.init_arg_expr != nullptr) {
|
||||
TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
|
||||
if (type_is_invalid(wanted_tag_int_type)) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
} else if (wanted_tag_int_type->id != TypeTableEntryIdInt) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
|
||||
} else if (wanted_tag_int_type->data.integral.is_signed) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
|
||||
} else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("'%s' too small to hold all bits; must be at least '%s'",
|
||||
buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name)));
|
||||
} else {
|
||||
tag_int_type = wanted_tag_int_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;
|
||||
|
||||
@ -1683,7 +1660,6 @@ static void resolve_struct_type(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
TypeTableEntry *field_type = type_struct_field->type_entry;
|
||||
|
||||
ensure_complete_type(g, field_type);
|
||||
|
||||
if (type_is_invalid(field_type)) {
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
break;
|
||||
@ -2121,6 +2097,18 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
|
||||
assert(!enum_type->data.enumeration.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("enums must have 1 or more fields"));
|
||||
|
||||
enum_type->data.enumeration.src_field_count = field_count;
|
||||
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;
|
||||
}
|
||||
|
||||
enum_type->data.enumeration.src_field_count = field_count;
|
||||
enum_type->data.enumeration.fields = allocate<TypeEnumField>(field_count);
|
||||
|
||||
@ -2128,14 +2116,69 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
|
||||
Scope *scope = &enum_type->data.enumeration.decls_scope->base;
|
||||
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> occupied_tag_values = {};
|
||||
occupied_tag_values.init(field_count);
|
||||
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count - 1);
|
||||
|
||||
if (decl_node->data.container_decl.init_arg_expr != nullptr) {
|
||||
TypeTableEntry *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr);
|
||||
if (type_is_invalid(wanted_tag_int_type)) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
} else if (wanted_tag_int_type->id != TypeTableEntryIdInt) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
|
||||
} else if (wanted_tag_int_type->data.integral.is_signed) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("expected unsigned integer, found '%s'", buf_ptr(&wanted_tag_int_type->name)));
|
||||
} else if (wanted_tag_int_type->data.integral.bit_count < tag_int_type->data.integral.bit_count) {
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
add_node_error(g, decl_node->data.container_decl.init_arg_expr,
|
||||
buf_sprintf("'%s' too small to hold all bits; must be at least '%s'",
|
||||
buf_ptr(&wanted_tag_int_type->name), buf_ptr(&tag_int_type->name)));
|
||||
} else {
|
||||
tag_int_type = wanted_tag_int_type;
|
||||
}
|
||||
}
|
||||
enum_type->data.enumeration.tag_int_type = tag_int_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);
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
|
||||
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->value = 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) {
|
||||
IrInstruction *result_inst = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
|
||||
if (result_inst->value.type->id == TypeTableEntryIdInvalid) {
|
||||
enum_type->data.enumeration.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(&type_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"));
|
||||
enum_type->data.enumeration.is_invalid = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
type_ensure_zero_bits_known(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
@ -2155,6 +2198,34 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *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);
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.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(&type_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(&type_enum_field->value, &proposed_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@ -2162,7 +2233,6 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
|
||||
|
||||
// also compute abi_alignment
|
||||
if (!enum_type->zero_bits) {
|
||||
TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
|
||||
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);
|
||||
}
|
||||
@ -2214,6 +2284,11 @@ static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
|
||||
type_struct_field->src_index = i;
|
||||
type_struct_field->gen_index = SIZE_MAX;
|
||||
|
||||
if (field_node->data.struct_field.value != nullptr) {
|
||||
add_node_error(g, field_node->data.struct_field.value,
|
||||
buf_sprintf("enums, not structs, support field assignment"));
|
||||
}
|
||||
|
||||
type_ensure_zero_bits_known(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
struct_type->data.structure.is_invalid = true;
|
||||
@ -2277,7 +2352,14 @@ static void resolve_union_zero_bits(CodeGen *g, TypeTableEntry *union_type) {
|
||||
type_union_field->name = field_node->data.struct_field.name;
|
||||
TypeTableEntry *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type);
|
||||
type_union_field->type_entry = field_type;
|
||||
type_union_field->value = i;
|
||||
|
||||
// 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"));
|
||||
}
|
||||
|
||||
type_ensure_zero_bits_known(g, field_type);
|
||||
if (type_is_invalid(field_type)) {
|
||||
@ -3190,6 +3272,29 @@ TypeUnionField *find_union_type_field(TypeTableEntry *type_entry, Buf *name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static TypeUnionField *find_union_field_by_tag(TypeTableEntry *type_entry, const BigInt *tag) {
|
||||
assert(type_entry->id == TypeTableEntryIdUnion);
|
||||
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 (bigint_cmp(&field->value, tag) == CmpEQ) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TypeEnumField *find_enum_field_by_tag(TypeTableEntry *enum_type, const BigInt *tag) {
|
||||
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
|
||||
TypeEnumField *field = &enum_type->data.enumeration.fields[i];
|
||||
if (bigint_cmp(&field->value, tag) == CmpEQ) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
static bool is_container(TypeTableEntry *type_entry) {
|
||||
switch (type_entry->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
@ -4178,6 +4283,18 @@ ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *str) {
|
||||
return const_val;
|
||||
}
|
||||
|
||||
void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = type;
|
||||
bigint_init_bigint(&const_val->data.x_bigint, bigint);
|
||||
}
|
||||
|
||||
ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint) {
|
||||
ConstExprValue *const_val = create_const_vals(1);
|
||||
init_const_bigint(const_val, type, 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;
|
||||
@ -4241,13 +4358,13 @@ ConstExprValue *create_const_float(TypeTableEntry *type, double value) {
|
||||
return const_val;
|
||||
}
|
||||
|
||||
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, uint64_t tag) {
|
||||
void init_const_enum_tag(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *tag) {
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
const_val->type = type;
|
||||
const_val->data.x_enum.tag = tag;
|
||||
bigint_init_bigint(&const_val->data.x_enum.tag, tag);
|
||||
}
|
||||
|
||||
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag) {
|
||||
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, const BigInt *tag) {
|
||||
ConstExprValue *const_val = create_const_vals(1);
|
||||
init_const_enum_tag(const_val, type, tag);
|
||||
return const_val;
|
||||
@ -4450,20 +4567,35 @@ 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 (enum1->tag == enum2->tag) {
|
||||
TypeEnumField *enum_field = &a->type->data.enumeration.fields[enum1->tag];
|
||||
if (type_has_bits(enum_field->type_entry)) {
|
||||
zig_panic("TODO const expr analyze enum special value for equality");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case TypeTableEntryIdUnion: {
|
||||
ConstUnionValue *union1 = &a->data.x_union;
|
||||
ConstUnionValue *union2 = &b->data.x_union;
|
||||
|
||||
if (bigint_cmp(&union1->tag, &union2->tag) == CmpEQ) {
|
||||
TypeUnionField *field = find_union_field_by_tag(a->type, &union1->tag);
|
||||
assert(field != nullptr);
|
||||
if (type_has_bits(field->type_entry)) {
|
||||
zig_panic("TODO const expr analyze union field value for equality");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
case TypeTableEntryIdMetaType:
|
||||
return a->data.x_type == b->data.x_type;
|
||||
case TypeTableEntryIdVoid:
|
||||
@ -4544,8 +4676,6 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case TypeTableEntryIdUnion:
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdUndefLit:
|
||||
zig_panic("TODO");
|
||||
case TypeTableEntryIdNullLit:
|
||||
@ -4855,11 +4985,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) {
|
||||
}
|
||||
|
||||
TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) {
|
||||
assert(size_in_bits > 0);
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->is_copyable = true;
|
||||
entry->type_ref = LLVMIntType(size_in_bits);
|
||||
entry->type_ref = (size_in_bits == 0) ? LLVMVoidType() : LLVMIntType(size_in_bits);
|
||||
entry->zero_bits = (size_in_bits == 0);
|
||||
|
||||
const char u_or_i = is_signed ? 'i' : 'u';
|
||||
buf_resize(&entry->name, 0);
|
||||
@ -4880,7 +5009,8 @@ TypeTableEntry *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits)
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
|
||||
uint64_t debug_size_in_bits = (size_in_bits == 0) ?
|
||||
0 : (8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref));
|
||||
entry->di_type = ZigLLVMCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), debug_size_in_bits, dwarf_tag);
|
||||
entry->data.integral.is_signed = is_signed;
|
||||
entry->data.integral.bit_count = size_in_bits;
|
||||
|
||||
@ -64,6 +64,8 @@ TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name);
|
||||
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);
|
||||
|
||||
bool is_container_ref(TypeTableEntry *type_entry);
|
||||
void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node);
|
||||
void scan_import(CodeGen *g, ImportTableEntry *import);
|
||||
@ -109,6 +111,9 @@ ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
|
||||
void init_const_c_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *c_str);
|
||||
ConstExprValue *create_const_c_str_lit(CodeGen *g, Buf *c_str);
|
||||
|
||||
void init_const_bigint(ConstExprValue *const_val, TypeTableEntry *type, const BigInt *bigint);
|
||||
ConstExprValue *create_const_bigint(TypeTableEntry *type, const BigInt *bigint);
|
||||
|
||||
void init_const_unsigned_negative(ConstExprValue *const_val, TypeTableEntry *type, uint64_t x, bool negative);
|
||||
ConstExprValue *create_const_unsigned_negative(TypeTableEntry *type, uint64_t x, bool negative);
|
||||
|
||||
@ -121,8 +126,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, uint64_t tag);
|
||||
ConstExprValue *create_const_enum_tag(TypeTableEntry *type, uint64_t tag);
|
||||
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_bool(CodeGen *g, ConstExprValue *const_val, bool value);
|
||||
ConstExprValue *create_const_bool(CodeGen *g, bool value);
|
||||
|
||||
@ -677,6 +677,10 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, ": ");
|
||||
render_node_grouped(ar, field_node->data.struct_field.type);
|
||||
}
|
||||
if (field_node->data.struct_field.value != nullptr) {
|
||||
fprintf(ar->f, "= ");
|
||||
render_node_grouped(ar, field_node->data.struct_field.value);
|
||||
}
|
||||
fprintf(ar->f, ",\n");
|
||||
}
|
||||
|
||||
|
||||
@ -1224,3 +1224,35 @@ Cmp bigint_cmp_zero(const BigInt *op) {
|
||||
}
|
||||
return op->is_negative ? CmpLT : CmpGT;
|
||||
}
|
||||
|
||||
uint32_t bigint_hash(BigInt x) {
|
||||
if (x.digit_count == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return bigint_ptr(&x)[0];
|
||||
}
|
||||
}
|
||||
|
||||
bool bigint_eql(BigInt a, BigInt b) {
|
||||
return bigint_cmp(&a, &b) == CmpEQ;
|
||||
}
|
||||
|
||||
void bigint_incr(BigInt *x) {
|
||||
if (x->digit_count == 0) {
|
||||
bigint_init_unsigned(x, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (x->digit_count == 1 && x->data.digit != UINT64_MAX) {
|
||||
x->data.digit += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
BigInt copy;
|
||||
bigint_init_bigint(©, x);
|
||||
|
||||
BigInt one;
|
||||
bigint_init_unsigned(&one, 1);
|
||||
|
||||
bigint_add(x, ©, &one);
|
||||
}
|
||||
|
||||
@ -88,6 +88,11 @@ size_t bigint_bits_needed(const BigInt *op);
|
||||
// convenience functions
|
||||
Cmp bigint_cmp_zero(const BigInt *op);
|
||||
|
||||
void bigint_incr(BigInt *value);
|
||||
|
||||
bool mul_u64_overflow(uint64_t op1, uint64_t op2, uint64_t *result);
|
||||
|
||||
uint32_t bigint_hash(BigInt x);
|
||||
bool bigint_eql(BigInt a, BigInt b);
|
||||
|
||||
#endif
|
||||
|
||||
@ -1362,8 +1362,12 @@ static LLVMValueRef bigint_to_llvm_const(LLVMTypeRef type_ref, BigInt *bigint) {
|
||||
if (bigint->digit_count == 0) {
|
||||
return LLVMConstNull(type_ref);
|
||||
}
|
||||
LLVMValueRef unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref,
|
||||
bigint->digit_count, bigint_ptr(bigint));
|
||||
LLVMValueRef unsigned_val;
|
||||
if (bigint->digit_count == 1) {
|
||||
unsigned_val = LLVMConstInt(type_ref, bigint_ptr(bigint)[0], false);
|
||||
} else {
|
||||
unsigned_val = LLVMConstIntOfArbitraryPrecision(type_ref, bigint->digit_count, bigint_ptr(bigint));
|
||||
}
|
||||
if (bigint->is_negative) {
|
||||
return LLVMConstNeg(unsigned_val);
|
||||
} else {
|
||||
@ -2420,9 +2424,10 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab
|
||||
if (ir_want_debug_safety(g, &instruction->base)) {
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, "");
|
||||
LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, "");
|
||||
LLVMValueRef expected_tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
|
||||
field->value, false);
|
||||
|
||||
|
||||
LLVMValueRef expected_tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
|
||||
&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, "");
|
||||
@ -3364,9 +3369,9 @@ static LLVMValueRef ir_render_enum_tag(CodeGen *g, IrExecutable *executable, IrI
|
||||
|
||||
static LLVMValueRef ir_render_init_enum(CodeGen *g, IrExecutable *executable, IrInstructionInitEnum *instruction) {
|
||||
TypeTableEntry *enum_type = instruction->enum_type;
|
||||
uint32_t value = instruction->field->value;
|
||||
LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref;
|
||||
LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false);
|
||||
|
||||
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;
|
||||
@ -3429,8 +3434,9 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I
|
||||
if (union_type->data.unionation.gen_tag_index != SIZE_MAX) {
|
||||
LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
|
||||
union_type->data.unionation.gen_tag_index, "");
|
||||
LLVMValueRef tag_value = LLVMConstInt(union_type->data.unionation.tag_type->type_ref,
|
||||
type_union_field->value, false);
|
||||
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(union_type->data.unionation.tag_type->type_ref,
|
||||
&type_union_field->value);
|
||||
gen_store_untyped(g, tag_value, tag_field_ptr, 0, false);
|
||||
|
||||
uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr,
|
||||
@ -4039,7 +4045,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val) {
|
||||
return union_value_ref;
|
||||
}
|
||||
|
||||
LLVMValueRef tag_value = LLVMConstInt(type_entry->data.unionation.tag_type->type_ref, const_val->data.x_union.tag, false);
|
||||
LLVMValueRef tag_value = bigint_to_llvm_const(type_entry->data.unionation.tag_type->type_ref,
|
||||
&const_val->data.x_union.tag);
|
||||
|
||||
LLVMValueRef fields[2];
|
||||
fields[type_entry->data.unionation.gen_union_index] = union_value_ref;
|
||||
@ -4055,13 +4062,13 @@ 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 = LLVMConstInt(tag_type_ref, const_val->data.x_enum.tag, false);
|
||||
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 = &type_entry->data.enumeration.fields[const_val->data.x_enum.tag];
|
||||
assert(enum_field->value == const_val->data.x_enum.tag);
|
||||
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;
|
||||
|
||||
109
src/ir.cpp
109
src/ir.cpp
@ -8387,7 +8387,7 @@ static IrInstruction *ir_analyze_enum_to_int(IrAnalyze *ira, IrInstruction *sour
|
||||
return ira->codegen->invalid_instruction;
|
||||
IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope,
|
||||
source_instr->source_node, wanted_type);
|
||||
init_const_unsigned_negative(&result->value, wanted_type, val->data.x_enum.tag, false);
|
||||
init_const_bigint(&result->value, wanted_type, &val->data.x_enum.tag);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -8469,7 +8469,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);
|
||||
result->value.data.x_enum.tag = bigint_as_unsigned(&val->data.x_bigint);
|
||||
bigint_init_bigint(&result->value.data.x_enum.tag, &val->data.x_bigint);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -9148,7 +9148,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (AtomicOrder)const_val->data.x_enum.tag;
|
||||
*out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -9168,7 +9168,27 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (GlobalLinkageId)const_val->data.x_enum.tag;
|
||||
*out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMode *out) {
|
||||
if (type_is_invalid(value->value.type))
|
||||
return false;
|
||||
|
||||
ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode");
|
||||
assert(float_mode_val->type->id == TypeTableEntryIdMetaType);
|
||||
TypeTableEntry *float_mode_type = float_mode_val->data.x_type;
|
||||
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, value, float_mode_type);
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
return false;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum.tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -11825,13 +11845,13 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru
|
||||
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,
|
||||
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_unsigned_negative(child_type->data.enumeration.tag_type, field->value, false),
|
||||
create_const_bigint(child_type->data.enumeration.tag_type, &field->value),
|
||||
child_type->data.enumeration.tag_type,
|
||||
ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile);
|
||||
}
|
||||
@ -12420,21 +12440,11 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode");
|
||||
assert(float_mode_val->type->id == TypeTableEntryIdMetaType);
|
||||
TypeTableEntry *float_mode_enum_type = float_mode_val->data.x_type;
|
||||
|
||||
IrInstruction *float_mode_value = instruction->mode_value->other;
|
||||
if (type_is_invalid(float_mode_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
IrInstruction *casted_value = ir_implicit_cast(ira, float_mode_value, float_mode_enum_type);
|
||||
if (type_is_invalid(casted_value->value.type))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ConstExprValue *mode_val = ir_resolve_const(ira, casted_value, UndefBad);
|
||||
if (!mode_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
bool want_fast_math = (mode_val->data.x_enum.tag == FloatModeOptimized);
|
||||
FloatMode float_mode_scalar;
|
||||
if (!ir_resolve_float_mode(ira, float_mode_value, &float_mode_scalar))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
AstNode *source_node = instruction->base.source_node;
|
||||
if (*fast_math_set_node_ptr) {
|
||||
@ -12444,7 +12454,7 @@ static TypeTableEntry *ir_analyze_instruction_set_float_mode(IrAnalyze *ira,
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
*fast_math_set_node_ptr = source_node;
|
||||
*fast_math_off_ptr = !want_fast_math;
|
||||
*fast_math_off_ptr = (float_mode_scalar == FloatModeStrict);
|
||||
|
||||
ir_build_const_from(ira, &instruction->base);
|
||||
return ira->codegen->builtin_types.entry_void;
|
||||
@ -12835,7 +12845,7 @@ 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_unsigned(&const_instruction->base.value.data.x_bigint, val->data.x_enum.tag);
|
||||
bigint_init_bigint(&const_instruction->base.value.data.x_bigint, &val->data.x_enum.tag);
|
||||
return &const_instruction->base;
|
||||
}
|
||||
|
||||
@ -13005,7 +13015,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
|
||||
assert(tag_type != nullptr);
|
||||
if (pointee_val) {
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &switch_target_instruction->base);
|
||||
bigint_init_unsigned(&out_val->data.x_bigint, pointee_val->data.x_enum.tag);
|
||||
bigint_init_bigint(&out_val->data.x_bigint, &pointee_val->data.x_enum.tag);
|
||||
return tag_type;
|
||||
}
|
||||
|
||||
@ -13056,9 +13066,9 @@ static TypeTableEntry *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstr
|
||||
|
||||
TypeEnumField *field;
|
||||
if (prong_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
field = &target_type->data.enumeration.fields[bigint_as_unsigned(&prong_val->data.x_bigint)];
|
||||
field = find_enum_field_by_tag(target_type, &prong_val->data.x_bigint);
|
||||
} else if (prong_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
field = &target_type->data.enumeration.fields[prong_val->data.x_enum.tag];
|
||||
field = find_enum_field_by_tag(target_type, &prong_val->data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -13503,8 +13513,8 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
|
||||
|
||||
TypeTableEntry *enum_type = container_type_value->value.type->data.enum_tag.enum_type;
|
||||
|
||||
uint64_t tag_uint = bigint_as_unsigned(&tag_value->data.x_bigint);
|
||||
TypeEnumField *field = &enum_type->data.enumeration.fields[tag_uint];
|
||||
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;
|
||||
@ -13520,7 +13530,7 @@ static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira
|
||||
if (!init_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
|
||||
out_val->data.x_enum.tag = tag_uint;
|
||||
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;
|
||||
}
|
||||
@ -13859,7 +13869,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);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -15117,7 +15127,9 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
|
||||
|
||||
if (switch_type->id == TypeTableEntryIdEnumTag) {
|
||||
TypeTableEntry *enum_type = switch_type->data.enum_tag.enum_type;
|
||||
AstNode **field_prev_uses = allocate<AstNode *>(enum_type->data.enumeration.src_field_count);
|
||||
HashMap<BigInt, AstNode *, bigint_hash, bigint_eql> field_prev_uses = {};
|
||||
field_prev_uses.init(enum_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];
|
||||
|
||||
@ -15129,41 +15141,52 @@ 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;
|
||||
|
||||
size_t start_index;
|
||||
size_t end_index;
|
||||
BigInt start_index;
|
||||
BigInt end_index;
|
||||
if (start_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
start_index = bigint_as_unsigned(&start_value->value.data.x_bigint);
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_bigint);
|
||||
} else if (start_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
start_index = start_value->value.data.x_enum.tag;
|
||||
bigint_init_bigint(&start_index, &start_value->value.data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
if (end_value->value.type->id == TypeTableEntryIdEnumTag) {
|
||||
end_index = bigint_as_unsigned(&end_value->value.data.x_bigint);
|
||||
bigint_init_bigint(&end_index, &end_value->value.data.x_bigint);
|
||||
} else if (end_value->value.type->id == TypeTableEntryIdEnum) {
|
||||
end_index = end_value->value.data.x_enum.tag;
|
||||
bigint_init_bigint(&end_index, &end_value->value.data.x_enum.tag);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
for (size_t field_index = start_index; field_index <= end_index; field_index += 1) {
|
||||
AstNode *prev_node = field_prev_uses[field_index];
|
||||
if (prev_node != nullptr) {
|
||||
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[field_index];
|
||||
BigInt field_index;
|
||||
bigint_init_bigint(&field_index, &start_index);
|
||||
for (;;) {
|
||||
Cmp cmp = bigint_cmp(&field_index, &end_index);
|
||||
if (cmp == CmpGT) {
|
||||
break;
|
||||
}
|
||||
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);
|
||||
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_ptr(type_enum_field->name)));
|
||||
buf_ptr(enum_field->name)));
|
||||
add_error_note(ira->codegen, msg, prev_node, buf_sprintf("other value is here"));
|
||||
}
|
||||
field_prev_uses[field_index] = start_value->source_node;
|
||||
bigint_incr(&field_index);
|
||||
}
|
||||
}
|
||||
if (!instruction->have_else_prong) {
|
||||
for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) {
|
||||
if (field_prev_uses[i] == nullptr) {
|
||||
TypeEnumField *enum_field = &enum_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_ptr(enum_type->data.enumeration.fields[i].name)));
|
||||
buf_ptr(enum_field->name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2379,7 +2379,7 @@ static AstNode *ast_parse_use(ParseContext *pc, size_t *token_index, VisibMod vi
|
||||
/*
|
||||
ContainerDecl = option("extern" | "packed") ("struct" | "union" | ("enum" option(GroupedExpression))) "{" many(ContainerMember) "}"
|
||||
ContainerMember = (ContainerField | FnDef | GlobalVarDecl)
|
||||
ContainerField = Symbol option(":" Expression) ","
|
||||
ContainerField = Symbol option(":" PrefixOpExpression option("=" PrefixOpExpression ","
|
||||
*/
|
||||
static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index, bool mandatory) {
|
||||
Token *first_token = &pc->tokens->at(*token_index);
|
||||
@ -2414,10 +2414,7 @@ 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;
|
||||
|
||||
if (kind == ContainerKindEnum || kind == ContainerKindStruct) {
|
||||
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
|
||||
}
|
||||
node->data.container_decl.init_arg_expr = ast_parse_grouped_expr(pc, token_index, false);
|
||||
|
||||
ast_eat_token(pc, token_index, TokenIdLBrace);
|
||||
|
||||
@ -2456,31 +2453,35 @@ static AstNode *ast_parse_container_decl(ParseContext *pc, size_t *token_index,
|
||||
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
|
||||
*token_index += 1;
|
||||
|
||||
node->data.container_decl.fields.append(field_node);
|
||||
field_node->data.struct_field.visib_mod = visib_mod;
|
||||
field_node->data.struct_field.name = token_buf(token);
|
||||
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
if (token->id == TokenIdComma || token->id == TokenIdRBrace) {
|
||||
field_node->data.struct_field.type = ast_create_void_type_node(pc, token);
|
||||
Token *colon_token = &pc->tokens->at(*token_index);
|
||||
if (colon_token->id == TokenIdColon) {
|
||||
*token_index += 1;
|
||||
node->data.container_decl.fields.append(field_node);
|
||||
|
||||
if (token->id == TokenIdRBrace) {
|
||||
break;
|
||||
}
|
||||
field_node->data.struct_field.type = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
} else {
|
||||
ast_eat_token(pc, token_index, TokenIdColon);
|
||||
field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true);
|
||||
node->data.container_decl.fields.append(field_node);
|
||||
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
if (token->id == TokenIdRBrace) {
|
||||
*token_index += 1;
|
||||
break;
|
||||
} else {
|
||||
ast_eat_token(pc, token_index, TokenIdComma);
|
||||
}
|
||||
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) {
|
||||
*token_index += 1;
|
||||
field_node->data.struct_field.value = ast_parse_prefix_op_expr(pc, token_index, true);
|
||||
}
|
||||
|
||||
Token *next_token = &pc->tokens->at(*token_index);
|
||||
if (next_token->id == TokenIdComma) {
|
||||
*token_index += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (next_token->id == TokenIdRBrace) {
|
||||
*token_index += 1;
|
||||
break;
|
||||
}
|
||||
|
||||
ast_invalid_token_error(pc, next_token);
|
||||
} else {
|
||||
ast_invalid_token_error(pc, token);
|
||||
}
|
||||
@ -2812,6 +2813,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
|
||||
break;
|
||||
case NodeTypeStructField:
|
||||
visit_field(&node->data.struct_field.type, visit, context);
|
||||
visit_field(&node->data.struct_field.value, visit, context);
|
||||
break;
|
||||
case NodeTypeContainerInitExpr:
|
||||
visit_field(&node->data.container_init_expr.type, visit, context);
|
||||
|
||||
@ -16,7 +16,7 @@ pub fn sort_stable(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b
|
||||
}}
|
||||
}
|
||||
|
||||
/// Unstable sort using O(n) stack space. Currentl implemented as quicksort.
|
||||
/// Unstable sort using O(n) stack space. Currently implemented as quicksort.
|
||||
pub fn sort(comptime T: type, array: []T, comptime cmp: fn(a: &const T, b: &const T)->Cmp) {
|
||||
if (array.len > 0) {
|
||||
quicksort(T, array, 0, array.len - 1, cmp);
|
||||
|
||||
@ -137,7 +137,6 @@ const AlignTestEnum = enum {
|
||||
B: u64,
|
||||
};
|
||||
|
||||
const ValueCount0 = enum {};
|
||||
const ValueCount1 = enum { I0 };
|
||||
const ValueCount2 = enum { I0, I1 };
|
||||
const ValueCount256 = enum {
|
||||
@ -183,7 +182,6 @@ const ValueCount257 = enum {
|
||||
|
||||
test "enum sizes" {
|
||||
comptime {
|
||||
assert(@sizeOf(ValueCount0) == 0);
|
||||
assert(@sizeOf(ValueCount1) == 0);
|
||||
assert(@sizeOf(ValueCount2) == 1);
|
||||
assert(@sizeOf(ValueCount256) == 1);
|
||||
@ -292,3 +290,57 @@ test "casting enum to its tag type" {
|
||||
fn testCastEnumToTagType(value: Small2) {
|
||||
assert(u2(value) == 1);
|
||||
}
|
||||
|
||||
const MultipleChoice = enum(u32) {
|
||||
A = 20,
|
||||
B = 40,
|
||||
C = 60,
|
||||
D = 1000,
|
||||
};
|
||||
|
||||
test "enum with specified tag values" {
|
||||
testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
|
||||
}
|
||||
|
||||
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) {
|
||||
assert(u32(x) == 60);
|
||||
assert(1234 == switch (x) {
|
||||
MultipleChoice.A => 1,
|
||||
MultipleChoice.B => 2,
|
||||
MultipleChoice.C => u32(1234),
|
||||
MultipleChoice.D => 4,
|
||||
});
|
||||
}
|
||||
|
||||
const MultipleChoice2 = enum(u32) {
|
||||
Unspecified1,
|
||||
A = 20,
|
||||
Unspecified2,
|
||||
B = 40,
|
||||
Unspecified3,
|
||||
C = 60,
|
||||
Unspecified4,
|
||||
D = 1000,
|
||||
Unspecified5,
|
||||
};
|
||||
|
||||
test "enum with specified and unspecified tag values" {
|
||||
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
|
||||
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
|
||||
}
|
||||
|
||||
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) {
|
||||
assert(u32(x) == 1000);
|
||||
assert(1234 == switch (x) {
|
||||
MultipleChoice2.A => 1,
|
||||
MultipleChoice2.B => 2,
|
||||
MultipleChoice2.C => 3,
|
||||
MultipleChoice2.D => u32(1234),
|
||||
MultipleChoice2.Unspecified1 => 5,
|
||||
MultipleChoice2.Unspecified2 => 6,
|
||||
MultipleChoice2.Unspecified3 => 7,
|
||||
MultipleChoice2.Unspecified4 => 8,
|
||||
MultipleChoice2.Unspecified5 => 9,
|
||||
});
|
||||
}
|
||||
|
||||
@ -2307,11 +2307,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
|
||||
cases.add("@memberType enum out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberType(Foo, 0);
|
||||
\\ _ = @memberType(Foo, 1);
|
||||
\\}
|
||||
\\const Foo = enum {};
|
||||
\\const Foo = enum {A,};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
".tmp_source.zig:2:26: error: member index 1 out of bounds; 'Foo' has 1 members");
|
||||
|
||||
cases.add("@memberName on unsupported type",
|
||||
\\comptime {
|
||||
@ -2330,11 +2330,11 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
|
||||
cases.add("@memberName enum out of bounds",
|
||||
\\comptime {
|
||||
\\ _ = @memberName(Foo, 0);
|
||||
\\ _ = @memberName(Foo, 1);
|
||||
\\}
|
||||
\\const Foo = enum {};
|
||||
\\const Foo = enum {A,};
|
||||
,
|
||||
".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
|
||||
".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() {
|
||||
@ -2447,4 +2447,47 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:1:19: error: expected unsigned integer, found 'i2'");
|
||||
|
||||
cases.add("struct fields with value assignments",
|
||||
\\const MultipleChoice = struct {
|
||||
\\ A: i32 = 20,
|
||||
\\};
|
||||
\\export fn entry() {
|
||||
\\ var x: MultipleChoice = undefined;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:14: error: enums, not structs, support field assignment");
|
||||
|
||||
cases.add("union fields with value assignments",
|
||||
\\const MultipleChoice = union {
|
||||
\\ A: i32 = 20,
|
||||
\\};
|
||||
\\export fn entry() {
|
||||
\\ var x: MultipleChoice = undefined;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:2:14: error: enums, not unions, support field assignment");
|
||||
|
||||
cases.add("enum with 0 fields",
|
||||
\\const Foo = enum {};
|
||||
\\export fn entry() -> usize {
|
||||
\\ return @sizeOf(Foo);
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:1:13: error: enums must have 1 or more fields");
|
||||
|
||||
cases.add("enum value already taken",
|
||||
\\const MultipleChoice = enum(u32) {
|
||||
\\ A = 20,
|
||||
\\ B = 40,
|
||||
\\ C = 60,
|
||||
\\ D = 1000,
|
||||
\\ E = 60,
|
||||
\\};
|
||||
\\export fn entry() {
|
||||
\\ var x = MultipleChoice.C;
|
||||
\\}
|
||||
,
|
||||
".tmp_source.zig:6:9: error: enum tag value 60 already taken",
|
||||
".tmp_source.zig:4:9: note: other occurrence here");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user