mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 12:30:28 +00:00
Add #all_or_none
This commit is contained in:
@@ -118,10 +118,10 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu
|
||||
|
||||
Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8]
|
||||
Type_Info_Struct_Flag :: enum u8 {
|
||||
packed = 0,
|
||||
raw_union = 1,
|
||||
_ = 2,
|
||||
align = 3,
|
||||
packed = 0,
|
||||
raw_union = 1,
|
||||
all_or_none = 2,
|
||||
align = 3,
|
||||
}
|
||||
|
||||
Type_Info_Struct :: struct {
|
||||
|
||||
@@ -408,9 +408,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
|
||||
}
|
||||
|
||||
print_string("struct ")
|
||||
if .packed in info.flags { print_string("#packed ") }
|
||||
if .raw_union in info.flags { print_string("#raw_union ") }
|
||||
// if .no_copy in info.flags { print_string("#no_copy ") }
|
||||
if .packed in info.flags { print_string("#packed ") }
|
||||
if .raw_union in info.flags { print_string("#raw_union ") }
|
||||
if .all_or_none in info.flags { print_string("#all_or_none ") }
|
||||
if .align in info.flags {
|
||||
print_string("#align(")
|
||||
print_u64(u64(ti.align))
|
||||
|
||||
@@ -790,6 +790,7 @@ Struct_Type :: struct {
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
is_no_copy: bool,
|
||||
is_all_or_none: bool,
|
||||
fields: ^Field_List,
|
||||
name_count: int,
|
||||
}
|
||||
|
||||
@@ -281,6 +281,7 @@ Type_Flag_Struct :: enum u32le {
|
||||
Polymorphic = 0,
|
||||
Packed = 1,
|
||||
Raw_Union = 2,
|
||||
All_Or_None = 3,
|
||||
}
|
||||
|
||||
Type_Flags_Union :: distinct bit_set[Type_Flag_Union; u32le]
|
||||
|
||||
@@ -2658,11 +2658,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
align: ^ast.Expr
|
||||
min_field_align: ^ast.Expr
|
||||
max_field_align: ^ast.Expr
|
||||
is_packed: bool
|
||||
is_raw_union: bool
|
||||
is_no_copy: bool
|
||||
fields: ^ast.Field_List
|
||||
name_count: int
|
||||
is_packed: bool
|
||||
is_raw_union: bool
|
||||
is_no_copy: bool
|
||||
is_all_or_none: bool
|
||||
fields: ^ast.Field_List
|
||||
name_count: int
|
||||
|
||||
if allow_token(p, .Open_Paren) {
|
||||
param_count: int
|
||||
@@ -2684,6 +2685,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
}
|
||||
is_packed = true
|
||||
case "all_or_none":
|
||||
if is_all_or_none {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
}
|
||||
is_all_or_none = true
|
||||
case "align":
|
||||
if align != nil {
|
||||
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
|
||||
@@ -2726,6 +2732,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
error(p, tok.pos, "'#raw_union' cannot also be '#packed")
|
||||
}
|
||||
|
||||
if is_raw_union && is_all_or_none {
|
||||
is_all_or_none = false
|
||||
error(p, tok.pos, "'#raw_union' cannot also be '#all_or_none")
|
||||
}
|
||||
|
||||
where_token: tokenizer.Token
|
||||
where_clauses: []^ast.Expr
|
||||
|
||||
@@ -2745,17 +2756,18 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
|
||||
close := expect_closing_brace_of_field_list(p)
|
||||
|
||||
st := ast.new(ast.Struct_Type, tok.pos, end_pos(close))
|
||||
st.poly_params = poly_params
|
||||
st.align = align
|
||||
st.min_field_align = min_field_align
|
||||
st.max_field_align = max_field_align
|
||||
st.is_packed = is_packed
|
||||
st.is_raw_union = is_raw_union
|
||||
st.is_no_copy = is_no_copy
|
||||
st.fields = fields
|
||||
st.name_count = name_count
|
||||
st.where_token = where_token
|
||||
st.where_clauses = where_clauses
|
||||
st.poly_params = poly_params
|
||||
st.align = align
|
||||
st.min_field_align = min_field_align
|
||||
st.max_field_align = max_field_align
|
||||
st.is_packed = is_packed
|
||||
st.is_raw_union = is_raw_union
|
||||
st.is_no_copy = is_no_copy
|
||||
st.is_all_or_none = is_all_or_none
|
||||
st.fields = fields
|
||||
st.name_count = name_count
|
||||
st.where_token = where_token
|
||||
st.where_clauses = where_clauses
|
||||
return st
|
||||
|
||||
case .Union:
|
||||
|
||||
@@ -696,9 +696,9 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
|
||||
}
|
||||
|
||||
io.write_string(w, "struct ", &n) or_return
|
||||
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
|
||||
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
|
||||
// if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return }
|
||||
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
|
||||
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
|
||||
if .all_or_none in info.flags { io.write_string(w, "#all_or_none ", &n) or_return }
|
||||
if .align in info.flags {
|
||||
io.write_string(w, "#align(", &n) or_return
|
||||
io.write_i64(w, i64(ti.align), 10, &n) or_return
|
||||
|
||||
@@ -9838,6 +9838,51 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
|
||||
|
||||
c->bit_field_bit_size = prev_bit_field_bit_size;
|
||||
}
|
||||
|
||||
if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) {
|
||||
PtrSet<Entity *> missing_fields = {};
|
||||
defer (ptr_set_destroy(&missing_fields));
|
||||
|
||||
for_array(i, bt->Struct.fields) {
|
||||
Entity *field = bt->Struct.fields[i];
|
||||
String name = field->token.string;
|
||||
if (is_blank_ident(name) || name == "") {
|
||||
continue;
|
||||
}
|
||||
bool found = string_set_exists(&fields_visited, name);
|
||||
String *raw_union = string_map_get(&fields_visited_through_raw_union, name);
|
||||
if (!found && raw_union == nullptr) {
|
||||
ptr_set_add(&missing_fields, field);
|
||||
}
|
||||
}
|
||||
|
||||
if (missing_fields.count > 0) {
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (build_context.terse_errors) {
|
||||
gbString fields_string = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(fields_string));
|
||||
isize i = 0;
|
||||
FOR_PTR_SET(field, missing_fields) {
|
||||
if (i > 0) {
|
||||
fields_string = gb_string_appendc(fields_string, ", ");
|
||||
}
|
||||
String name = field->token.string;
|
||||
fields_string = gb_string_append_length(fields_string, name.text, name.len);
|
||||
i += 1;
|
||||
}
|
||||
|
||||
error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string);
|
||||
} else {
|
||||
error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:");
|
||||
FOR_PTR_SET(field, missing_fields) {
|
||||
gbString s = type_to_string(field->type);
|
||||
error_line("\t%.*s: %s\n", LIT(field->token.string), s);
|
||||
gb_string_free(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {
|
||||
|
||||
@@ -654,9 +654,10 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
context = str_lit("struct #raw_union");
|
||||
}
|
||||
|
||||
struct_type->Struct.node = node;
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.node = node;
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.is_all_or_none = st->is_all_or_none;
|
||||
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, st->polymorphic_params,
|
||||
&struct_type->Struct.is_polymorphic,
|
||||
|
||||
@@ -817,10 +817,10 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ
|
||||
|
||||
{
|
||||
u8 flags = 0;
|
||||
if (t->Struct.is_packed) flags |= 1<<0;
|
||||
if (t->Struct.is_raw_union) flags |= 1<<1;
|
||||
//
|
||||
if (t->Struct.custom_align) flags |= 1<<3;
|
||||
if (t->Struct.is_packed) flags |= 1<<0;
|
||||
if (t->Struct.is_raw_union) flags |= 1<<1;
|
||||
if (t->Struct.is_all_or_none) flags |= 1<<2;
|
||||
if (t->Struct.custom_align) flags |= 1<<3;
|
||||
|
||||
vals[6] = lb_const_int(m, t_u8, flags).value;
|
||||
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
|
||||
|
||||
@@ -749,8 +749,9 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) {
|
||||
write_canonical_params(w, type->Struct.polymorphic_params);
|
||||
}
|
||||
|
||||
if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
|
||||
if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
|
||||
if (type->Struct.is_packed) type_writer_appendc(w, "#packed");
|
||||
if (type->Struct.is_raw_union) type_writer_appendc(w, "#raw_union");
|
||||
if (type->Struct.is_all_or_none) type_writer_appendc(w, "#all_or_none");
|
||||
if (type->Struct.custom_min_field_align != 0) type_writer_append_fmt(w, "#min_field_align(%lld)", cast(long long)type->Struct.custom_min_field_align);
|
||||
if (type->Struct.custom_max_field_align != 0) type_writer_append_fmt(w, "#max_field_align(%lld)", cast(long long)type->Struct.custom_max_field_align);
|
||||
if (type->Struct.custom_align != 0) type_writer_append_fmt(w, "#align(%lld)", cast(long long)type->Struct.custom_align);
|
||||
|
||||
@@ -1230,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) {
|
||||
}
|
||||
|
||||
gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy, bool is_all_or_none,
|
||||
Ast *align, Ast *min_field_align, Ast *max_field_align,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_StructType);
|
||||
@@ -1241,6 +1241,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
|
||||
result->StructType.is_packed = is_packed;
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.is_no_copy = is_no_copy;
|
||||
result->StructType.is_all_or_none = is_all_or_none;
|
||||
result->StructType.align = align;
|
||||
result->StructType.min_field_align = min_field_align;
|
||||
result->StructType.max_field_align = max_field_align;
|
||||
@@ -2773,6 +2774,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Token token = expect_token(f, Token_struct);
|
||||
Ast *polymorphic_params = nullptr;
|
||||
bool is_packed = false;
|
||||
bool is_all_or_none = false;
|
||||
bool is_raw_union = false;
|
||||
bool no_copy = false;
|
||||
Ast *align = nullptr;
|
||||
@@ -2802,6 +2804,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
is_packed = true;
|
||||
} else if (tag.string == "all_or_none") {
|
||||
if (is_packed) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
is_all_or_none = true;
|
||||
} else if (tag.string == "align") {
|
||||
if (align) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
@@ -2872,6 +2879,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
is_packed = false;
|
||||
syntax_error(token, "'#raw_union' cannot also be '#packed'");
|
||||
}
|
||||
if (is_raw_union && is_all_or_none) {
|
||||
is_all_or_none = false;
|
||||
syntax_error(token, "'#raw_union' cannot also be '#all_or_none'");
|
||||
}
|
||||
|
||||
Token where_token = {};
|
||||
Array<Ast *> where_clauses = {};
|
||||
@@ -2901,7 +2912,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
|
||||
parser_check_polymorphic_record_parameters(f, polymorphic_params);
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, min_field_align, max_field_align, where_token, where_clauses);
|
||||
return ast_struct_type(f, token, decls, name_count,
|
||||
polymorphic_params, is_packed, is_raw_union, no_copy, is_all_or_none,
|
||||
align, min_field_align, max_field_align,
|
||||
where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
|
||||
@@ -766,6 +766,7 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
bool is_no_copy; \
|
||||
bool is_all_or_none; \
|
||||
}) \
|
||||
AST_KIND(UnionType, "union type", struct { \
|
||||
Scope *scope; \
|
||||
|
||||
@@ -162,6 +162,7 @@ struct TypeStruct {
|
||||
bool are_offsets_set : 1;
|
||||
bool is_packed : 1;
|
||||
bool is_raw_union : 1;
|
||||
bool is_all_or_none : 1;
|
||||
bool is_poly_specialized : 1;
|
||||
|
||||
std::atomic<bool> are_offsets_being_processed;
|
||||
@@ -3084,9 +3085,10 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
||||
break;
|
||||
|
||||
case Type_Struct:
|
||||
if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
|
||||
x->Struct.fields.count == y->Struct.fields.count &&
|
||||
x->Struct.is_packed == y->Struct.is_packed &&
|
||||
if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
|
||||
x->Struct.fields.count == y->Struct.fields.count &&
|
||||
x->Struct.is_packed == y->Struct.is_packed &&
|
||||
x->Struct.is_all_or_none == y->Struct.is_all_or_none &&
|
||||
x->Struct.soa_kind == y->Struct.soa_kind &&
|
||||
x->Struct.soa_count == y->Struct.soa_count &&
|
||||
are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) {
|
||||
|
||||
Reference in New Issue
Block a user