|
@@ -925,6 +925,144 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam
|
|
|
enum_type->Enum.max_value_index = max_value_index;
|
|
|
}
|
|
|
|
|
|
+gb_internal bool is_valid_bit_field_backing_type(Type *type) {
|
|
|
+ if (type == nullptr) {
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+ type = base_type(type);
|
|
|
+ if (is_type_untyped(type)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ if (is_type_integer(type)) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (type->kind == Type_Array) {
|
|
|
+ return is_type_integer(type->Array.elem);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, Type *named_type, Ast *node) {
|
|
|
+ ast_node(bf, BitFieldType, node);
|
|
|
+ GB_ASSERT(is_type_bit_field(bit_field_type));
|
|
|
+
|
|
|
+ Type *backing_type = check_type(ctx, bf->backing_type);
|
|
|
+ if (backing_type == nullptr || !is_valid_bit_field_backing_type(backing_type)) {
|
|
|
+ error(node, "Backing type for a bit_field must be an integer or an array of an integer");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ bit_field_type->BitField.backing_type = backing_type;
|
|
|
+ bit_field_type->BitField.scope = ctx->scope;
|
|
|
+
|
|
|
+ auto fields = array_make<Entity *>(permanent_allocator(), 0, bf->fields.count);
|
|
|
+ auto bit_sizes = array_make<u8> (permanent_allocator(), 0, bf->fields.count);
|
|
|
+
|
|
|
+ u64 maximum_bit_size = 8 * type_size_of(backing_type);
|
|
|
+ u64 total_bit_size = 0;
|
|
|
+
|
|
|
+ for_array(i, bf->fields) {
|
|
|
+ i32 field_src_index = cast(i32)i;
|
|
|
+ Ast *field = bf->fields[i];
|
|
|
+ if (field->kind != Ast_BitFieldField) {
|
|
|
+ error(field, "Invalid AST for a bit_field");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ ast_node(f, BitFieldField, field);
|
|
|
+ if (f->name == nullptr || f->name->kind != Ast_Ident) {
|
|
|
+ error(field, "A bit_field's field name must be an identifier");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ CommentGroup *docs = f->docs;
|
|
|
+ CommentGroup *comment = f->comment;
|
|
|
+
|
|
|
+ String name = f->name->Ident.token.string;
|
|
|
+
|
|
|
+ if (f->type == nullptr) {
|
|
|
+ error(field, "A bit_field's field must have a type");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Type *type = check_type(ctx, f->type);
|
|
|
+ if (type_size_of(type) > 8) {
|
|
|
+ error(f->type, "The type of a bit_field's field must be <= 8 bytes, got %lld", cast(long long)type_size_of(type));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (is_type_untyped(type)) {
|
|
|
+ gbString s = type_to_string(type);
|
|
|
+ error(f->type, "The type of a bit_field's field must be a typed integer, enum, or boolean, got %s", s);
|
|
|
+ gb_string_free(s);
|
|
|
+ } else if (!(is_type_integer(type) || is_type_enum(type) || is_type_boolean(type))) {
|
|
|
+ gbString s = type_to_string(type);
|
|
|
+ error(f->type, "The type of a bit_field's field must be an integer, enum, or boolean, got %s", s);
|
|
|
+ gb_string_free(s);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (f->bit_size == nullptr) {
|
|
|
+ error(field, "A bit_field's field must have a specified bit size");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Operand o = {};
|
|
|
+ check_expr(ctx, &o, f->bit_size);
|
|
|
+ if (o.mode != Addressing_Constant) {
|
|
|
+ error(f->bit_size, "A bit_field's specified bit size must be a constant");
|
|
|
+ o.mode = Addressing_Invalid;
|
|
|
+ }
|
|
|
+ if (o.value.kind == ExactValue_Float) {
|
|
|
+ o.value = exact_value_to_integer(o.value);
|
|
|
+ }
|
|
|
+
|
|
|
+ ExactValue bit_size = o.value;
|
|
|
+
|
|
|
+ if (bit_size.kind != ExactValue_Integer) {
|
|
|
+ gbString s = expr_to_string(f->bit_size);
|
|
|
+ error(f->bit_size, "Expected an integer constant value for the specified bit size, got %s", s);
|
|
|
+ gb_string_free(s);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (scope_lookup_current(ctx->scope, name) != nullptr) {
|
|
|
+ error(f->name, "'%.*s' is already declared in this bit_field", LIT(name));
|
|
|
+ } else {
|
|
|
+ i64 bit_size_i64 = exact_value_to_i64(bit_size);
|
|
|
+ u8 bit_size_u8 = 0;
|
|
|
+ if (bit_size_i64 <= 0) {
|
|
|
+ error(f->bit_size, "A bit_field's specified bit size cannot be <= 0, got %lld", cast(long long)bit_size_i64);
|
|
|
+ bit_size_i64 = 1;
|
|
|
+ }
|
|
|
+ if (bit_size_i64 > 64) {
|
|
|
+ error(f->bit_size, "A bit_field's specified bit size cannot exceed 64 bits, got %lld", cast(long long)bit_size_i64);
|
|
|
+ bit_size_i64 = 64;
|
|
|
+ }
|
|
|
+ bit_size_u8 = cast(u8)bit_size_i64;
|
|
|
+
|
|
|
+ Entity *e = alloc_entity_field(ctx->scope, f->name->Ident.token, type, false, field_src_index);
|
|
|
+ e->Variable.docs = docs;
|
|
|
+ e->Variable.comment = comment;
|
|
|
+
|
|
|
+ add_entity(ctx, ctx->scope, nullptr, e);
|
|
|
+ array_add(&fields, e);
|
|
|
+ array_add(&bit_sizes, bit_size_u8);
|
|
|
+ add_entity_use(ctx, field, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ GB_ASSERT(fields.count <= bf->fields.count);
|
|
|
+
|
|
|
+ if (total_bit_size > maximum_bit_size) {
|
|
|
+ gbString s = type_to_string(backing_type);
|
|
|
+ error(node, "The numbers required %llu exceeds the backing type's (%s) bit size %llu",
|
|
|
+ cast(unsigned long long)total_bit_size,
|
|
|
+ s,
|
|
|
+ cast(unsigned long long)maximum_bit_size);
|
|
|
+ gb_string_free(s);
|
|
|
+ }
|
|
|
+
|
|
|
+ bit_field_type->BitField.fields = slice_from_array(fields);
|
|
|
+ bit_field_type->BitField.bit_sizes = slice_from_array(bit_sizes);
|
|
|
+}
|
|
|
+
|
|
|
gb_internal bool is_type_valid_bit_set_range(Type *t) {
|
|
|
if (is_type_integer(t)) {
|
|
|
return true;
|
|
@@ -3051,6 +3189,20 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T
|
|
|
return true;
|
|
|
case_end;
|
|
|
|
|
|
+ case_ast_node(bf, BitFieldType, e);
|
|
|
+ bool ips = ctx->in_polymorphic_specialization;
|
|
|
+ defer (ctx->in_polymorphic_specialization = ips);
|
|
|
+ ctx->in_polymorphic_specialization = false;
|
|
|
+
|
|
|
+ *type = alloc_type_bit_field();
|
|
|
+ set_base_type(named_type, *type);
|
|
|
+ check_open_scope(ctx, e);
|
|
|
+ check_bit_field_type(ctx, *type, named_type, e);
|
|
|
+ check_close_scope(ctx);
|
|
|
+ (*type)->BitField.node = e;
|
|
|
+ return true;
|
|
|
+ case_end;
|
|
|
+
|
|
|
|
|
|
case_ast_node(pt, ProcType, e);
|
|
|
bool ips = ctx->in_polymorphic_specialization;
|