aboutsummaryrefslogtreecommitdiff
path: root/src/check_type.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/check_type.cpp')
-rw-r--r--src/check_type.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 8a140d95e..8afac2fc5 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -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;