aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLemonBoy <thatlemon@gmail.com>2019-05-10 19:28:13 +0200
committerLemonBoy <thatlemon@gmail.com>2019-05-11 21:29:53 +0200
commitb05e8d46ec0a1a26c533118d5a0bab2262a99a63 (patch)
treeb63f9f410579d34859c08d6c0d209a92f11ed0f7 /src
parent655794f44fc8563f9fa4d45c208e859382a6a599 (diff)
downloadzig-b05e8d46ec0a1a26c533118d5a0bab2262a99a63.tar.gz
zig-b05e8d46ec0a1a26c533118d5a0bab2262a99a63.zip
Change the enum value allocation strategy
Diffstat (limited to 'src')
-rw-r--r--src/analyze.cpp93
1 files changed, 40 insertions, 53 deletions
diff --git a/src/analyze.cpp b/src/analyze.cpp
index 9462ce0121..3f662c246c 100644
--- a/src/analyze.cpp
+++ b/src/analyze.cpp
@@ -2003,6 +2003,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
enum_type->abi_size = tag_int_type->abi_size;
enum_type->abi_align = tag_int_type->abi_align;
+ BigInt bi_one;
+ bigint_init_unsigned(&bi_one, 1);
+
+ TypeEnumField *last_enum_field = nullptr;
+
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];
@@ -2028,76 +2033,58 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
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) {
+ // A user-specified value is available
ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr);
if (type_is_invalid(result->type)) {
enum_type->data.enumeration.is_invalid = true;
continue;
}
+
assert(result->special != ConstValSpecialRuntime);
- assert(result->type->id == ZigTypeIdInt ||
- result->type->id == ZigTypeIdComptimeInt);
- auto entry = occupied_tag_values.put_unique(result->data.x_bigint, tag_value);
- if (entry == nullptr) {
- bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint);
+ assert(result->type->id == ZigTypeIdInt || result->type->id == ZigTypeIdComptimeInt);
+
+ bigint_init_bigint(&type_enum_field->value, &result->data.x_bigint);
+ } else {
+ // No value was explicitly specified: allocate the last value + 1
+ // or, if this is the first element, zero
+ if (last_enum_field != nullptr) {
+ bigint_add(&type_enum_field->value, &last_enum_field->value, &bi_one);
} else {
- Buf *val_buf = buf_alloc();
- bigint_append_buf(val_buf, &result->data.x_bigint, 10);
+ bigint_init_unsigned(&type_enum_field->value, 0);
+ }
- 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"));
+ // Make sure we can represent this number with tag_int_type
+ if (!bigint_fits_in_bits(&type_enum_field->value,
+ tag_int_type->size_in_bits,
+ tag_int_type->data.integral.is_signed)) {
enum_type->data.enumeration.is_invalid = true;
- continue;
- }
- }
- }
- // Now iterate again and populate the unspecified tag values
- BigInt next_maybe_unoccupied_index;
- bigint_init_unsigned(&next_maybe_unoccupied_index, 0);
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &type_enum_field->value, 10);
+ add_node_error(g, field_node,
+ buf_sprintf("enumeration value %s too large for type '%s'",
+ buf_ptr(val_buf), buf_ptr(&tag_int_type->name)));
- // Since we're allocating positive values only we have one less bit
- // available if the tag type is signed (eg. for a i8 we can only use (0,127))
- unsigned tag_bit_width = tag_int_type->size_in_bits;
- if (tag_int_type->data.integral.is_signed)
- tag_bit_width--;
+ break;
+ }
+ }
- 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;
+ // Make sure the value is unique
+ auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node);
+ if (entry != nullptr) {
+ enum_type->data.enumeration.is_invalid = true;
- // Already handled in the loop above
- if (tag_value != nullptr)
- continue;
+ Buf *val_buf = buf_alloc();
+ bigint_append_buf(val_buf, &type_enum_field->value, 10);
- // Make sure we can represent this number with tag_int_type
- const unsigned repr_bits = bigint_bits_needed(&next_maybe_unoccupied_index);
- if (repr_bits > tag_bit_width) {
- enum_type->data.enumeration.is_invalid = true;
- add_node_error(g, field_node,
- buf_sprintf("enumeration value %" ZIG_PRI_u64 " too large for type '%s'",
- bigint_as_unsigned(&next_maybe_unoccupied_index),
- buf_ptr(&tag_int_type->name)));
- break;
+ ErrorMsg *msg = add_node_error(g, field_node,
+ buf_sprintf("enum tag value %s already taken", buf_ptr(val_buf)));
+ add_error_note(g, msg, entry->value,
+ buf_sprintf("other occurrence here"));
}
- if (occupied_tag_values.size() == 0) {
- type_enum_field->value = next_maybe_unoccupied_index;
- bigint_incr(&next_maybe_unoccupied_index);
- } else {
- for (;;) {
- auto entry = occupied_tag_values.put_unique(next_maybe_unoccupied_index, field_node);
- if (entry == nullptr)
- break;
- bigint_incr(&next_maybe_unoccupied_index);
- }
- type_enum_field->value = next_maybe_unoccupied_index;
- }
+ last_enum_field = type_enum_field;
}
enum_type->data.enumeration.zero_bits_loop_flag = false;