diff options
| author | gingerBill <gingerBill@users.noreply.github.com> | 2025-12-01 11:53:08 +0000 |
|---|---|---|
| committer | gingerBill <gingerBill@users.noreply.github.com> | 2025-12-01 11:53:08 +0000 |
| commit | 3771ff7b123bf1debe2da2886d833791ee890b39 (patch) | |
| tree | 69cc14a85ef5cb47ede1280df76f6206aa934d00 /src | |
| parent | 9f80d697027a41a9c36b8eb42d9c98f9b7fcbe2c (diff) | |
| parent | e72aad983bb683858a1aee935b2956ced40f69f8 (diff) | |
Merge branch 'master' into vendor/curl
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_builtin.cpp | 124 | ||||
| -rw-r--r-- | src/check_decl.cpp | 3 | ||||
| -rw-r--r-- | src/check_expr.cpp | 115 | ||||
| -rw-r--r-- | src/check_type.cpp | 9 | ||||
| -rw-r--r-- | src/checker.cpp | 32 | ||||
| -rw-r--r-- | src/checker_builtin_procs.hpp | 2 | ||||
| -rw-r--r-- | src/docs_format.cpp | 62 | ||||
| -rw-r--r-- | src/docs_writer.cpp | 7 | ||||
| -rw-r--r-- | src/llvm_backend.cpp | 14 | ||||
| -rw-r--r-- | src/llvm_backend_const.cpp | 40 | ||||
| -rw-r--r-- | src/llvm_backend_debug.cpp | 6 | ||||
| -rw-r--r-- | src/llvm_backend_expr.cpp | 9 | ||||
| -rw-r--r-- | src/llvm_backend_proc.cpp | 2 | ||||
| -rw-r--r-- | src/llvm_backend_stmt.cpp | 13 | ||||
| -rw-r--r-- | src/llvm_backend_type.cpp | 33 | ||||
| -rw-r--r-- | src/llvm_backend_utility.cpp | 2 | ||||
| -rw-r--r-- | src/main.cpp | 34 | ||||
| -rw-r--r-- | src/name_canonicalization.cpp | 177 | ||||
| -rw-r--r-- | src/parser.cpp | 25 | ||||
| -rw-r--r-- | src/parser.hpp | 1 | ||||
| -rw-r--r-- | src/tilde_type_info.cpp | 12 | ||||
| -rw-r--r-- | src/types.cpp | 13 | ||||
| -rw-r--r-- | src/ucg/ucg.c | 2 | ||||
| -rw-r--r-- | src/ucg/ucg_tables.h | 2 |
24 files changed, 626 insertions, 113 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b2d28afc0..1b3e6912c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2485,6 +2485,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As case BuiltinProc_min: case BuiltinProc_max: case BuiltinProc_type_is_subtype_of: + case BuiltinProc_type_is_superset_of: case BuiltinProc_objc_send: case BuiltinProc_objc_find_selector: case BuiltinProc_objc_find_class: @@ -7397,6 +7398,129 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As operand->type = t_untyped_bool; } break; + case BuiltinProc_type_is_superset_of: + { + Operand op_super = {}; + Operand op_sub = {}; + + check_expr_or_type(c, &op_super, ce->args[0]); + if (op_super.mode != Addressing_Type) { + gbString e = expr_to_string(op_super.expr); + error(op_super.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + check_expr_or_type(c, &op_sub, ce->args[1]); + if (op_sub.mode != Addressing_Type) { + gbString e = expr_to_string(op_sub.expr); + error(op_sub.expr, "'%.*s' expects a type, got %s", LIT(builtin_name), e); + gb_string_free(e); + return false; + } + + operand->mode = Addressing_Constant; + operand->type = t_untyped_bool; + + Type *super = op_super.type; + Type *sub = op_sub.type; + if (are_types_identical(super, sub)) { + operand->value = exact_value_bool(true); + return true; + } + + super = base_type(super); + sub = base_type(sub); + if (are_types_identical(super, sub)) { + operand->value = exact_value_bool(true); + return true; + } + + if (super->kind != sub->kind) { + gbString a = type_to_string(op_super.type); + gbString b = type_to_string(op_sub.type); + error(op_super.expr, "'%.*s' expects types of the same kind, got %s vs %s", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + + if (super->kind == Type_Enum) { + if (sub->Enum.fields.count > super->Enum.fields.count) { + operand->value = exact_value_bool(false); + return true; + } + + + Type *base_super = base_enum_type(super); + Type *base_sub = base_enum_type(sub); + if (base_super == base_sub && base_super == nullptr) { + // okay + } else if (!are_types_identical(base_type(base_super), base_type(base_sub))) { + operand->value = exact_value_bool(false); + return true; + } + + for (Entity *f_sub : sub->Enum.fields) { + bool found = false; + + if (f_sub->kind != Entity_Constant) { + continue; + } + + for (Entity *f_super : super->Enum.fields) { + if (f_super->kind != Entity_Constant) { + continue; + } + + if (f_sub->token.string == f_super->token.string) { + if (compare_exact_values(Token_CmpEq, f_sub->Constant.value, f_super->Constant.value)) { + found = true; + break; + } + } + } + + if (!found) { + operand->value = exact_value_bool(false); + return true; + } + } + + operand->value = exact_value_bool(true); + return true; + + } else if (super->kind == Type_Union) { + if (sub->Union.variants.count > super->Union.variants.count) { + operand->value = exact_value_bool(false); + return true; + } + if (sub->Union.kind != super->Union.kind) { + operand->value = exact_value_bool(false); + return true; + } + + for_array(i, sub->Union.variants) { + Type *t_sub = sub->Union.variants[i]; + Type *t_super = super->Union.variants[i]; + if (!are_types_identical(t_sub, t_super)) { + operand->value = exact_value_bool(false); + return true; + } + } + + operand->value = exact_value_bool(true); + return true; + + } + gbString a = type_to_string(op_super.type); + gbString b = type_to_string(op_sub.type); + error(op_super.expr, "'%.*s' expects types of the same kind and either an enum or union, got %s vs %s", LIT(builtin_name), a, b); + gb_string_free(b); + gb_string_free(a); + return false; + } + + case BuiltinProc_type_field_index_of: { Operand op = {}; diff --git a/src/check_decl.cpp b/src/check_decl.cpp index e54943d80..27babd255 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1607,8 +1607,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) { if (is_arch_wasm() && foreign_library != nullptr) { // NOTE(bill): this must be delayed because the foreign import paths might not be evaluated yet until much later mpsc_enqueue(&ctx->info->foreign_decls_to_check, e); - } else { - // TODO(harold): Check if it's an objective-C foreign, if so, I don't think we need to check it. + } else if (!e->Procedure.is_objc_impl_or_import) { check_foreign_procedure(ctx, e, d); } } else { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index e22f12323..418fb5378 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9200,6 +9200,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A return kind; } + +gb_internal void check_expr_as_value_for_ternary(CheckerContext *c, Operand *o, Ast *e, Type *type_hint) { + check_expr_base(c, o, e, type_hint); + check_not_tuple(c, o); + error_operand_no_value(o); + + switch (o->mode) { + case Addressing_Type: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A type '%s' cannot be used as a runtime value", expr_str); + + error_line("\tSuggestion: If a runtime 'typeid' is wanted, use 'typeid_of' to convert a type\n"); + + o->mode = Addressing_Invalid; + + } break; + + case Addressing_Builtin: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "A built-in procedure '%s' cannot be used as a runtime value", expr_str); + + error_line("\tNote: Built-in procedures are implemented by the compiler and might not be actually instantiated procedures\n"); + + o->mode = Addressing_Invalid; + } break; + + case Addressing_ProcGroup: { + ERROR_BLOCK(); + gbString expr_str = expr_to_string(o->expr); + defer (gb_string_free(expr_str)); + + error(o->expr, "Cannot use overloaded procedure '%s' as a runtime value", expr_str); + + error_line("\tNote: Please specify which procedure in the procedure group to use, via cast or type inference\n"); + + o->mode = Addressing_Invalid; + } break; + } +} + gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_hint) { ExprKind kind = Expr_Expr; Operand cond = {Addressing_Invalid}; @@ -9213,7 +9259,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n Operand x = {Addressing_Invalid}; Operand y = {Addressing_Invalid}; - check_expr_or_type(c, &x, te->x, type_hint); + check_expr_as_value_for_ternary(c, &x, te->x, type_hint); node->viral_state_flags |= te->x->viral_state_flags; if (te->y != nullptr) { @@ -9221,7 +9267,7 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n if (type_hint == nullptr && is_type_typed(x.type)) { th = x.type; } - check_expr_or_type(c, &y, te->y, th); + check_expr_as_value_for_ternary(c, &y, te->y, th); node->viral_state_flags |= te->y->viral_state_flags; } else { error(node, "A ternary expression must have an else clause"); @@ -9248,6 +9294,20 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n return kind; } + if (x.mode == Addressing_Builtin && y.mode == Addressing_Builtin) { + if (type_hint == nullptr) { + error(node, "Built-in procedures cannot be used within a ternary expression since they have no well-defined signature"); + return kind; + } + } + + if (x.mode == Addressing_ProcGroup && y.mode == Addressing_ProcGroup) { + if (type_hint == nullptr) { + error(node, "Procedure groups cannot be used within a ternary expression since they have no well-defined signature that can be inferred without a context"); + return kind; + } + } + // NOTE(bill, 2023-01-30): Allow for expression like this: // x: union{f32} = f32(123) if cond else nil if (type_hint && !is_type_any(type_hint)) { @@ -9778,6 +9838,57 @@ 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) { + Ast *expr = o->expr; + if (expr == nullptr) { + GB_ASSERT(elems.count > 0); + expr = elems[elems.count-1]; + } + + 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(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(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 f1a2e9e22..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, @@ -1633,6 +1634,8 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { } else if (expr->kind == Ast_Ident) { Operand x= {}; Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, true); + GB_ASSERT(e != nullptr); + if (e->flags & EntityFlag_Param) { return true; } diff --git a/src/checker.cpp b/src/checker.cpp index 8b3638c9d..4d5482933 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -790,8 +790,10 @@ gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_fl // Is >256 KiB good enough? if (sz > 1ll<<18) { bool is_ref = false; - if((e->flags & EntityFlag_ForValue) != 0) { + if ((e->flags & EntityFlag_ForValue) != 0) { is_ref = type_deref(e->Variable.for_loop_parent_type) != NULL; + } else if ((e->flags & EntityFlag_SwitchValue) != 0) { + is_ref = !(e->flags & EntityFlag_Value); } if(!is_ref) { gbString type_str = type_to_string(e->type); @@ -923,6 +925,22 @@ gb_internal AstPackage *get_core_package(CheckerInfo *info, String name) { return *found; } + +gb_internal AstPackage *try_get_core_package(CheckerInfo *info, String name) { + if (name == "runtime") { + return get_runtime_package(info); + } + + gbAllocator a = heap_allocator(); + String path = get_fullpath_core_collection(a, name, nullptr); + defer (gb_free(a, path.text)); + auto found = string_map_get(&info->packages, path); + if (found == nullptr) { + return nullptr; + } + return *found; +} + gb_internal void add_package_dependency(CheckerContext *c, char const *package_name, char const *name, bool required=false) { String n = make_string_c(name); AstPackage *p = get_core_package(&c->checker->info, make_string_c(package_name)); @@ -7015,9 +7033,11 @@ gb_internal void check_objc_context_provider_procedures(Checker *c) { } } -gb_internal void check_unique_package_names(Checker *c) { +gb_internal bool check_unique_package_names(Checker *c) { ERROR_BLOCK(); + bool ok = true; + StringMap<AstPackage *> pkgs = {}; // Key: package name string_map_init(&pkgs, 2*c->info.packages.count); defer (string_map_destroy(&pkgs)); @@ -7042,6 +7062,7 @@ gb_internal void check_unique_package_names(Checker *c) { continue; } + ok = false; begin_error_block(); error(curr, "Duplicate declaration of 'package %.*s'", LIT(name)); @@ -7064,6 +7085,8 @@ gb_internal void check_unique_package_names(Checker *c) { end_error_block(); } + + return ok; } gb_internal void check_add_entities_from_queues(Checker *c) { @@ -7446,7 +7469,7 @@ gb_internal void check_parsed_files(Checker *c) { debugf("Total Procedure Bodies Checked: %td\n", total_bodies_checked.load(std::memory_order_relaxed)); TIME_SECTION("check unique package names"); - check_unique_package_names(c); + bool package_names_are_unique = check_unique_package_names(c); TIME_SECTION("sanity checks"); check_merge_queues_into_arrays(c); @@ -7503,7 +7526,8 @@ gb_internal void check_parsed_files(Checker *c) { c->info.type_info_types_hash_map[index] = tt; bool exists = map_set_if_not_previously_exists(&c->info.min_dep_type_info_index_map, tt.hash, index); - if (exists) { + // Because we've already written a nice error about a duplicate package declaration, skip this panic if the package names aren't unique. + if (package_names_are_unique && exists) { for (auto const &entry : c->info.min_dep_type_info_index_map) { if (entry.key != tt.hash) { continue; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 663274cdc..5b446cc1c 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -336,6 +336,7 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_polymorphic_record_parameter_value, BuiltinProc_type_is_subtype_of, + BuiltinProc_type_is_superset_of, BuiltinProc_type_field_index_of, @@ -708,6 +709,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_polymorphic_record_parameter_value"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_is_subtype_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_is_superset_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics }, {STR_LIT("type_field_index_of"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, diff --git a/src/docs_format.cpp b/src/docs_format.cpp index 6378971d0..2235789d5 100644 --- a/src/docs_format.cpp +++ b/src/docs_format.cpp @@ -94,6 +94,7 @@ enum OdinDocTypeFlag_Struct : u32 { OdinDocTypeFlag_Struct_polymorphic = 1<<0, OdinDocTypeFlag_Struct_packed = 1<<1, OdinDocTypeFlag_Struct_raw_union = 1<<2, + OdinDocTypeFlag_Struct_all_or_none = 1<<3, }; enum OdinDocTypeFlag_Union : u32 { @@ -124,21 +125,76 @@ enum { struct OdinDocType { OdinDocTypeKind kind; + // Type_Kind specific used by some types + // Underlying flag types: + // .Basic - Type_Flags_Basic + // .Struct - Type_Flags_Struct + // .Union - Type_Flags_Union + // .Proc - Type_Flags_Proc + // .Bit_Set - Type_Flags_Bit_Set u32 flags; + + // Used by: + // .Basic + // .Named + // .Generic OdinDocString name; + + // Used By: .Struct, .Union OdinDocString custom_align; - // Used by some types + // Used by: + // .Array - 1 count: 0=len + // .Enumerated_Array - 1 count: 0=len + // .SOA_Struct_Fixed - 1 count: 0=len + // .Bit_Set - 2 count: 0=lower, 1=upper + // .Simd_Vector - 1 count: 0=len + // .Matrix - 2 count: 0=row_count, 1=column_count + // .Struct - <=2 count: 0=min_field_align, 1=max_field_align u32 elem_count_len; i64 elem_counts[OdinDocType_ElemsCap]; - // Each of these is esed by some types, not all + // Used by: .Procedures + // blank implies the "odin" calling convention OdinDocString calling_convention; + + // Used by: + // .Named - 1 type: 0=base type + // .Generic - <1 type: 0=specialization + // .Pointer - 1 type: 0=element + // .Array - 1 type: 0=element + // .Enumerated_Array - 2 types: 0=index and 1=element + // .Slice - 1 type: 0=element + // .Dynamic_Array - 1 type: 0=element + // .Map - 2 types: 0=key, 1=value + // .SOA_Struct_Fixed - 1 type: underlying SOA struct element + // .SOA_Struct_Slice - 1 type: underlying SOA struct element + // .SOA_Struct_Dynamic - 1 type: underlying SOA struct element + // .Union - 0+ types: variants + // .Enum - <1 type: 0=base type + // .Proc - 2 types: 0=parameters, 1=results + // .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set) + // .Simd_Vector - 1 type: 0=element + // .Relative_Pointer - 2 types: 0=pointer type, 1=base integer + // .Multi_Pointer - 1 type: 0=element + // .Matrix - 1 type: 0=element + // .Soa_Pointer - 1 type: 0=element + // .Bit_Field - 1 type: 0=backing type OdinDocArray<OdinDocTypeIndex> types; + + // Used by: + // .Named - 1 field for the definition + // .Struct - fields + // .Enum - fields + // .Parameters - parameters (procedures only) OdinDocArray<OdinDocEntityIndex> entities; + + // Used By: .Struct, .Union OdinDocTypeIndex polmorphic_params; + // Used By: .Struct, .Union OdinDocArray<OdinDocString> where_clauses; - OdinDocArray<OdinDocString> tags; // struct field tags + // Used By: .Struct + OdinDocArray<OdinDocString> tags; }; struct OdinDocAttribute { diff --git a/src/docs_writer.cpp b/src/docs_writer.cpp index 1f2325980..3edd7da9d 100644 --- a/src/docs_writer.cpp +++ b/src/docs_writer.cpp @@ -620,6 +620,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca if (type->Struct.is_polymorphic) { doc_type.flags |= OdinDocTypeFlag_Struct_polymorphic; } if (type->Struct.is_packed) { doc_type.flags |= OdinDocTypeFlag_Struct_packed; } if (type->Struct.is_raw_union) { doc_type.flags |= OdinDocTypeFlag_Struct_raw_union; } + if (type->Struct.is_all_or_none) { doc_type.flags |= OdinDocTypeFlag_Struct_all_or_none; } + + if (type->Struct.custom_min_field_align > 0 || type->Struct.custom_max_field_align > 0) { + doc_type.elem_count_len = 2; + doc_type.elem_counts[0] = cast(u32)gb_max(type->Struct.custom_min_field_align, 0); + doc_type.elem_counts[1] = cast(u32)gb_max(type->Struct.custom_max_field_align, 0); + } auto fields = array_make<OdinDocEntityIndex>(heap_allocator(), type->Struct.fields.count); defer (array_free(&fields)); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 22a481187..71bca42ab 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -2090,6 +2090,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur name = gb_string_append_length(name, ename.text, ename.len); lbProcedure *dummy = lb_create_dummy_procedure(m, make_string_c(name), dummy_type); + dummy->is_startup = true; LLVMSetVisibility(dummy->value, LLVMHiddenVisibility); LLVMSetLinkage(dummy->value, LLVMWeakAnyLinkage); @@ -2900,7 +2901,18 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star args[0] = lb_addr_load(p, all_tests_slice); lbValue result = lb_emit_call(p, runner, args); - lbValue exit_runner = lb_find_package_value(m, str_lit("os"), str_lit("exit")); + lbValue exit_runner = {}; + { + AstPackage *pkg = get_runtime_package(m->info); + + String name = str_lit("exit"); + Entity *e = scope_lookup_current(pkg->scope, name); + if (e == nullptr) { + compiler_error("Could not find type declaration for '%.*s.%.*s'\n", LIT(pkg->name), LIT(name)); + } + exit_runner = lb_find_value_from_entity(m, e); + } + auto exit_args = array_make<lbValue>(temporary_allocator(), 1); exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1)); lb_emit_call(p, exit_runner, exit_args, ProcInlining_none); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index a7117fe0b..22e124792 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -185,8 +185,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue } Type *bt = base_type(t); GB_ASSERT(bt->kind == Type_Struct || bt->kind == Type_Union); - - GB_ASSERT(value_count_ == bt->Struct.fields.count); + GB_ASSERT(bt->kind != Type_Struct || value_count_ == bt->Struct.fields.count); auto field_remapping = lb_get_struct_remapping(m, t); unsigned values_with_padding_count = elem_count; @@ -513,7 +512,7 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi max_count = mp_pack_count(a, nails, size); if (sz < max_count) { debug_print_big_int(a); - gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz);; + gb_printf_err("%s -> %tu\n", type_to_string(original_type), sz); } GB_ASSERT_MSG(sz >= max_count, "max_count: %tu, sz: %tu, written: %tu, type %s", max_count, sz, written, type_to_string(original_type)); GB_ASSERT(gb_size_of(rop64) >= sz); @@ -691,11 +690,20 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } else if (bt->Union.variants.count == 1) { if (value.kind == ExactValue_Compound) { ast_node(cl, CompoundLit, value.value_compound); - if (cl->elems.count == 0 && cl->type == nullptr) { - return lb_const_nil(m, original_type); + if (cl->elems.count == 0) { + if (cl->type == nullptr) { + return lb_const_nil(m, original_type); + } + if (are_types_identical(type_of_expr(cl->type), original_type)) { + return lb_const_nil(m, original_type); + } } } + if (value_type == t_untyped_nil) { + return lb_const_nil(m, original_type); + } + Type *t = bt->Union.variants[0]; lbValue cv = lb_const_value(m, t, value, cc); GB_ASSERT(LLVMIsConstant(cv.value)); @@ -736,6 +744,8 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb } else if (value.kind == ExactValue_Invalid) { return lb_const_nil(m, original_type); } + } else if (value_type == t_untyped_nil) { + return lb_const_nil(m, original_type); } GB_ASSERT_MSG(value_type != nullptr, "%s :: %s", type_to_string(original_type), exact_value_to_string(value)); @@ -792,13 +802,21 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, lb if (value.kind == ExactValue_Procedure) { lbValue res = {}; - Ast *expr = unparen_expr(value.value_procedure); - GB_ASSERT(expr != nullptr); - if (expr->kind == Ast_ProcLit) { - res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); - } else { + for (;;) { + Ast *expr = unparen_expr(value.value_procedure); + GB_ASSERT(expr != nullptr); + if (expr->kind == Ast_ProcLit) { + res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr); + break; + } Entity *e = entity_from_expr(expr); - res = lb_find_procedure_value_from_entity(m, e); + GB_ASSERT(e != nullptr); + if (e->kind != Entity_Constant) { + res = lb_find_procedure_value_from_entity(m, e); + break; + } + value = e->Constant.value; + GB_ASSERT(value.kind == ExactValue_Procedure); } if (res.value == nullptr) { // This is an unspecialized polymorphic procedure, return nil or dummy value diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 3372165f2..187aebf7c 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -704,7 +704,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Basic_uintptr: return lb_debug_type_basic_type(m, str_lit("uintptr"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned); case Basic_typeid: - return lb_debug_type_basic_type(m, str_lit("typeid"), ptr_bits, LLVMDWARFTypeEncoding_Unsigned); + return lb_debug_type_basic_type(m, str_lit("typeid"), 64, LLVMDWARFTypeEncoding_Unsigned); // Endian Specific Types case Basic_i16le: return lb_debug_type_basic_type(m, str_lit("i16le"), 16, LLVMDWARFTypeEncoding_Signed, LLVMDIFlagLittleEndian); @@ -820,8 +820,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { { LLVMMetadataRef elements[2] = {}; elements[0] = lb_debug_struct_field(m, str_lit("data"), t_rawptr, 0); - elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, ptr_bits); - return lb_debug_basic_struct(m, str_lit("any"), 2*ptr_bits, ptr_bits, elements, gb_count_of(elements)); + elements[1] = lb_debug_struct_field(m, str_lit("id"), t_typeid, 64); + return lb_debug_basic_struct(m, str_lit("any"), 128, 64, elements, gb_count_of(elements)); } // Untyped types diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 187c34595..d5658b9d5 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -634,7 +634,7 @@ gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) } -gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) { +gb_internal lbValue lb_emit_matrix_transpose(lbProcedure *p, lbValue m, Type *type) { if (is_type_array(m.type)) { i32 rank = type_math_rank(m.type); if (rank == 2) { @@ -664,7 +664,12 @@ gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *typ Type *mt = base_type(m.type); GB_ASSERT(mt->kind == Type_Matrix); - if (lb_is_matrix_simdable(mt)) { + Type *rt = base_type(type); + if (rt->kind == Type_Matrix && rt->Matrix.is_row_major != mt->Matrix.is_row_major) { + GB_PANIC("TODO: transpose with changing layout"); + } + + if (lb_is_matrix_simdable(mt) && lb_is_matrix_simdable(type)) { unsigned stride = cast(unsigned)matrix_type_stride_in_elems(mt); unsigned row_count = cast(unsigned)mt->Matrix.row_count; unsigned column_count = cast(unsigned)mt->Matrix.column_count; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 890556a61..10e10564e 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -2681,7 +2681,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu case BuiltinProc_transpose: { lbValue m = lb_build_expr(p, ce->args[0]); - return lb_emit_matrix_tranpose(p, m, tv.type); + return lb_emit_matrix_transpose(p, m, tv.type); } case BuiltinProc_outer_product: diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index f247fa2a7..3dbcea4fb 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2178,11 +2178,14 @@ gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) { LLVMSetLinkage(var_global_ref, LLVMInternalLinkage); } - LLVMValueRef vals[2] = { - lb_emit_conv(p, var_global.addr, t_rawptr).value, - lb_typeid(p->module, var_type).value, - }; - LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals, gb_count_of(vals)); + auto vals = array_make<LLVMValueRef>(temporary_allocator(), 0, 3); + array_add(&vals, lb_emit_conv(p, var_global.addr, t_rawptr).value); + if (build_context.metrics.ptr_size == 4) { + array_add(&vals, LLVMConstNull(lb_type_padding_filler(p->module, 4, 4))); + } + array_add(&vals, lb_typeid(p->module, var_type).value); + + LLVMValueRef init = llvm_const_named_struct(p->module, e->type, vals.data, vals.count); LLVMSetInitializer(global, init); } else { LLVMSetInitializer(global, value.value); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 7d412eb15..382304a4e 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -181,15 +181,9 @@ gb_internal LLVMTypeRef *lb_setup_modified_types_for_type_info(lbModule *m, isiz stypes[0] = lb_type(m, tibt->Struct.fields[0]->type); stypes[1] = lb_type(m, tibt->Struct.fields[1]->type); stypes[2] = lb_type(m, tibt->Struct.fields[2]->type); - isize variant_index = 0; - if (build_context.ptr_size == 8) { - stypes[3] = lb_type(m, t_i32); // padding - stypes[4] = lb_type(m, tibt->Struct.fields[3]->type); - variant_index = 5; - } else { - stypes[3] = lb_type(m, tibt->Struct.fields[3]->type); - variant_index = 4; - } + stypes[3] = lb_type(m, t_i32); // padding + stypes[4] = lb_type(m, tibt->Struct.fields[3]->type); + isize variant_index = 5; LLVMTypeRef *modified_types = gb_alloc_array(heap_allocator(), LLVMTypeRef, Typeid__COUNT); GB_ASSERT(Typeid__COUNT == ut->Union.variants.count); @@ -360,16 +354,9 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ small_const_values[0] = LLVMConstInt(lb_type(m, t_int), size, true); small_const_values[1] = LLVMConstInt(lb_type(m, t_int), align, true); small_const_values[2] = type_info_flags.value; - - unsigned variant_index = 0; - if (build_context.ptr_size == 8) { - small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3)); - small_const_values[4] = id.value; - variant_index = 5; - } else { - small_const_values[3] = id.value; - variant_index = 4; - } + small_const_values[3] = LLVMConstNull(LLVMStructGetTypeAtIndex(stype, 3)); + small_const_values[4] = id.value; + unsigned variant_index = 5; LLVMTypeRef full_variant_type = LLVMStructGetTypeAtIndex(stype, variant_index); unsigned full_variant_elem_count = LLVMCountStructElementTypes(full_variant_type); @@ -830,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/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index c7b4170e9..33ad2ee8d 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -1005,6 +1005,7 @@ gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) { switch (index) { case 0: return 0; // data case 1: return 2; // id + default: GB_PANIC("index > 1"); } } else if (build_context.ptr_size != build_context.int_size) { switch (t->kind) { @@ -1203,6 +1204,7 @@ gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) { switch (index) { case 0: result_type = t_rawptr; break; case 1: result_type = t_typeid; break; + default: GB_PANIC("index > 1"); } } else if (is_type_dynamic_array(t)) { switch (index) { diff --git a/src/main.cpp b/src/main.cpp index 83e7d688c..544cd54bb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1309,23 +1309,17 @@ gb_internal bool parse_build_flags(Array<String> args) { build_context.vet_flags |= VetFlag_All; break; - case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break; - case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break; - case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; - case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; - case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; - case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; - case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; - case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; - case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; - case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; - case BuildFlag_VetUnusedProcedures: - build_context.vet_flags |= VetFlag_UnusedProcedures; - if (!set_flags[BuildFlag_VetPackages]) { - gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name)); - bad_flags = true; - } - break; + case BuildFlag_VetUnusedVariables: build_context.vet_flags |= VetFlag_UnusedVariables; break; + case BuildFlag_VetUnusedImports: build_context.vet_flags |= VetFlag_UnusedImports; break; + case BuildFlag_VetUnused: build_context.vet_flags |= VetFlag_Unused; break; + case BuildFlag_VetShadowing: build_context.vet_flags |= VetFlag_Shadowing; break; + case BuildFlag_VetUsingStmt: build_context.vet_flags |= VetFlag_UsingStmt; break; + case BuildFlag_VetUsingParam: build_context.vet_flags |= VetFlag_UsingParam; break; + case BuildFlag_VetStyle: build_context.vet_flags |= VetFlag_Style; break; + case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; + case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; + case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetUnusedProcedures: build_context.vet_flags |= VetFlag_UnusedProcedures; break; case BuildFlag_VetPackages: { @@ -1788,6 +1782,11 @@ gb_internal bool parse_build_flags(Array<String> args) { } } + if (set_flags[BuildFlag_VetUnusedProcedures] && !set_flags[BuildFlag_VetPackages]) { + gb_printf_err("-vet-unused-procedures must be used with -vet-packages\n"); + bad_flags = true; + } + if ((!(build_context.export_timings_format == TimingsExportUnspecified)) && (build_context.export_timings_file.len == 0)) { gb_printf_err("`-export-timings:<format>` requires `-export-timings-file:<filename>` to be specified as well\n"); bad_flags = true; @@ -2681,7 +2680,6 @@ gb_internal int print_show_help(String const arg0, String command, String option print_usage_line(3, "-integer-division-by-zero:trap Trap on division/modulo/remainder by zero"); print_usage_line(3, "-integer-division-by-zero:zero x/0 == 0 and x%%0 == x and x%%%%0 == x"); print_usage_line(3, "-integer-division-by-zero:self x/0 == x and x%%0 == 0 and x%%%%0 == 0"); - print_usage_line(3, "-integer-division-by-zero:all-bits x/0 == ~T(0) and x%%0 == x and x%%%%0 == x"); } } diff --git a/src/name_canonicalization.cpp b/src/name_canonicalization.cpp index 8bacfabc6..f1dccb182 100644 --- a/src/name_canonicalization.cpp +++ b/src/name_canonicalization.cpp @@ -242,9 +242,146 @@ gb_internal gb_inline void type_set_clear(TypeSet *s) { typedef TYPE_WRITER_PROC(TypeWriterProc); +enum { SIP_BLOCK_SIZE = 8 }; + +struct SipHashContext { + u64 v0, v1, v2, v3; // State values + u64 k0, k1; // Split key + isize c_rounds; // Number of message rounds + isize d_rounds; // Number of finalization rounds + u8 buf[SIP_BLOCK_SIZE]; // Provided data + isize last_block; // offset from last block + isize total_length; + bool is_initialized; +}; + +struct TypeidHashContext { + SipHashContext sip; +}; + + +void typeid_hash_context_init(TypeidHashContext *hash_ctx) { + SipHashContext *sip = &hash_ctx->sip; + sip->c_rounds = 2; + sip->d_rounds = 4; + + // some random numbers to act as the seed + sip->k0 = 0xa6592ea25e04ac3cull; + sip->k1 = 0xba3cba04ed28a9aeull; + + // + sip->v0 = 0x736f6d6570736575 ^ sip->k0; + sip->v1 = 0x646f72616e646f6d ^ sip->k1; + sip->v2 = 0x6c7967656e657261 ^ sip->k0; + sip->v3 = 0x7465646279746573 ^ sip->k1; + + sip->last_block = 0; + sip->total_length = 0; + + sip->is_initialized = true; +} + +u64 rotate_left64(u64 x, u64 k) { + static u64 const n = 64; + u64 s = k & (n-1); + return (x<<s) | (x>>(n-2)); +} + +void sip_compress(SipHashContext *sip) { + sip->v0 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 13); + sip->v1 ^= sip->v0; + sip->v0 = rotate_left64(sip->v0, 32); + sip->v2 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 16); + sip->v3 ^= sip->v2; + sip->v0 += sip->v3; + sip->v3 = rotate_left64(sip->v3, 21); + sip->v3 ^= sip->v0; + sip->v2 += sip->v1; + sip->v1 = rotate_left64(sip->v1, 17); + sip->v1 ^= sip->v2; + sip->v2 = rotate_left64(sip->v2, 32); +} + +void sip_block(SipHashContext *sip, void const *ptr, isize len) { + u8 const *data = cast(u8 const *)ptr; + while (len >= SIP_BLOCK_SIZE) { + u64 m = 0; + gb_memcopy(&m, data, 8); + + sip->v3 ^= m; + + for (isize i = 0; i < sip->c_rounds; i++) { + sip_compress(sip); + } + + sip->v0 ^= m; + + data += SIP_BLOCK_SIZE; + len -= SIP_BLOCK_SIZE; + } +} + +void typeid_hash_context_update(TypeidHashContext *ctx, void const *ptr, isize len) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 const *data = cast(u8 const *)ptr; + sip->total_length += len; + if (sip->last_block > 0) { + isize n = gb_min(SIP_BLOCK_SIZE - sip->last_block, len); + gb_memcopy(sip->buf + sip->last_block, data, n); + sip->last_block += n; + if (sip->last_block == SIP_BLOCK_SIZE) { + sip_block(sip, sip->buf, SIP_BLOCK_SIZE); + sip->last_block = 0; + } + data += n; + len -= n; + } + + if (len >= SIP_BLOCK_SIZE) { + isize n = len & ~(SIP_BLOCK_SIZE-1); + sip_block(sip, data, n); + data += n; + len -= n; + } + if (len > 0) { + isize n = gb_min(SIP_BLOCK_SIZE, len); + gb_memcopy(sip->buf, data, n); + sip->last_block = n; + } +} + +u64 typeid_hash_context_fini(TypeidHashContext *ctx) { + GB_ASSERT(ctx->sip.is_initialized); + SipHashContext *sip = &ctx->sip; + + u8 tmp[SIP_BLOCK_SIZE] = {}; + gb_memcopy(tmp, sip->buf, gb_min(sip->last_block, SIP_BLOCK_SIZE)); + tmp[7] = u8(sip->total_length & 0xff); + sip_block(sip, tmp, SIP_BLOCK_SIZE); + + sip->v2 ^= 0xff; + + for (isize i = 0; i < sip->d_rounds; i++) { + sip_compress(sip); + } + + u64 res = sip->v0 ^ sip->v1 ^ sip->v2 ^ sip->v3; + + *sip = {}; + + return res ? res : 1; +} + + + struct TypeWriter { - TypeWriterProc *proc; - void *user_data; + TypeWriterProc * proc; + void * user_data; + TypeidHashContext hash_ctx; }; bool type_writer_append(TypeWriter *w, void const *ptr, isize len) { @@ -289,13 +426,14 @@ void type_writer_destroy_string(TypeWriter *w) { TYPE_WRITER_PROC(type_writer_hasher_writer_proc) { - u64 *seed = cast(u64 *)w->user_data; - *seed = fnv64a(ptr, len, *seed); + TypeidHashContext *ctx = cast(TypeidHashContext *)w->user_data; + typeid_hash_context_update(ctx, ptr, len); return true; } -void type_writer_make_hasher(TypeWriter *w, u64 *hash) { - w->user_data = hash; +void type_writer_make_hasher(TypeWriter *w, TypeidHashContext *ctx) { + typeid_hash_context_init(ctx); + w->user_data = ctx; w->proc = type_writer_hasher_writer_proc; } @@ -378,11 +516,10 @@ gb_internal u64 type_hash_canonical_type(Type *type) { return prev_hash; } - u64 hash = fnv64a(nullptr, 0); TypeWriter w = {}; - type_writer_make_hasher(&w, &hash); + type_writer_make_hasher(&w, &w.hash_ctx); write_type_to_canonical_string(&w, type); - hash = hash ? hash : 1; + u64 hash = typeid_hash_context_fini(&w.hash_ctx); type->canonical_hash.store(hash, std::memory_order_relaxed); @@ -417,7 +554,7 @@ gb_internal gbString string_canonical_entity_name(gbAllocator allocator, Entity gb_internal void write_canonical_parent_prefix(TypeWriter *w, Entity *e) { GB_ASSERT(e != nullptr); - if (e->kind == Entity_Procedure || e->kind == Entity_TypeName) { + if (e->kind == Entity_Procedure || e->kind == Entity_TypeName || e->kind == Entity_Variable) { if (e->kind == Entity_Procedure && (e->Procedure.is_export || e->Procedure.is_foreign)) { // no prefix return; @@ -527,6 +664,11 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { } else if (s->flags & (ScopeFlag_Builtin)) { goto write_base_name; } + + if (e->kind == Entity_TypeName) { + goto write_base_name; + } + gb_printf_err("%s WEIRD ENTITY TYPE %s %u %p\n", token_pos_to_string(e->token.pos), type_to_string(e->type), s->flags, s->decl_info); auto const print_scope_flags = [](Scope *s) { @@ -543,7 +685,7 @@ gb_internal void write_canonical_entity_name(TypeWriter *w, Entity *e) { }; print_scope_flags(s); - GB_PANIC("weird entity %.*s", LIT(e->token.string)); + GB_PANIC("weird entity %.*s (%.*s)", LIT(e->token.string), LIT(entity_strings[e->kind])); } if (e->pkg != nullptr) { type_writer_append(w, e->pkg->name.text, e->pkg->name.len); @@ -744,8 +886,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); @@ -756,6 +899,14 @@ gb_internal void write_type_to_canonical_string(TypeWriter *w, Type *type) { if (i > 0) { type_writer_appendc(w, CANONICAL_FIELD_SEPARATOR); } + + if (f->flags & EntityFlags_IsSubtype) { + type_writer_appendc(w, "#subtype "); + } + + if (f->flags & EntityFlag_Using) { + type_writer_appendc(w, "using "); + } type_writer_append(w, f->token.string.text, f->token.string.len); type_writer_appendc(w, CANONICAL_TYPE_SEPARATOR); write_type_to_canonical_string(w, f->type); diff --git a/src/parser.cpp b/src/parser.cpp index 152e55f8b..06703d643 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_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); @@ -1240,7 +1240,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i result->StructType.polymorphic_params = polymorphic_params; 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,8 +2773,8 @@ 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; Ast *min_field_align = nullptr; Ast *max_field_align = nullptr; @@ -2802,6 +2802,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)); @@ -2856,11 +2861,6 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_raw_union = true; - } else if (tag.string == "no_copy") { - if (no_copy) { - syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); - } - no_copy = true; } else { syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string)); } @@ -2872,6 +2872,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 +2905,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, 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/tilde_type_info.cpp b/src/tilde_type_info.cpp index 58e8d3087..96a101376 100644 --- a/src/tilde_type_info.cpp +++ b/src/tilde_type_info.cpp @@ -783,14 +783,13 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { i64 is_packed_offset = type_offset_of(tag_type, 5); i64 is_raw_union_offset = type_offset_of(tag_type, 6); - i64 is_no_copy_offset = type_offset_of(tag_type, 7); - i64 custom_align_offset = type_offset_of(tag_type, 8); + i64 custom_align_offset = type_offset_of(tag_type, 7); - i64 equal_offset = type_offset_of(tag_type, 9); + i64 equal_offset = type_offset_of(tag_type, 8); - i64 soa_kind_offset = type_offset_of(tag_type, 10); - i64 soa_base_type_offset = type_offset_of(tag_type, 11); - i64 soa_len_offset = type_offset_of(tag_type, 12); + i64 soa_kind_offset = type_offset_of(tag_type, 9); + i64 soa_base_type_offset = type_offset_of(tag_type, 10); + i64 soa_len_offset = type_offset_of(tag_type, 11); // TODO(bill): equal proc stuff gb_unused(equal_offset); @@ -825,7 +824,6 @@ gb_internal void cg_setup_type_info_data(cgModule *m) { set_bool(m, global, offset+is_packed_offset, t->Struct.is_packed); set_bool(m, global, offset+is_raw_union_offset, t->Struct.is_raw_union); - set_bool(m, global, offset+is_no_copy_offset, t->Struct.is_no_copy); set_bool(m, global, offset+custom_align_offset, t->Struct.custom_align != 0); if (t->Struct.soa_kind != StructSoa_None) { diff --git a/src/types.cpp b/src/types.cpp index a1311ba5d..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)) { @@ -4577,6 +4579,8 @@ gb_internal i64 type_offset_of(Type *t, i64 index, Type **field_type_) { case 1: if (field_type_) *field_type_ = t_typeid; return 8; // id + default: + GB_PANIC("index > 1"); } } break; @@ -4654,6 +4658,7 @@ gb_internal i64 type_offset_of_from_selection(Type *type, Selection sel) { switch (index) { case 0: t = t_rawptr; break; case 1: t = t_typeid; break; + default: GB_PANIC("index > 1"); } } break; @@ -4919,7 +4924,7 @@ gb_internal Type *type_internal_index(Type *t, isize index) { case Type_Slice: { GB_ASSERT(index == 0 || index == 1); - return index == 0 ? t_rawptr : t_typeid; + return index == 0 ? t_rawptr : t_int; } case Type_DynamicArray: { diff --git a/src/ucg/ucg.c b/src/ucg/ucg.c index c3e270e1a..119f88805 100644 --- a/src/ucg/ucg.c +++ b/src/ucg/ucg.c @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: (c) 2024 Feoramund - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: zlib */ diff --git a/src/ucg/ucg_tables.h b/src/ucg/ucg_tables.h index a33f9f898..f31e51773 100644 --- a/src/ucg/ucg_tables.h +++ b/src/ucg/ucg_tables.h @@ -1,6 +1,6 @@ /* * SPDX-FileCopyrightText: (c) 2024 Feoramund - * SPDX-License-Identifier: BSD-3-Clause + * SPDX-License-Identifier: zlib */ #ifndef _UCG_TABLES_INCLUDED #define _UCG_TABLES_INCLUDED |