mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-10 13:21:37 -07:00
Support compound literals for bit_field
This commit is contained in:
@@ -139,7 +139,7 @@ Entity :: struct {
|
||||
// May be used by (Struct fields and procedure fields):
|
||||
// .Variable
|
||||
// .Constant
|
||||
// This is equal to the "bit size" it this is a `bit_field`s field
|
||||
// This is equal to the negative of the "bit size" it this is a `bit_field`s field
|
||||
field_group_index: i32le,
|
||||
|
||||
// May used by:
|
||||
|
||||
+44
-5
@@ -8440,6 +8440,11 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
StringMap<String> fields_visited_through_raw_union = {};
|
||||
defer (string_map_destroy(&fields_visited_through_raw_union));
|
||||
|
||||
String assignment_str = str_lit("structure literal");
|
||||
if (bt->kind == Type_BitField) {
|
||||
assignment_str = str_lit("bit_field literal");
|
||||
}
|
||||
|
||||
for (Ast *elem : elems) {
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
error(elem, "Mixture of 'field = value' and value elements in a literal is not allowed");
|
||||
@@ -8461,17 +8466,26 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
continue;
|
||||
}
|
||||
|
||||
Entity *field = bt->Struct.fields[sel.index[0]];
|
||||
Entity *field = nullptr;
|
||||
if (bt->kind == Type_Struct) {
|
||||
field = bt->Struct.fields[sel.index[0]];
|
||||
} else if (bt->kind == Type_BitField) {
|
||||
field = bt->BitField.fields[sel.index[0]];
|
||||
} else {
|
||||
GB_PANIC("Unknown type");
|
||||
}
|
||||
|
||||
|
||||
add_entity_use(c, fv->field, field);
|
||||
if (string_set_update(&fields_visited, name)) {
|
||||
if (sel.index.count > 1) {
|
||||
if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) {
|
||||
error(fv->field, "Field '%.*s' is already initialized due to a previously assigned struct #raw_union field '%.*s'", LIT(sel.entity->token.string), LIT(*found));
|
||||
} else {
|
||||
error(fv->field, "Duplicate or reused field '%.*s' in structure literal", LIT(sel.entity->token.string));
|
||||
error(fv->field, "Duplicate or reused field '%.*s' in %.*s", LIT(sel.entity->token.string), LIT(assignment_str));
|
||||
}
|
||||
} else {
|
||||
error(fv->field, "Duplicate field '%.*s' in structure literal", LIT(field->token.string));
|
||||
error(fv->field, "Duplicate field '%.*s' in %.*s", LIT(field->token.string), LIT(assignment_str));
|
||||
}
|
||||
continue;
|
||||
} else if (String *found = string_map_get(&fields_visited_through_raw_union, sel.entity->token.string)) {
|
||||
@@ -8479,11 +8493,13 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
continue;
|
||||
}
|
||||
if (sel.indirect) {
|
||||
error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a structure literal", cast(int)sel.index.count-1, LIT(name));
|
||||
error(fv->field, "Cannot assign to the %d-nested anonymous indirect field '%.*s' in a %.*s", cast(int)sel.index.count-1, LIT(name), LIT(assignment_str));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sel.index.count > 1) {
|
||||
GB_ASSERT(bt->kind == Type_Struct);
|
||||
|
||||
if (is_constant) {
|
||||
Type *ft = type;
|
||||
for (i32 index : sel.index) {
|
||||
@@ -8544,7 +8560,15 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
is_constant = check_is_operand_compound_lit_constant(c, &o);
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, str_lit("structure literal"));
|
||||
u8 prev_bit_field_bit_size = c->bit_field_bit_size;
|
||||
if (field->kind == Entity_Variable && field->Variable.bit_field_bit_size) {
|
||||
// HACK NOTE(bill): This is a bit of a hack, but it will work fine for this use case
|
||||
c->bit_field_bit_size = field->Variable.bit_field_bit_size;
|
||||
}
|
||||
|
||||
check_assignment(c, &o, field->type, assignment_str);
|
||||
|
||||
c->bit_field_bit_size = prev_bit_field_bit_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9346,6 +9370,21 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Type_BitField: {
|
||||
if (cl->elems.count == 0) {
|
||||
break; // NOTE(bill): No need to init
|
||||
}
|
||||
is_constant = false;
|
||||
if (cl->elems[0]->kind != Ast_FieldValue) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(node, "%s ('bit_field') compound literals are only allowed to contain 'field = value' elements", type_str);
|
||||
gb_string_free(type_str);
|
||||
} else {
|
||||
check_compound_literal_field_values(c, cl->elems, o, type, is_constant);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
default: {
|
||||
if (cl->elems.count == 0) {
|
||||
|
||||
@@ -4235,6 +4235,38 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
switch (bt->kind) {
|
||||
default: GB_PANIC("Unknown CompoundLit type: %s", type_to_string(type)); break;
|
||||
|
||||
case Type_BitField:
|
||||
for (Ast *elem : cl->elems) {
|
||||
ast_node(fv, FieldValue, elem);
|
||||
String name = fv->field->Ident.token.string;
|
||||
Selection sel = lookup_field(bt, name, false);
|
||||
GB_ASSERT(sel.is_bit_field);
|
||||
GB_ASSERT(!sel.indirect);
|
||||
GB_ASSERT(sel.index.count == 1);
|
||||
GB_ASSERT(sel.entity != nullptr);
|
||||
|
||||
i64 index = sel.index[0];
|
||||
i64 bit_offset = 0;
|
||||
i64 bit_size = -1;
|
||||
for_array(i, bt->BitField.fields) {
|
||||
Entity *f = bt->BitField.fields[i];
|
||||
if (f == sel.entity) {
|
||||
bit_offset = bt->BitField.bit_offsets[i];
|
||||
bit_size = bt->BitField.bit_sizes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT(bit_size > 0);
|
||||
|
||||
Type *field_type = sel.entity->type;
|
||||
lbValue field_expr = lb_build_expr(p, fv->value);
|
||||
field_expr = lb_emit_conv(p, field_expr, field_type);
|
||||
|
||||
lbAddr field_addr = lb_addr_bit_field(v.addr, field_type, index, bit_offset, bit_size);
|
||||
lb_addr_store(p, field_addr, field_expr);
|
||||
}
|
||||
return v;
|
||||
|
||||
case Type_Struct: {
|
||||
// TODO(bill): "constant" '#raw_union's are not initialized constantly at the moment.
|
||||
// NOTE(bill): This is due to the layout of the unions when printed to LLVM-IR
|
||||
|
||||
Reference in New Issue
Block a user