diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2025-11-05 13:30:40 +0000 |
|---|---|---|
| committer | gingerBill <gingerBill@users.noreply.github.com> | 2025-11-05 13:30:40 +0000 |
| commit | 593d2e6daa1f0dd9c24c7fb8704463c8db757af0 (patch) | |
| tree | bb1ba4fc37dc14b11efd9197208ba1372aac9f21 /src | |
| parent | ea5db0e04864f7e453a5b5faa305df22543c4b75 (diff) | |
Add `#all_or_none`
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.cpp | 45 | ||||
| -rw-r--r-- | src/check_type.cpp | 7 | ||||
| -rw-r--r-- | src/llvm_backend_type.cpp | 8 | ||||
| -rw-r--r-- | src/name_canonicalization.cpp | 5 | ||||
| -rw-r--r-- | src/parser.cpp | 18 | ||||
| -rw-r--r-- | src/parser.hpp | 1 | ||||
| -rw-r--r-- | src/types.cpp | 8 |
7 files changed, 78 insertions, 14 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8ac277917..677735c44 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -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) { diff --git a/src/check_type.cpp b/src/check_type.cpp index 5accfbd9f..af07efd8f 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -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, diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 474999191..382304a4e 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -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)) { diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 87d7a8522..7cc4ad893 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -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); diff --git a/src/parser.cpp b/src/parser.cpp index 152e55f8b..d3b35f3f4 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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: { diff --git a/src/parser.hpp b/src/parser.hpp index 6127468d4..71b61d95f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -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; \ diff --git a/src/types.cpp b/src/types.cpp index b9089b9fc..eb20b8edf 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -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)) { |