From ec5a84a5379236a2413b8f3115509629879f5b53 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Apr 2024 13:10:58 +0100 Subject: Improve code generation for loading `bit_field` fields --- src/check_type.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index a6dbb8dfc..77ac91c38 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -955,14 +955,19 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, 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.backing_type = backing_type ? backing_type : t_u8; bit_field_type->BitField.scope = ctx->scope; + if (backing_type == nullptr) { + error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer"); + return; + } + if (!is_valid_bit_field_backing_type(backing_type)) { + error(bf->backing_type, "Backing type for a bit_field must be an integer or an array of an integer"); + return; + } + auto fields = array_make(permanent_allocator(), 0, bf->fields.count); auto bit_sizes = array_make (permanent_allocator(), 0, bf->fields.count); auto tags = array_make (permanent_allocator(), 0, bf->fields.count); -- cgit v1.2.3 From 94d35d9918a8ce8b3686dba52bab3e468b46729d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 24 Apr 2024 17:28:00 +0100 Subject: Disallow mixing endian types within a `bit_field` --- src/check_type.cpp | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 77ac91c38..ab8c0b057 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1101,6 +1101,45 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, gb_string_free(s); } + enum EndianKind { + Endian_Unknown, + Endian_Native, + Endian_Little, + Endian_Big, + }; + auto const &determine_endian_kind = [](Type *type) -> EndianKind { + if (is_type_boolean(type)) { + // NOTE(bill): it doesn't matter, and when it does, + // that api is absolutely stupid + return Endian_Unknown; + } else if (is_type_endian_specific(type)) { + if (is_type_endian_little(type)) { + return Endian_Little; + } else { + return Endian_Big; + } + } + return Endian_Native; + }; + + EndianKind backing_type_endian_kind = determine_endian_kind(core_array_type(backing_type)); + EndianKind endian_kind = Endian_Unknown; + for (Entity *f : fields) { + EndianKind field_kind = determine_endian_kind(f->type); + + if (field_kind && backing_type_endian_kind != field_kind) { + error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big"); + } + + if (endian_kind == Endian_Unknown) { + endian_kind = field_kind; + } else if (field_kind && endian_kind != field_kind) { + error(f->token, "All 'bit_field' field types must be of the same endian variety, i.e. all native, all little, or all big"); + } + } + + + if (bit_sizes.count > 0 && is_type_integer(backing_type)) { bool all_booleans = is_type_boolean(fields[0]->type); bool all_ones = bit_sizes[0] == 1; -- cgit v1.2.3 From 2201f365a1676f966fff5b9a79f0f56b5c1cf7ee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 3 May 2024 14:51:02 +0100 Subject: Allow `#no_alias` on multi-pointers --- src/check_type.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index ab8c0b057..61c502a68 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2017,8 +2017,8 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } if (p->flags&FieldFlag_no_alias) { - if (!is_type_pointer(type)) { - error(name, "'#no_alias' can only be applied pointer typed parameters"); + if (!is_type_pointer(type) && !is_type_multi_pointer(type)) { + error(name, "'#no_alias' can only be applied pointer or multi-pointer typed parameters"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } } -- cgit v1.2.3 From 6ec7845249d2e77e68f2e802e3bebe5b5fc3480f Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 6 May 2024 18:27:34 -0400 Subject: Fix #3531 Individual `bit_field` size was not being added to the total size. Error message was changed to be more explicit. --- src/check_type.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 61c502a68..457375779 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1080,6 +1080,8 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, array_add(&tags, tag); add_entity_use(ctx, field, e); + + total_bit_size += bit_size_u8; } } @@ -1094,7 +1096,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, 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", + error(node, "The total bit size of a bit_field's fields (%llu) must fit into its backing type's (%s) bit size of %llu", cast(unsigned long long)total_bit_size, s, cast(unsigned long long)maximum_bit_size); -- cgit v1.2.3 From 0da6a3e214c66e2955307e2aad12d844a051f8d8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 May 2024 11:42:48 +0100 Subject: Fix #3530 --- src/check_type.cpp | 9 +++++++-- src/parser.cpp | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 457375779..6efac54d6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -797,11 +797,11 @@ gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *nam enum_type->Enum.scope = ctx->scope; Type *base_type = t_int; - if (et->base_type != nullptr) { + if (unparen_expr(et->base_type) != nullptr) { base_type = check_type(ctx, et->base_type); } - if (base_type == nullptr || !is_type_integer(base_type)) { + if (base_type == nullptr || base_type == t_invalid || !is_type_integer(base_type)) { error(node, "Base type for enumeration must be an integer"); return; } @@ -3265,6 +3265,11 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T case_end; case_ast_node(pe, ParenExpr, e); + if (pe->expr == nullptr) { + error(e, "Expected an expression or type within the parentheses"); + *type = t_invalid; + return true; + } *type = check_type_expr(ctx, pe->expr, named_type); set_base_type(named_type, *type); return true; diff --git a/src/parser.cpp b/src/parser.cpp index 2bf25c768..04505cbd7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -3499,6 +3499,10 @@ gb_internal Ast *parse_type(AstFile *f) { Token token = advance_token(f); syntax_error(token, "Expected a type"); return ast_bad_expr(f, token, f->curr_token); + } else if (type->kind == Ast_ParenExpr && + unparen_expr(type) == nullptr) { + syntax_error(type, "Expected a type within the parentheses"); + return ast_bad_expr(f, type->ParenExpr.open, type->ParenExpr.close); } return type; } -- cgit v1.2.3 From 0cec2d7827a537557555bf6c92c2f090113806a4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 May 2024 11:51:06 +0100 Subject: Fix #3527 --- src/check_type.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 6efac54d6..ea249c293 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1430,6 +1430,10 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special bool can_convert = check_cast_internal(ctx, &o, specialization); return can_convert; } else if (t->kind == Type_Struct) { + if (t->Struct.polymorphic_parent == nullptr && + t == s) { + return true; + } if (t->Struct.polymorphic_parent == specialization) { return true; } @@ -1479,6 +1483,10 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } } else if (t->kind == Type_Union) { + if (t->Union.polymorphic_parent == nullptr && + t == s) { + return true; + } if (t->Union.polymorphic_parent == specialization) { return true; } -- cgit v1.2.3 From 3f7a369aa1ff90ec1c71e6b4805778d4899790a5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 7 May 2024 14:53:02 +0100 Subject: Check for specialization in `typeid/T` for parapoly records --- src/check_type.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index ea249c293..c119ce6b5 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -381,6 +381,7 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly Type *type = nullptr; bool is_type_param = false; bool is_type_polymorphic_type = false; + Type *specialization = nullptr; if (type_expr == nullptr && default_value == nullptr) { error(param, "Expected a type for this parameter"); continue; @@ -393,7 +394,6 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly } if (type_expr->kind == Ast_TypeidType) { is_type_param = true; - Type *specialization = nullptr; if (type_expr->TypeidType.specialization != nullptr) { Ast *s = type_expr->TypeidType.specialization; specialization = check_type(ctx, s); @@ -471,6 +471,15 @@ gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *poly if (is_type_polymorphic(base_type(operand.type))) { *is_polymorphic_ = true; can_check_fields = false; + } else if (specialization && + !check_type_specialization_to(ctx, specialization, operand.type, false, /*modify_type*/true)) { + if (!ctx->no_polymorphic_errors) { + gbString t = type_to_string(operand.type); + gbString s = type_to_string(specialization); + error(operand.expr, "Cannot convert type '%s' to the specialization '%s'", t, s); + gb_string_free(s); + gb_string_free(t); + } } e = alloc_entity_type_name(scope, token, operand.type); e->TypeName.is_type_alias = true; -- cgit v1.2.3 From d85c8f0b2c5989f7d14b02c9023060990d241111 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 May 2024 10:58:57 +0100 Subject: Fix #3555 --- src/check_decl.cpp | 11 +++++++++++ src/check_type.cpp | 1 + src/entity.cpp | 1 + src/types.cpp | 4 ++++ 4 files changed, 17 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5b9486873..441c8000d 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1619,6 +1619,17 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de if (e->kind != Entity_Variable) { continue; } + if (is_type_polymorphic(e->type)) { + gbString s = type_to_string(e->type); + char const *msg = "Unspecialized polymorphic types are not allowed in procedure parameters, got %s"; + if (e->Variable.type_expr) { + error(e->Variable.type_expr, msg, s); + } else { + error(e->token, msg, s); + } + gb_string_free(s); + } + if (!(e->flags & EntityFlag_Using)) { continue; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c119ce6b5..3d11b5012 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2076,6 +2076,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para param = alloc_entity_param(scope, name->Ident.token, type, is_using, true); param->Variable.param_value = param_value; param->Variable.field_group_index = field_group_index; + param->Variable.type_expr = type_expr; } } if (p->flags&FieldFlag_no_alias) { diff --git a/src/entity.cpp b/src/entity.cpp index d76d5f441..60ca208ec 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -210,6 +210,7 @@ struct Entity { CommentGroup *comment; } Constant; struct { + Ast *type_expr; // only used for some variables within procedure bodies Ast *init_expr; // only used for some variables within procedure bodies i32 field_index; i32 field_group_index; diff --git a/src/types.cpp b/src/types.cpp index 3ec05059f..30e009086 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -3267,6 +3267,10 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name } } + if (is_type_polymorphic(type)) { + // NOTE(bill): A polymorphic struct has no fields, this only hits in the case of an error + return sel; + } wait_signal_until_available(&type->Struct.fields_wait_signal); isize field_count = type->Struct.fields.count; if (field_count != 0) for_array(i, type->Struct.fields) { -- cgit v1.2.3 From f54977336b27c32eab52b77d94e7b1610f4350cf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 9 May 2024 15:56:00 +0100 Subject: With `-vet-style`, give suggestion of separating where clauses with a comma rather than '&&' This improves the error messages --- src/check_expr.cpp | 14 ++++++++++++++ src/check_type.cpp | 2 +- src/parser.cpp | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 013638e63..98aebfe4e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6193,6 +6193,20 @@ gb_internal bool evaluate_where_clauses(CheckerContext *ctx, Ast *call_expr, Sco } return false; } + + if (ast_file_vet_style(ctx->file)) { + Ast *c = unparen_expr(clause); + if (c->kind == Ast_BinaryExpr && c->BinaryExpr.op.kind == Token_CmpAnd) { + ERROR_BLOCK(); + error(c, "Prefer to separate 'where' clauses with a comma rather than '&&'"); + gbString x = expr_to_string(c->BinaryExpr.left); + gbString y = expr_to_string(c->BinaryExpr.right); + error_line("\tSuggestion: '%s, %s'", x, y); + gb_string_free(y); + gb_string_free(x); + } + } + } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 3d11b5012..11e332757 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1166,7 +1166,7 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, } } if (all_ones && all_booleans) { - if (build_context.vet_flags & VetFlag_Style) { + if (ast_file_vet_style(ctx->file)) { char const *msg = "This 'bit_field' is better expressed as a 'bit_set' since all of the fields are booleans, of 1-bit in size, and the backing type is an integer (-vet-style)"; error(node, msg); } else { diff --git a/src/parser.cpp b/src/parser.cpp index 04505cbd7..6e859fe32 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,7 +1,7 @@ #include "parser_pos.cpp" gb_internal u64 ast_file_vet_flags(AstFile *f) { - if (f->vet_flags_set) { + if (f != nullptr && f->vet_flags_set) { return f->vet_flags; } return build_context.vet_flags; -- cgit v1.2.3 From aea28d5189848746725707d595155726b6b94ea0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 May 2024 13:47:33 +0100 Subject: Allow edge-case where backing type of a `bit_field` is (array of) `u8`, to allow any endian type --- src/check_type.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 11e332757..6fe87c2c7 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1133,12 +1133,13 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, return Endian_Native; }; - EndianKind backing_type_endian_kind = determine_endian_kind(core_array_type(backing_type)); + Type *backing_type_elem = core_array_type(backing_type); + EndianKind backing_type_endian_kind = determine_endian_kind(backing_type_elem); EndianKind endian_kind = Endian_Unknown; for (Entity *f : fields) { EndianKind field_kind = determine_endian_kind(f->type); - if (field_kind && backing_type_endian_kind != field_kind) { + if (field_kind && backing_type_endian_kind != field_kind && backing_type_elem != t_u8) { error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big"); } -- cgit v1.2.3 From 811d53b305643607f25718437336c74dffdccb6b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 May 2024 13:48:19 +0100 Subject: Generalize to any 1-byte element in `bit_field` --- src/check_type.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 6fe87c2c7..88aa4ca1e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1134,12 +1134,13 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, }; Type *backing_type_elem = core_array_type(backing_type); + i64 backing_type_elem_size = type_size_of(backing_type_elem); EndianKind backing_type_endian_kind = determine_endian_kind(backing_type_elem); EndianKind endian_kind = Endian_Unknown; for (Entity *f : fields) { EndianKind field_kind = determine_endian_kind(f->type); - if (field_kind && backing_type_endian_kind != field_kind && backing_type_elem != t_u8) { + if (field_kind && backing_type_endian_kind != field_kind && backing_type_elem_size > 1) { error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big"); } -- cgit v1.2.3 From 6bfaf4a093fc566c38e97c5c7b80b9586ddf41e9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 11 May 2024 22:36:17 +0100 Subject: Fix another oversight for `bit_field` endian with 1-byte types --- src/check_type.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 88aa4ca1e..4df0c5d19 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1139,14 +1139,15 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, EndianKind endian_kind = Endian_Unknown; for (Entity *f : fields) { EndianKind field_kind = determine_endian_kind(f->type); + i64 field_size = type_size_of(f->type); - if (field_kind && backing_type_endian_kind != field_kind && backing_type_elem_size > 1) { + if (field_kind && backing_type_endian_kind != field_kind && field_size > 1 && backing_type_elem_size > 1) { error(f->token, "All 'bit_field' field types must match the same endian kind as the backing type, i.e. all native, all little, or all big"); } if (endian_kind == Endian_Unknown) { endian_kind = field_kind; - } else if (field_kind && endian_kind != field_kind) { + } else if (field_kind && endian_kind != field_kind && field_size > 1) { error(f->token, "All 'bit_field' field types must be of the same endian variety, i.e. all native, all little, or all big"); } } -- cgit v1.2.3 From 7905f0533f3fbbffec262a97b083d6aae450e46b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 May 2024 12:01:16 +0100 Subject: Fix #3582 by disallowing it --- src/check_type.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 4df0c5d19..8d3c28f06 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -191,9 +191,10 @@ gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slicenames.count > 0) { Type *first_type = fields_array[fields_array.count-1]->type; + bool soa_ptr = is_type_soa_pointer(first_type); Type *t = base_type(type_deref(first_type)); - if (!does_field_type_allow_using(t) && + if ((soa_ptr || !does_field_type_allow_using(t)) && p->names.count >= 1 && p->names[0]->kind == Ast_Ident) { Token name_token = p->names[0]->Ident.token; -- cgit v1.2.3 From 8fa20fb875849774942117af3a23cb676a3fd8d7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 13 May 2024 14:44:53 +0100 Subject: Extra check for `field` being `nullptr` --- src/check_type.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 8d3c28f06..c209a8e09 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -19,10 +19,12 @@ gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstF } } else { Token tok = make_token_ident(name); - if (field->names.count > 0) { - tok.pos = ast_token(field->names[0]).pos; - } else { - tok.pos = ast_token(field->type).pos; + if (field) { + if (field->names.count > 0) { + tok.pos = ast_token(field->names[0]).pos; + } else { + tok.pos = ast_token(field->type).pos; + } } Entity *f = alloc_entity_array_elem(nullptr, tok, t->Array.elem, idx); add_entity(ctx, ctx->scope, nullptr, f); -- cgit v1.2.3 From 32245e93a106c5cb1ee9b448789f623a4dbef717 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 16 May 2024 16:18:21 +0100 Subject: Fix #3514 along with `soa.a[i]` bounds checking --- src/check_expr.cpp | 4 ++-- src/check_type.cpp | 15 ++++++++++--- src/llvm_backend_expr.cpp | 50 +++++++++++++++++++++++++++++++------------- src/llvm_backend_general.cpp | 2 +- 4 files changed, 50 insertions(+), 21 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index c44232dab..c9cfb58be 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7806,8 +7806,8 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 if (is_type_pointer(original_type) && indirection) { Type *ptr = base_type(original_type); - if (ptr->kind == Type_Pointer && o->mode == Addressing_SoaVariable) { - o->type = ptr->Pointer.elem; + if (ptr->kind == Type_MultiPointer && o->mode == Addressing_SoaVariable) { + o->type = ptr->MultiPointer.elem; o->mode = Addressing_Value; return true; } diff --git a/src/check_type.cpp b/src/check_type.cpp index c209a8e09..9381443fc 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2827,12 +2827,15 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis GB_ASSERT(soa_count >= 0); field_type = alloc_type_array(old_field->type, soa_count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); t->Struct.fields[i] = new_field; add_entity(scope, new_field); new_field->flags |= EntityFlag_Used; + if (t->Struct.soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { t->Struct.fields[i] = old_field; } @@ -2948,7 +2951,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_array->Array.elem, count); } else { - field_type = alloc_type_pointer(old_array->Array.elem); + field_type = alloc_type_multi_pointer(old_array->Array.elem); } Token token = {}; token.string = params_xyzw[i]; @@ -2957,6 +2960,9 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } is_complete = true; @@ -2980,12 +2986,15 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e GB_ASSERT(count >= 0); field_type = alloc_type_array(old_field->type, count); } else { - field_type = alloc_type_pointer(old_field->type); + field_type = alloc_type_multi_pointer(old_field->type); } Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index); soa_struct->Struct.fields[i] = new_field; add_entity(ctx, scope, nullptr, new_field); add_entity_use(ctx, nullptr, new_field); + if (soa_kind != StructSoa_Fixed) { + new_field->flags |= EntityFlag_SoaPtrField; + } } else { soa_struct->Struct.fields[i] = old_field; } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index 899b74e56..934f59d9a 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3851,27 +3851,39 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) { if (ie->expr->tav.mode == Addressing_SoaVariable) { // SOA Structures for slices/dynamic arrays - GB_ASSERT(is_type_pointer(type_of_expr(ie->expr))); + GB_ASSERT_MSG(is_type_multi_pointer(type_of_expr(ie->expr)), "%s", type_to_string(type_of_expr(ie->expr))); lbValue field = lb_build_expr(p, ie->expr); lbValue index = lb_build_expr(p, ie->index); - if (!build_context.no_bounds_check) { - // TODO HACK(bill): Clean up this hack to get the length for bounds checking - // GB_ASSERT(LLVMIsALoadInst(field.value)); - - // lbValue a = {}; - // a.value = LLVMGetOperand(field.value, 0); - // a.type = alloc_type_pointer(field.type); - - // irInstr *b = &a->Instr; - // GB_ASSERT(b->kind == irInstr_StructElementPtr); - // lbValue base_struct = b->StructElementPtr.address; + Ast *se_expr = unparen_expr(ie->expr); + if (se_expr->kind == Ast_SelectorExpr) { + ast_node(se, SelectorExpr, se_expr); + lbValue len = {}; + + Type *type = base_type(type_deref(type_of_expr(se->expr))); + GB_ASSERT_MSG(is_type_soa_struct(type), "%s", type_to_string(type)); + if (type->Struct.soa_kind == StructSoa_Fixed) { + len = lb_const_int(p->module, t_int, type->Struct.soa_count); + } else { + lbAddr *found = map_get(&p->selector_addr, se_expr); + if (found) { + lbAddr addr = *found; + lbValue parent = lb_addr_get_ptr(p, addr); + if (is_type_pointer(type_deref(parent.type))) { + parent = lb_emit_load(p, parent); + } + len = lb_soa_struct_len(p, parent); + } + } - // GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct)))); - // lbValue len = ir_soa_struct_len(p, base_struct); - // lb_emit_bounds_check(p, ast_token(ie->index), index, len); + if (len.value) { + lb_emit_bounds_check(p, ast_token(ie->index), index, len); + } + } else { + // TODO(bill): how do you even do bounds checking here? + } } lbValue val = lb_emit_ptr_offset(p, field, index); return lb_addr(val); @@ -4218,6 +4230,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i); field_src = lb_emit_array_ep(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4233,6 +4246,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4247,6 +4261,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) { lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i); lbValue field_src = lb_emit_struct_ev(p, base, i); field_src = lb_emit_ptr_offset(p, field_src, low); + field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type)); lb_emit_store(p, field_dst, field_src); } @@ -4989,6 +5004,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) { sel.index[0] = addr.swizzle.indices[sel.index[0]]; } + Type *atype = type_deref(lb_addr_type(addr)); + if (is_type_soa_struct(atype)) { + map_set(&p->selector_addr, expr, addr); + } + lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); return lb_addr(a); diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 3c1a7ee7f..e8183027f 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1324,7 +1324,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { for (isize i = 0; i < field_count; i++) { Entity *field = t->Struct.fields[i]; Type *base_type = field->type; - GB_ASSERT(base_type->kind == Type_Pointer); + GB_ASSERT(base_type->kind == Type_MultiPointer); lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i); lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i); -- cgit v1.2.3 From 64bdb3a09770b96afccd3b375b5c91214e97415b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 26 May 2024 12:17:03 +0100 Subject: Fix #3630 (first part) --- src/check_expr.cpp | 2 +- src/check_type.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 5d4d6c73b..8672941c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1805,7 +1805,7 @@ gb_internal Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *nam case Entity_ImportName: if (!allow_import_name) { - error(n, "Use of import '%.*s' not in selector", LIT(name)); + error(n, "Use of import name '%.*s' not in the form of 'x.y'", LIT(name)); } return e; case Entity_LibraryName: diff --git a/src/check_type.cpp b/src/check_type.cpp index 9381443fc..7ed657bee 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1595,7 +1595,7 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { return is_expr_from_a_parameter(ctx, lhs); } else if (expr->kind == Ast_Ident) { Operand x= {}; - Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, false); + Entity *e = check_ident(ctx, &x, expr, nullptr, nullptr, true); if (e->flags & EntityFlag_Param) { return true; } -- cgit v1.2.3 From 7044a7d77650e922a66f3bfe99711f3ed370e1ba Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 6 Jun 2024 23:55:48 +0100 Subject: Try to fix a possible race condition with polymorphic record parameters --- src/check_builtin.cpp | 31 ++++++++----------------------- src/check_expr.cpp | 11 +++-------- src/check_type.cpp | 30 +++++++++++++----------------- src/checker.cpp | 4 ++++ src/types.cpp | 18 ++++++++++++++++++ 5 files changed, 46 insertions(+), 48 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 7e3bcb7ee..eef925d94 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5912,15 +5912,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (operand->mode != Addressing_Type) { error(operand->expr, "Expected a record type for '%.*s'", LIT(builtin_name)); } else { - Type *bt = base_type(operand->type); - if (bt->kind == Type_Struct) { - if (bt->Struct.polymorphic_params != nullptr) { - operand->value = exact_value_i64(bt->Struct.polymorphic_params->Tuple.variables.count); - } - } else if (bt->kind == Type_Union) { - if (bt->Union.polymorphic_params != nullptr) { - operand->value = exact_value_i64(bt->Union.polymorphic_params->Tuple.variables.count); - } + TypeTuple *tuple = get_record_polymorphic_params(operand->type); + if (tuple) { + operand->value = exact_value_i64(tuple->variables.count); } else { error(operand->expr, "Expected a record type for '%.*s'", LIT(builtin_name)); } @@ -5952,20 +5946,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As Entity *param = nullptr; i64 count = 0; - Type *bt = base_type(operand->type); - if (bt->kind == Type_Struct) { - if (bt->Struct.polymorphic_params != nullptr) { - count = bt->Struct.polymorphic_params->Tuple.variables.count; - if (index < count) { - param = bt->Struct.polymorphic_params->Tuple.variables[cast(isize)index]; - } - } - } else if (bt->kind == Type_Union) { - if (bt->Union.polymorphic_params != nullptr) { - count = bt->Union.polymorphic_params->Tuple.variables.count; - if (index < count) { - param = bt->Union.polymorphic_params->Tuple.variables[cast(isize)index]; - } + TypeTuple *tuple = get_record_polymorphic_params(operand->type); + if (tuple) { + count = tuple->variables.count; + if (index < count) { + param = tuple->variables[cast(isize)index]; } } else { error(operand->expr, "Expected a specialized polymorphic record type for '%.*s'", LIT(builtin_name)); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index d2d01deda..ad546858c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7331,14 +7331,9 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O gbString s = gb_string_make_reserve(heap_allocator(), e->token.string.len+3); s = gb_string_append_fmt(s, "%.*s(", LIT(e->token.string)); - Type *params = nullptr; - switch (bt->kind) { - case Type_Struct: params = bt->Struct.polymorphic_params; break; - case Type_Union: params = bt->Union.polymorphic_params; break; - } - - if (params != nullptr) for_array(i, params->Tuple.variables) { - Entity *v = params->Tuple.variables[i]; + TypeTuple *tuple = get_record_polymorphic_params(e->type); + if (tuple != nullptr) for_array(i, tuple->variables) { + Entity *v = tuple->variables[i]; String name = v->token.string; if (i > 0) { s = gb_string_append_fmt(s, ", "); diff --git a/src/check_type.cpp b/src/check_type.cpp index 7ed657bee..e0dea19cb 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -564,19 +564,7 @@ gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, T gb_internal Entity *find_polymorphic_record_entity(GenTypesData *found_gen_types, isize param_count, Array const &ordered_operands) { for (Entity *e : found_gen_types->types) { Type *t = base_type(e->type); - TypeTuple *tuple = nullptr; - switch (t->kind) { - case Type_Struct: - if (t->Struct.polymorphic_params) { - tuple = &t->Struct.polymorphic_params->Tuple; - } - break; - case Type_Union: - if (t->Union.polymorphic_params) { - tuple = &t->Union.polymorphic_params->Tuple; - } - break; - } + TypeTuple *tuple = get_record_polymorphic_params(t); GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t)); GB_ASSERT(param_count == tuple->variables.count); @@ -663,6 +651,8 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * &struct_type->Struct.is_polymorphic, node, poly_operands ); + wait_signal_set(&struct_type->Struct.polymorphic_wait_signal); + struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &struct_type->Struct.is_polymorphic); if (original_type_for_poly) { GB_ASSERT(named_type != nullptr); @@ -712,6 +702,8 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no &union_type->Union.is_polymorphic, node, poly_operands ); + wait_signal_set(&union_type->Union.polymorphic_wait_signal); + union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &union_type->Union.is_polymorphic); if (original_type_for_poly) { GB_ASSERT(named_type != nullptr); @@ -1453,12 +1445,14 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } + wait_for_record_polymorphic_params(s); + wait_for_record_polymorphic_params(t); if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent && s->Struct.polymorphic_params != nullptr && t->Struct.polymorphic_params != nullptr) { - TypeTuple *s_tuple = &s->Struct.polymorphic_params->Tuple; - TypeTuple *t_tuple = &t->Struct.polymorphic_params->Tuple; + TypeTuple *s_tuple = get_record_polymorphic_params(s); + TypeTuple *t_tuple = get_record_polymorphic_params(t); GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count); for_array(i, s_tuple->variables) { Entity *s_e = s_tuple->variables[i]; @@ -1506,12 +1500,14 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } + wait_for_record_polymorphic_params(s); + wait_for_record_polymorphic_params(t); if (t->Union.polymorphic_parent == s->Union.polymorphic_parent && s->Union.polymorphic_params != nullptr && t->Union.polymorphic_params != nullptr) { - TypeTuple *s_tuple = &s->Union.polymorphic_params->Tuple; - TypeTuple *t_tuple = &t->Union.polymorphic_params->Tuple; + TypeTuple *s_tuple = get_record_polymorphic_params(s); + TypeTuple *t_tuple = get_record_polymorphic_params(t); GB_ASSERT(t_tuple->variables.count == s_tuple->variables.count); for_array(i, s_tuple->variables) { Entity *s_e = s_tuple->variables[i]; diff --git a/src/checker.cpp b/src/checker.cpp index 8a58bb425..e90509c1f 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2031,6 +2031,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } else { add_type_info_type_internal(c, t_type_info_ptr); } + wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_type_info_type_internal(c, bt->Union.variants[i]); @@ -2063,6 +2064,7 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } } } + wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; @@ -2292,6 +2294,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } else { add_min_dep_type_info(c, t_type_info_ptr); } + wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_min_dep_type_info(c, bt->Union.variants[i]); @@ -2321,6 +2324,7 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } } } + wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; diff --git a/src/types.cpp b/src/types.cpp index 45aa26894..4ceba5244 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -140,6 +140,7 @@ struct TypeStruct { i64 custom_field_align; Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; + Wait_Signal polymorphic_wait_signal; Type * soa_elem; i32 soa_count; @@ -167,6 +168,7 @@ struct TypeUnion { i64 custom_align; Type * polymorphic_params; // Type_Tuple Type * polymorphic_parent; + Wait_Signal polymorphic_wait_signal; i16 tag_size; bool is_polymorphic; @@ -1093,6 +1095,7 @@ gb_internal Type *alloc_type_struct() { gb_internal Type *alloc_type_struct_complete() { Type *t = alloc_type(Type_Struct); wait_signal_set(&t->Struct.fields_wait_signal); + wait_signal_set(&t->Struct.polymorphic_wait_signal); return t; } @@ -2136,15 +2139,30 @@ gb_internal bool is_type_polymorphic_record_unspecialized(Type *t) { return false; } +gb_internal void wait_for_record_polymorphic_params(Type *t) { + t = base_type(t); + switch (t->kind) { + case Type_Struct: + wait_signal_until_available(&t->Struct.polymorphic_wait_signal); + break; + case Type_Union: + wait_signal_until_available(&t->Union.polymorphic_wait_signal); + break; + } +} + + gb_internal TypeTuple *get_record_polymorphic_params(Type *t) { t = base_type(t); switch (t->kind) { case Type_Struct: + wait_signal_until_available(&t->Struct.polymorphic_wait_signal); if (t->Struct.polymorphic_params) { return &t->Struct.polymorphic_params->Tuple; } break; case Type_Union: + wait_signal_until_available(&t->Union.polymorphic_wait_signal); if (t->Union.polymorphic_params) { return &t->Union.polymorphic_params->Tuple; } -- cgit v1.2.3 From 68781f8dd365692aee55099d3e14cb83a115764c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 7 Jun 2024 00:11:00 +0100 Subject: Remove unnecessary Wait_Signal checks --- src/check_type.cpp | 4 ---- src/checker.cpp | 4 ---- src/types.cpp | 12 ------------ 3 files changed, 20 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index e0dea19cb..17f7813d5 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1445,8 +1445,6 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } - wait_for_record_polymorphic_params(s); - wait_for_record_polymorphic_params(t); if (t->Struct.polymorphic_parent == s->Struct.polymorphic_parent && s->Struct.polymorphic_params != nullptr && t->Struct.polymorphic_params != nullptr) { @@ -1500,8 +1498,6 @@ gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *special return true; } - wait_for_record_polymorphic_params(s); - wait_for_record_polymorphic_params(t); if (t->Union.polymorphic_parent == s->Union.polymorphic_parent && s->Union.polymorphic_params != nullptr && t->Union.polymorphic_params != nullptr) { diff --git a/src/checker.cpp b/src/checker.cpp index e90509c1f..8a58bb425 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -2031,7 +2031,6 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } else { add_type_info_type_internal(c, t_type_info_ptr); } - wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_type_info_type_internal(c, bt->Union.variants[i]); @@ -2064,7 +2063,6 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) { } } } - wait_for_record_polymorphic_params(bt); add_type_info_type_internal(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; @@ -2294,7 +2292,6 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } else { add_min_dep_type_info(c, t_type_info_ptr); } - wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Union.polymorphic_params); for_array(i, bt->Union.variants) { add_min_dep_type_info(c, bt->Union.variants[i]); @@ -2324,7 +2321,6 @@ gb_internal void add_min_dep_type_info(Checker *c, Type *t) { } } } - wait_for_record_polymorphic_params(bt); add_min_dep_type_info(c, bt->Struct.polymorphic_params); for_array(i, bt->Struct.fields) { Entity *f = bt->Struct.fields[i]; diff --git a/src/types.cpp b/src/types.cpp index 4ceba5244..97e8267a3 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2139,18 +2139,6 @@ gb_internal bool is_type_polymorphic_record_unspecialized(Type *t) { return false; } -gb_internal void wait_for_record_polymorphic_params(Type *t) { - t = base_type(t); - switch (t->kind) { - case Type_Struct: - wait_signal_until_available(&t->Struct.polymorphic_wait_signal); - break; - case Type_Union: - wait_signal_until_available(&t->Union.polymorphic_wait_signal); - break; - } -} - gb_internal TypeTuple *get_record_polymorphic_params(Type *t) { t = base_type(t); -- cgit v1.2.3 From 29250f2657f644e766dba09dcffdf594f54554f5 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 7 Jun 2024 16:33:38 +0200 Subject: fix regression in test_issue_2395 --- src/check_type.cpp | 2 +- tests/issues/run.sh | 5 ++--- tests/issues/test_issue_2395.odin | 2 -- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 17f7813d5..c56c8a739 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -776,7 +776,7 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no } } if (variants.count < 2) { - error(ut->align, "A union with #no_nil must have at least 2 variants"); + error(node, "A union with #no_nil must have at least 2 variants"); } break; } diff --git a/tests/issues/run.sh b/tests/issues/run.sh index e17cb4c73..20259ac63 100755 --- a/tests/issues/run.sh +++ b/tests/issues/run.sh @@ -6,8 +6,6 @@ pushd build ODIN=../../../odin COMMON="-define:ODIN_TEST_FANCY=false -file -vet -strict-style" -NO_NIL_ERR="Error: " - set -x $ODIN test ../test_issue_829.odin $COMMON @@ -18,10 +16,11 @@ $ODIN test ../test_issue_2466.odin $COMMON $ODIN test ../test_issue_2615.odin $COMMON $ODIN test ../test_issue_2637.odin $COMMON $ODIN test ../test_issue_2666.odin $COMMON -if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "$NO_NIL_ERR") -eq 2 ]] ; then +if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "must have at least 2 variants") -eq 2 ]] ; then echo "SUCCESSFUL 1/1" else echo "SUCCESSFUL 0/1" + exit 1 fi set +x diff --git a/tests/issues/test_issue_2395.odin b/tests/issues/test_issue_2395.odin index 48e1ee516..bbbcb3aea 100644 --- a/tests/issues/test_issue_2395.odin +++ b/tests/issues/test_issue_2395.odin @@ -5,8 +5,6 @@ // exactly 2 errors from the invalid unions package test_issues -import "core:testing" - ValidUnion :: union($T: typeid) #no_nil { T, f32, -- cgit v1.2.3 From ec38215842e75eeba5e10f1f8a1419b872eb6af9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 28 Jun 2024 10:09:46 +0100 Subject: Fix #3803 --- src/check_type.cpp | 8 +++++--- src/checker.cpp | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index c56c8a739..7fd9b379a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -335,7 +335,7 @@ bool check_constant_parameter_value(Type *type, Ast *expr) { gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params, bool *is_polymorphic_, - Ast *node, Array *poly_operands) { + Array *poly_operands) { Type *polymorphic_params_type = nullptr; GB_ASSERT(is_polymorphic_ != nullptr); @@ -643,13 +643,14 @@ 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.is_no_copy = st->is_no_copy; struct_type->Struct.polymorphic_params = check_record_polymorphic_params( ctx, st->polymorphic_params, &struct_type->Struct.is_polymorphic, - node, poly_operands + poly_operands ); wait_signal_set(&struct_type->Struct.polymorphic_wait_signal); @@ -696,11 +697,12 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no ast_node(ut, UnionType, node); + union_type->Union.node = node; union_type->Union.scope = ctx->scope; union_type->Union.polymorphic_params = check_record_polymorphic_params( ctx, ut->polymorphic_params, &union_type->Union.is_polymorphic, - node, poly_operands + poly_operands ); wait_signal_set(&union_type->Union.polymorphic_wait_signal); diff --git a/src/checker.cpp b/src/checker.cpp index fdf5a8b7d..8ccdcb9f7 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -346,6 +346,7 @@ gb_internal Scope *scope_of_node(Ast *node) { gb_internal void check_open_scope(CheckerContext *c, Ast *node) { node = unparen_expr(node); + GB_ASSERT(node != nullptr); GB_ASSERT(node->kind == Ast_Invalid || is_ast_stmt(node) || is_ast_type(node)); -- cgit v1.2.3 From f66b7021a6023854404ffa60ebf757afe8aca6d1 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Fri, 5 Jul 2024 00:50:52 +0200 Subject: Fix not detecting duplicate proc cases Fixes #3864 --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 7fd9b379a..52c6f89ab 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -740,7 +740,7 @@ gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *no gb_string_free(str); } else { for_array(j, variants) { - if (are_types_identical(t, variants[j])) { + if (union_variant_index_types_equal(t, variants[j])) { ok = false; ERROR_BLOCK(); gbString str = type_to_string(t); -- cgit v1.2.3 From ae2f16edeadf10589aa883bbe0a8496d0dd3eed1 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 9 Jul 2024 15:29:36 +0100 Subject: Fix #3894 --- src/check_type.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 52c6f89ab..5323ea12d 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1120,6 +1120,8 @@ gb_internal void check_bit_field_type(CheckerContext *ctx, Type *bit_field_type, // NOTE(bill): it doesn't matter, and when it does, // that api is absolutely stupid return Endian_Unknown; + } else if (type_size_of(type) < 2) { + return Endian_Unknown; } else if (is_type_endian_specific(type)) { if (is_type_endian_little(type)) { return Endian_Little; -- cgit v1.2.3 From f85f6b338aa181fc10712eccf6c9b60afc1cdd65 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Jul 2024 12:28:15 +0100 Subject: Change `..` variadic logic; comment out unneeded error message --- src/check_type.cpp | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 5323ea12d..cd329af00 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1765,6 +1765,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (type_expr == nullptr) { param_value = handle_parameter_value(ctx, nullptr, &type, default_value, true); } else { + Ast *original_type_expr = type_expr; if (type_expr->kind == Ast_Ellipsis) { type_expr = type_expr->Ellipsis.expr; is_variadic = true; @@ -1773,6 +1774,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(param, "Invalid AST: Invalid variadic parameter with multiple names"); success = false; } + + GB_ASSERT(original_type_expr->kind == Ast_Ellipsis); + type_expr = ast_array_type(type_expr->file(), original_type_expr->Ellipsis.token, nullptr, type_expr); } if (type_expr->kind == Ast_TypeidType) { ast_node(tt, TypeidType, type_expr); @@ -1796,6 +1800,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (operands != nullptr) { ctx->allow_polymorphic_types = true; } + type = check_type(ctx, type_expr); ctx->allow_polymorphic_types = prev; @@ -1828,12 +1833,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } type = t_invalid; } - if (is_type_empty_union(type)) { - gbString str = type_to_string(type); - error(param, "Invalid use of an empty union '%s'", str); - gb_string_free(str); - type = t_invalid; - } + // if (is_type_empty_union(type)) { + // gbString str = type_to_string(type); + // error(param, "Invalid use of an empty union '%s'", str); + // gb_string_free(str); + // type = t_invalid; + // } if (is_type_polymorphic(type)) { switch (param_value.kind) { @@ -2081,6 +2086,14 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para param->Variable.type_expr = type_expr; } } + + if (is_variadic && variadic_index == variables.count) { + param->flags |= EntityFlag_Ellipsis; + if (is_c_vararg) { + param->flags |= EntityFlag_CVarArg; + } + } + if (p->flags&FieldFlag_no_alias) { param->flags |= EntityFlag_NoAlias; } @@ -2115,18 +2128,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (is_variadic) { GB_ASSERT(variadic_index >= 0); - } - - if (is_variadic) { GB_ASSERT(params.count > 0); - // NOTE(bill): Change last variadic parameter to be a slice - // Custom Calling convention for variadic parameters - Entity *end = variables[variadic_index]; - end->type = alloc_type_slice(end->type); - end->flags |= EntityFlag_Ellipsis; - if (is_c_vararg) { - end->flags |= EntityFlag_CVarArg; - } } isize specialization_count = 0; -- cgit v1.2.3 From c83307f26f1978143056df1e8881a6b81897f0b5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 10 Jul 2024 12:39:42 +0100 Subject: Give error message suggestion when doing `^x` instead of `x^` if `x` is an r-value --- src/check_type.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index cd329af00..dd8559114 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -3337,6 +3337,10 @@ gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, T gbString s = expr_to_string(pt->type); error(e, "^ is used for pointer types, did you mean '&%s'?", s); gb_string_free(s); + } else if (is_type_pointer(o.type)) { + gbString s = expr_to_string(pt->type); + error(e, "^ is used for pointer types, did you mean a dereference: '%s^'?", s); + gb_string_free(s); } else { // NOTE(bill): call check_type_expr again to get a consistent error message elem = check_type_expr(&c, pt->type, nullptr); -- cgit v1.2.3 From edc793d7c123a38826860ef72684308902a7012c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 11:39:05 +0100 Subject: Add `#no_capture args: ..T` to reuse the backing array stack memory --- core/fmt/fmt.odin | 58 +++++++++++++++++++++++------------------------ core/fmt/fmt_js.odin | 24 ++++++++++---------- core/fmt/fmt_os.odin | 24 ++++++++++---------- src/check_expr.cpp | 17 ++++++++++++++ src/check_type.cpp | 17 ++++++++++++++ src/checker.cpp | 1 + src/checker.hpp | 7 ++++++ src/entity.cpp | 2 +- src/llvm_backend.hpp | 7 ++++++ src/llvm_backend_proc.cpp | 27 +++++++++++++++++++++- src/parser.cpp | 1 + src/parser.hpp | 8 +++++-- 12 files changed, 136 insertions(+), 57 deletions(-) (limited to 'src/check_type.cpp') diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 234f4afbd..e56211346 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -125,7 +125,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist // Returns: A formatted string. // @(require_results) -aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { +aprint :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprint(&str, ..args, sep=sep) @@ -141,7 +141,7 @@ aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> strin // Returns: A formatted string with a newline character at the end. // @(require_results) -aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { +aprintln :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintln(&str, ..args, sep=sep) @@ -158,7 +158,7 @@ aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> str // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newline := false) -> string { +aprintf :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator, newline := false) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -174,7 +174,7 @@ aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newlin // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintfln :: proc(fmt: string, args: ..any, allocator := context.allocator) -> string { +aprintfln :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator) -> string { return aprintf(fmt, ..args, allocator=allocator, newline=true) } // Creates a formatted string @@ -188,7 +188,7 @@ aprintfln :: proc(fmt: string, args: ..any, allocator := context.allocator) -> s // Returns: A formatted string. // @(require_results) -tprint :: proc(args: ..any, sep := " ") -> string { +tprint :: proc(#no_capture args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprint(&str, ..args, sep=sep) @@ -204,7 +204,7 @@ tprint :: proc(args: ..any, sep := " ") -> string { // Returns: A formatted string with a newline character at the end. // @(require_results) -tprintln :: proc(args: ..any, sep := " ") -> string { +tprintln :: proc(#no_capture args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintln(&str, ..args, sep=sep) @@ -221,7 +221,7 @@ tprintln :: proc(args: ..any, sep := " ") -> string { // Returns: A formatted string. // @(require_results) -tprintf :: proc(fmt: string, args: ..any, newline := false) -> string { +tprintf :: proc(fmt: string, #no_capture args: ..any, newline := false) -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -237,7 +237,7 @@ tprintf :: proc(fmt: string, args: ..any, newline := false) -> string { // Returns: A formatted string. // @(require_results) -tprintfln :: proc(fmt: string, args: ..any) -> string { +tprintfln :: proc(fmt: string, #no_capture args: ..any) -> string { return tprintf(fmt, ..args, newline=true) } // Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer. @@ -249,7 +249,7 @@ tprintfln :: proc(fmt: string, args: ..any) -> string { // // Returns: A formatted string // -bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { +bprint :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprint(&sb, ..args, sep=sep) } @@ -262,7 +262,7 @@ bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { // // Returns: A formatted string with a newline character at the end // -bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { +bprintln :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprintln(&sb, ..args, sep=sep) } @@ -276,7 +276,7 @@ bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { // // Returns: A formatted string // -bprintf :: proc(buf: []byte, fmt: string, args: ..any, newline := false) -> string { +bprintf :: proc(buf: []byte, fmt: string, #no_capture args: ..any, newline := false) -> string { sb := strings.builder_from_bytes(buf) return sbprintf(&sb, fmt, ..args, newline=newline) } @@ -289,7 +289,7 @@ bprintf :: proc(buf: []byte, fmt: string, args: ..any, newline := false) -> stri // // Returns: A formatted string // -bprintfln :: proc(buf: []byte, fmt: string, args: ..any) -> string { +bprintfln :: proc(buf: []byte, fmt: string, #no_capture args: ..any) -> string { return bprintf(buf, fmt, ..args, newline=true) } // Runtime assertion with a formatted message @@ -301,14 +301,14 @@ bprintfln :: proc(buf: []byte, fmt: string, args: ..any) -> string { // - loc: The location of the caller // @(disabled=ODIN_DISABLE_ASSERT) -assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) { +assertf :: proc(condition: bool, fmt: string, #no_capture args: ..any, loc := #caller_location) { if !condition { // NOTE(dragos): We are using the same trick as in builtin.assert // to improve performance to make the CPU not // execute speculatively, making it about an order of // magnitude faster @(cold) - internal :: proc(loc: runtime.Source_Code_Location, fmt: string, args: ..any) { + internal :: proc(loc: runtime.Source_Code_Location, fmt: string, #no_capture args: ..any) { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -326,7 +326,7 @@ assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_locati // - args: A variadic list of arguments to be formatted // - loc: The location of the caller // -panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { +panicf :: proc(fmt: string, #no_capture args: ..any, loc := #caller_location) -> ! { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -346,7 +346,7 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { // Returns: A formatted C string // @(require_results) -caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { +caprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str) sbprintf(&str, format, ..args, newline=newline) @@ -365,7 +365,7 @@ caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { // Returns: A formatted C string // @(require_results) -caprintfln :: proc(format: string, args: ..any) -> cstring { +caprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { return caprintf(format, ..args, newline=true) } // Creates a formatted C string @@ -379,7 +379,7 @@ caprintfln :: proc(format: string, args: ..any) -> cstring { // Returns: A formatted C string. // @(require_results) -ctprint :: proc(args: ..any, sep := " ") -> cstring { +ctprint :: proc(#no_capture args: ..any, sep := " ") -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprint(&str, ..args, sep=sep) @@ -399,7 +399,7 @@ ctprint :: proc(args: ..any, sep := " ") -> cstring { // Returns: A formatted C string // @(require_results) -ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring { +ctprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprintf(&str, format, ..args, newline=newline) @@ -418,7 +418,7 @@ ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring { // Returns: A formatted C string // @(require_results) -ctprintfln :: proc(format: string, args: ..any) -> cstring { +ctprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { return ctprintf(format, ..args, newline=true) } // Formats using the default print settings and writes to the given strings.Builder @@ -430,7 +430,7 @@ ctprintfln :: proc(format: string, args: ..any) -> cstring { // // Returns: A formatted string // -sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { +sbprint :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { wprint(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -443,7 +443,7 @@ sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // // Returns: The resulting formatted string // -sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { +sbprintln :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { wprintln(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -457,7 +457,7 @@ sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { // // Returns: The resulting formatted string // -sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any, newline := false) -> string { +sbprintf :: proc(buf: ^strings.Builder, fmt: string, #no_capture args: ..any, newline := false) -> string { wprintf(strings.to_writer(buf), fmt, ..args, flush=true, newline=newline) return strings.to_string(buf^) } @@ -469,7 +469,7 @@ sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any, newline := fal // // Returns: A formatted string // -sbprintfln :: proc(buf: ^strings.Builder, format: string, args: ..any) -> string { +sbprintfln :: proc(buf: ^strings.Builder, format: string, #no_capture args: ..any) -> string { return sbprintf(buf, format, ..args, newline=true) } // Formats and writes to an io.Writer using the default print settings @@ -481,7 +481,7 @@ sbprintfln :: proc(buf: ^strings.Builder, format: string, args: ..any) -> string // // Returns: The number of bytes written // -wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { +wprint :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -522,7 +522,7 @@ wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { // // Returns: The number of bytes written // -wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { +wprintln :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -549,11 +549,11 @@ wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { // // Returns: The number of bytes written // -wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true, newline := false) -> int { +wprintf :: proc(w: io.Writer, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { MAX_CHECKED_ARGS :: 64 assert(len(args) <= MAX_CHECKED_ARGS, "number of args > 64 is unsupported") - parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], args: ..any) -> int { + parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], #no_capture args: ..any) -> int { i := index // Prefix @@ -809,7 +809,7 @@ wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true, newline : // // Returns: The number of bytes written. // -wprintfln :: proc(w: io.Writer, format: string, args: ..any, flush := true) -> int { +wprintfln :: proc(w: io.Writer, format: string, #no_capture args: ..any, flush := true) -> int { return wprintf(w, format, ..args, flush=flush, newline=true) } // Writes a ^runtime.Type_Info value to an io.Writer diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index acf218eb5..4389b8d87 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -43,7 +43,7 @@ fd_to_writer :: proc(fd: os.Handle, loc := #caller_location) -> io.Writer { } // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -54,7 +54,7 @@ fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #ca } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -66,7 +66,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := # } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -78,24 +78,24 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, loc := #caller_location) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true, loc=loc) } // print formats using the default print settings and writes to stdout -print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } +print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } // println formats using the default print settings and writes to stdout -println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } +println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } // printf formats according to the specififed format string and writes to stdout -printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to stdout, followed by a newline. -printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to stderr -eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } +eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to stderr -eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } +eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } // eprintf formats according to the specififed format string and writes to stderr -eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to stderr, followed by a newline. -eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index 9de0d43be..538f7a08b 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -9,7 +9,7 @@ import "core:io" import "core:bufio" // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -20,7 +20,7 @@ fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { +fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -31,7 +31,7 @@ fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { return wprintln(w, ..args, sep=sep, flush=flush) } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -42,7 +42,7 @@ fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline return wprintf(w, fmt, ..args, flush=flush, newline=newline) } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true) } fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) { @@ -67,19 +67,19 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: } // print formats using the default print settings and writes to os.stdout -print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } +print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } // println formats using the default print settings and writes to os.stdout -println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } +println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } // printf formats according to the specified format string and writes to os.stdout -printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to os.stdout, followed by a newline. -printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to os.stderr -eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } +eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to os.stderr -eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } +eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } // eprintf formats according to the specified format string and writes to os.stderr -eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to os.stderr, followed by a newline. -eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 12acca0cb..645d8ac5a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6033,6 +6033,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; o.type = vt->type; + + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameter that use `#no_capture` + // on the variadic parameter + if (c->decl && (vt->flags & EntityFlag_NoCapture)) { + bool found = false; + for (NoCaptureData &nc : c->decl->no_captures) { + if (are_types_identical(vt->type, nc.slice_type)) { + nc.max_count = gb_max(nc.max_count, variadic_operands.count); + found = true; + break; + } + } + if (!found) { + array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count}); + } + } + } else { dummy_argument_count += 1; o.type = t_untyped_nil; diff --git a/src/check_type.cpp b/src/check_type.cpp index dd8559114..d1c9bb381 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1953,6 +1953,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(name, "'#by_ptr' can only be applied to variable fields"); p->flags &= ~FieldFlag_by_ptr; } + if (p->flags&FieldFlag_no_capture) { + error(name, "'#no_capture' can only be applied to variable variadic fields"); + p->flags &= ~FieldFlag_no_capture; + } param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved); param->TypeName.is_type_alias = true; @@ -2054,6 +2058,15 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para p->flags &= ~FieldFlag_by_ptr; // Remove the flag } } + if (p->flags&FieldFlag_no_capture) { + if (!(is_variadic && variadic_index == variables.count)) { + error(name, "'#no_capture' can only be applied to a variadic parameter"); + p->flags &= ~FieldFlag_no_capture; + } else if (p->flags & FieldFlag_c_vararg) { + error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); + p->flags &= ~FieldFlag_no_capture; + } + } if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { @@ -2115,6 +2128,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para if (p->flags&FieldFlag_by_ptr) { param->flags |= EntityFlag_ByPtr; } + if (p->flags&FieldFlag_no_capture) { + param->flags |= EntityFlag_NoCapture; + } + param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it add_entity(ctx, scope, name, param); diff --git a/src/checker.cpp b/src/checker.cpp index 8756cce1a..abacc13cb 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -184,6 +184,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { ptr_set_init(&d->deps, 0); ptr_set_init(&d->type_info_deps, 0); d->labels.allocator = heap_allocator(); + d->no_captures.allocator = heap_allocator(); } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { diff --git a/src/checker.hpp b/src/checker.hpp index 781737140..17722f6b6 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -181,6 +181,11 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { "Checked", }; +struct NoCaptureData { + Type *slice_type; // ..elem_type + isize max_count; +}; + // DeclInfo is used to store information of certain declarations to allow for "any order" usage struct DeclInfo { DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment @@ -219,6 +224,8 @@ struct DeclInfo { Array labels; + Array no_captures; + // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time struct lbModule *code_gen_module; }; diff --git a/src/entity.cpp b/src/entity.cpp index 41d84e0f7..db6ffdd52 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -45,7 +45,7 @@ enum EntityFlag : u64 { EntityFlag_Value = 1ull<<11, EntityFlag_BitFieldField = 1ull<<12, - + EntityFlag_NoCapture = 1ull<<13, // #no_capture EntityFlag_PolyConst = 1ull<<15, EntityFlag_NotExported = 1ull<<16, diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 005358734..dd1041702 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -296,6 +296,11 @@ enum lbProcedureFlag : u32 { lbProcedureFlag_DebugAllocaCopy = 1<<1, }; +struct lbNoCaptureData { + Type *slice_type; + lbAddr base_array; +}; + struct lbProcedure { u32 flags; u16 state_flags; @@ -336,6 +341,8 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; + Array no_captures; + LLVMValueRef temp_callee_return_struct_memory; Ast *curr_stmt; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 610c34de2..ec244e185 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -517,6 +517,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters); + p->no_captures.allocator = heap_allocator(); GB_ASSERT(p->type != nullptr); @@ -3450,8 +3451,32 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } isize slice_len = var_args.count; if (slice_len > 0) { + lbAddr base_array = {}; + if (e->flags & EntityFlag_NoCapture) { + for (lbNoCaptureData const &nc : p->no_captures) { + if (are_types_identical(nc.slice_type, slice_type)) { + base_array = nc.base_array; + break; + } + } + DeclInfo *d = decl_info_of_entity(p->entity); + if (d != nullptr && base_array.addr.value == nullptr) { + for (NoCaptureData const &nc : d->no_captures) { + if (are_types_identical(nc.slice_type, slice_type)) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, nc.max_count), true); + array_add(&p->no_captures, lbNoCaptureData{slice_type, base_array}); + break; + } + } + } + } + + if (base_array.addr.value == nullptr) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); + } + GB_ASSERT(base_array.addr.value != nullptr); + lbAddr slice = lb_add_local_generated(p, slice_type, true); - lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); for (isize i = 0; i < var_args.count; i++) { lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i); diff --git a/src/parser.cpp b/src/parser.cpp index 9ce3d563d..a6a146cfd 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4014,6 +4014,7 @@ struct ParseFieldPrefixMapping { gb_global ParseFieldPrefixMapping const parse_field_prefix_mappings[] = { {str_lit("using"), Token_using, FieldFlag_using}, {str_lit("no_alias"), Token_Hash, FieldFlag_no_alias}, + {str_lit("no_capture"), Token_Hash, FieldFlag_no_capture}, {str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg}, {str_lit("const"), Token_Hash, FieldFlag_const}, {str_lit("any_int"), Token_Hash, FieldFlag_any_int}, diff --git a/src/parser.hpp b/src/parser.hpp index 86b3393af..15176f789 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -330,9 +330,10 @@ enum FieldFlag : u32 { FieldFlag_subtype = 1<<7, FieldFlag_by_ptr = 1<<8, FieldFlag_no_broadcast = 1<<9, // disallow array programming + FieldFlag_no_capture = 1<<10, // Internal use by the parser only - FieldFlag_Tags = 1<<10, + FieldFlag_Tags = 1<<11, FieldFlag_Results = 1<<16, @@ -340,7 +341,10 @@ enum FieldFlag : u32 { FieldFlag_Invalid = 1u<<31, // Parameter List Restrictions - FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast, + FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg| + FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast| + FieldFlag_no_capture, + FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags, }; -- cgit v1.2.3 From 8642d719f0ece3625d535d47b41ff4d35072f47f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 12:19:47 +0100 Subject: Imply `#no_capture` to all variadic parameters --- base/runtime/core_builtin.odin | 8 ++-- base/runtime/core_builtin_soa.odin | 4 +- base/runtime/print.odin | 4 +- core/container/small_array/small_array.odin | 2 +- core/encoding/xml/tokenizer.odin | 6 +-- core/fmt/fmt.odin | 58 +++++++++++++-------------- core/fmt/fmt_js.odin | 24 +++++------ core/fmt/fmt_os.odin | 24 +++++------ core/log/log.odin | 32 +++++++-------- core/math/big/helpers.odin | 10 ++--- core/math/big/internal.odin | 8 ++-- core/odin/parser/parser.odin | 12 +++--- core/odin/tokenizer/tokenizer.odin | 6 +-- core/testing/testing.odin | 10 ++--- core/text/scanner/scanner.odin | 2 +- core/text/table/table.odin | 2 +- core/unicode/tools/generate_entity_table.odin | 2 +- src/check_type.cpp | 10 ++++- src/llvm_backend.hpp | 1 - src/parser.hpp | 5 ++- tests/core/encoding/xml/test_core_xml.odin | 2 +- tests/core/fmt/test_core_fmt.odin | 2 +- tests/documentation/documentation_tester.odin | 2 +- vendor/OpenGL/wrappers.odin | 2 +- vendor/raylib/raylib.odin | 4 +- 25 files changed, 125 insertions(+), 117 deletions(-) (limited to 'src/check_type.cpp') diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 5f6e1ec16..d68eefe23 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -524,12 +524,12 @@ _append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, l } @builtin -append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elems(array, true, loc, args) } @builtin -non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_elems(array, false, loc, args) } @@ -617,7 +617,7 @@ inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast arg: E, } @builtin -inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { +inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { if array == nil { return } @@ -679,7 +679,7 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle @builtin -assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { +assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error { new_size := index + len(args) if len(args) == 0 { ok = true diff --git a/base/runtime/core_builtin_soa.odin b/base/runtime/core_builtin_soa.odin index 108183ea6..7f7f5f086 100644 --- a/base/runtime/core_builtin_soa.odin +++ b/base/runtime/core_builtin_soa.odin @@ -342,12 +342,12 @@ _append_soa_elem :: proc(array: ^$T/#soa[dynamic]$E, zero_memory: bool, #no_broa } @builtin -append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_soa_elems(array, true, args=args, loc=loc) } @builtin -non_zero_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast #no_capture args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { +non_zero_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error { return _append_soa_elems(array, false, args=args, loc=loc) } diff --git a/base/runtime/print.odin b/base/runtime/print.odin index ecd301d21..0262e8ef6 100644 --- a/base/runtime/print.odin +++ b/base/runtime/print.odin @@ -72,7 +72,7 @@ when !ODIN_NO_RTTI { print_string("") } } - println_any :: #force_no_inline proc "contextless" (#no_capture args: ..any) { + println_any :: #force_no_inline proc "contextless" (args: ..any) { context = default_context() loop: for arg, i in args { assert(arg.id != nil) @@ -127,7 +127,7 @@ print_string :: #force_no_inline proc "contextless" (str: string) -> (n: int) { return } -print_strings :: #force_no_inline proc "contextless" (#no_capture args: ..string) -> (n: int) { +print_strings :: #force_no_inline proc "contextless" (args: ..string) -> (n: int) { for str in args { m, err := stderr_write(transmute([]byte)str) n += m diff --git a/core/container/small_array/small_array.odin b/core/container/small_array/small_array.odin index a698d965c..b2068469d 100644 --- a/core/container/small_array/small_array.odin +++ b/core/container/small_array/small_array.odin @@ -139,7 +139,7 @@ clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) { resize(a, 0) } -push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), #no_capture items: ..T) { +push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) { n := copy(a.data[a.len:], items[:]) a.len += n } diff --git a/core/encoding/xml/tokenizer.odin b/core/encoding/xml/tokenizer.odin index 8a26f1bce..a2bbaf28e 100644 --- a/core/encoding/xml/tokenizer.odin +++ b/core/encoding/xml/tokenizer.odin @@ -17,7 +17,7 @@ import "core:fmt" import "core:unicode" import "core:unicode/utf8" -Error_Handler :: #type proc(pos: Pos, fmt: string, #no_capture args: ..any) +Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) Token :: struct { kind: Token_Kind, @@ -112,13 +112,13 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { } } -default_error_handler :: proc(pos: Pos, msg: string, #no_capture args: ..any) { +default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column) fmt.eprintf(msg, ..args) fmt.eprintf("\n") } -error :: proc(t: ^Tokenizer, offset: int, msg: string, #no_capture args: ..any) { +error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { pos := offset_to_pos(t, offset) if t.err != nil { t.err(pos, msg, ..args) diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index e56211346..234f4afbd 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -125,7 +125,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist // Returns: A formatted string. // @(require_results) -aprint :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { +aprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprint(&str, ..args, sep=sep) @@ -141,7 +141,7 @@ aprint :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocat // Returns: A formatted string with a newline character at the end. // @(require_results) -aprintln :: proc(#no_capture args: ..any, sep := " ", allocator := context.allocator) -> string { +aprintln :: proc(args: ..any, sep := " ", allocator := context.allocator) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintln(&str, ..args, sep=sep) @@ -158,7 +158,7 @@ aprintln :: proc(#no_capture args: ..any, sep := " ", allocator := context.alloc // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintf :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator, newline := false) -> string { +aprintf :: proc(fmt: string, args: ..any, allocator := context.allocator, newline := false) -> string { str: strings.Builder strings.builder_init(&str, allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -174,7 +174,7 @@ aprintf :: proc(fmt: string, #no_capture args: ..any, allocator := context.alloc // Returns: A formatted string. The returned string must be freed accordingly. // @(require_results) -aprintfln :: proc(fmt: string, #no_capture args: ..any, allocator := context.allocator) -> string { +aprintfln :: proc(fmt: string, args: ..any, allocator := context.allocator) -> string { return aprintf(fmt, ..args, allocator=allocator, newline=true) } // Creates a formatted string @@ -188,7 +188,7 @@ aprintfln :: proc(fmt: string, #no_capture args: ..any, allocator := context.all // Returns: A formatted string. // @(require_results) -tprint :: proc(#no_capture args: ..any, sep := " ") -> string { +tprint :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprint(&str, ..args, sep=sep) @@ -204,7 +204,7 @@ tprint :: proc(#no_capture args: ..any, sep := " ") -> string { // Returns: A formatted string with a newline character at the end. // @(require_results) -tprintln :: proc(#no_capture args: ..any, sep := " ") -> string { +tprintln :: proc(args: ..any, sep := " ") -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintln(&str, ..args, sep=sep) @@ -221,7 +221,7 @@ tprintln :: proc(#no_capture args: ..any, sep := " ") -> string { // Returns: A formatted string. // @(require_results) -tprintf :: proc(fmt: string, #no_capture args: ..any, newline := false) -> string { +tprintf :: proc(fmt: string, args: ..any, newline := false) -> string { str: strings.Builder strings.builder_init(&str, context.temp_allocator) return sbprintf(&str, fmt, ..args, newline=newline) @@ -237,7 +237,7 @@ tprintf :: proc(fmt: string, #no_capture args: ..any, newline := false) -> strin // Returns: A formatted string. // @(require_results) -tprintfln :: proc(fmt: string, #no_capture args: ..any) -> string { +tprintfln :: proc(fmt: string, args: ..any) -> string { return tprintf(fmt, ..args, newline=true) } // Creates a formatted string using a supplied buffer as the backing array. Writes into the buffer. @@ -249,7 +249,7 @@ tprintfln :: proc(fmt: string, #no_capture args: ..any) -> string { // // Returns: A formatted string // -bprint :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { +bprint :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprint(&sb, ..args, sep=sep) } @@ -262,7 +262,7 @@ bprint :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { // // Returns: A formatted string with a newline character at the end // -bprintln :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { +bprintln :: proc(buf: []byte, args: ..any, sep := " ") -> string { sb := strings.builder_from_bytes(buf) return sbprintln(&sb, ..args, sep=sep) } @@ -276,7 +276,7 @@ bprintln :: proc(buf: []byte, #no_capture args: ..any, sep := " ") -> string { // // Returns: A formatted string // -bprintf :: proc(buf: []byte, fmt: string, #no_capture args: ..any, newline := false) -> string { +bprintf :: proc(buf: []byte, fmt: string, args: ..any, newline := false) -> string { sb := strings.builder_from_bytes(buf) return sbprintf(&sb, fmt, ..args, newline=newline) } @@ -289,7 +289,7 @@ bprintf :: proc(buf: []byte, fmt: string, #no_capture args: ..any, newline := fa // // Returns: A formatted string // -bprintfln :: proc(buf: []byte, fmt: string, #no_capture args: ..any) -> string { +bprintfln :: proc(buf: []byte, fmt: string, args: ..any) -> string { return bprintf(buf, fmt, ..args, newline=true) } // Runtime assertion with a formatted message @@ -301,14 +301,14 @@ bprintfln :: proc(buf: []byte, fmt: string, #no_capture args: ..any) -> string { // - loc: The location of the caller // @(disabled=ODIN_DISABLE_ASSERT) -assertf :: proc(condition: bool, fmt: string, #no_capture args: ..any, loc := #caller_location) { +assertf :: proc(condition: bool, fmt: string, args: ..any, loc := #caller_location) { if !condition { // NOTE(dragos): We are using the same trick as in builtin.assert // to improve performance to make the CPU not // execute speculatively, making it about an order of // magnitude faster @(cold) - internal :: proc(loc: runtime.Source_Code_Location, fmt: string, #no_capture args: ..any) { + internal :: proc(loc: runtime.Source_Code_Location, fmt: string, args: ..any) { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -326,7 +326,7 @@ assertf :: proc(condition: bool, fmt: string, #no_capture args: ..any, loc := #c // - args: A variadic list of arguments to be formatted // - loc: The location of the caller // -panicf :: proc(fmt: string, #no_capture args: ..any, loc := #caller_location) -> ! { +panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -346,7 +346,7 @@ panicf :: proc(fmt: string, #no_capture args: ..any, loc := #caller_location) -> // Returns: A formatted C string // @(require_results) -caprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { +caprintf :: proc(format: string, args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str) sbprintf(&str, format, ..args, newline=newline) @@ -365,7 +365,7 @@ caprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> c // Returns: A formatted C string // @(require_results) -caprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { +caprintfln :: proc(format: string, args: ..any) -> cstring { return caprintf(format, ..args, newline=true) } // Creates a formatted C string @@ -379,7 +379,7 @@ caprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { // Returns: A formatted C string. // @(require_results) -ctprint :: proc(#no_capture args: ..any, sep := " ") -> cstring { +ctprint :: proc(args: ..any, sep := " ") -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprint(&str, ..args, sep=sep) @@ -399,7 +399,7 @@ ctprint :: proc(#no_capture args: ..any, sep := " ") -> cstring { // Returns: A formatted C string // @(require_results) -ctprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> cstring { +ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring { str: strings.Builder strings.builder_init(&str, context.temp_allocator) sbprintf(&str, format, ..args, newline=newline) @@ -418,7 +418,7 @@ ctprintf :: proc(format: string, #no_capture args: ..any, newline := false) -> c // Returns: A formatted C string // @(require_results) -ctprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { +ctprintfln :: proc(format: string, args: ..any) -> cstring { return ctprintf(format, ..args, newline=true) } // Formats using the default print settings and writes to the given strings.Builder @@ -430,7 +430,7 @@ ctprintfln :: proc(format: string, #no_capture args: ..any) -> cstring { // // Returns: A formatted string // -sbprint :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { +sbprint :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { wprint(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -443,7 +443,7 @@ sbprint :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> s // // Returns: The resulting formatted string // -sbprintln :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> string { +sbprintln :: proc(buf: ^strings.Builder, args: ..any, sep := " ") -> string { wprintln(strings.to_writer(buf), ..args, sep=sep, flush=true) return strings.to_string(buf^) } @@ -457,7 +457,7 @@ sbprintln :: proc(buf: ^strings.Builder, #no_capture args: ..any, sep := " ") -> // // Returns: The resulting formatted string // -sbprintf :: proc(buf: ^strings.Builder, fmt: string, #no_capture args: ..any, newline := false) -> string { +sbprintf :: proc(buf: ^strings.Builder, fmt: string, args: ..any, newline := false) -> string { wprintf(strings.to_writer(buf), fmt, ..args, flush=true, newline=newline) return strings.to_string(buf^) } @@ -469,7 +469,7 @@ sbprintf :: proc(buf: ^strings.Builder, fmt: string, #no_capture args: ..any, ne // // Returns: A formatted string // -sbprintfln :: proc(buf: ^strings.Builder, format: string, #no_capture args: ..any) -> string { +sbprintfln :: proc(buf: ^strings.Builder, format: string, args: ..any) -> string { return sbprintf(buf, format, ..args, newline=true) } // Formats and writes to an io.Writer using the default print settings @@ -481,7 +481,7 @@ sbprintfln :: proc(buf: ^strings.Builder, format: string, #no_capture args: ..an // // Returns: The number of bytes written // -wprint :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { +wprint :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -522,7 +522,7 @@ wprint :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) // // Returns: The number of bytes written // -wprintln :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := true) -> int { +wprintln :: proc(w: io.Writer, args: ..any, sep := " ", flush := true) -> int { fi: Info fi.writer = w @@ -549,11 +549,11 @@ wprintln :: proc(w: io.Writer, #no_capture args: ..any, sep := " ", flush := tru // // Returns: The number of bytes written // -wprintf :: proc(w: io.Writer, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { +wprintf :: proc(w: io.Writer, fmt: string, args: ..any, flush := true, newline := false) -> int { MAX_CHECKED_ARGS :: 64 assert(len(args) <= MAX_CHECKED_ARGS, "number of args > 64 is unsupported") - parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], #no_capture args: ..any) -> int { + parse_options :: proc(fi: ^Info, fmt: string, index, end: int, unused_args: ^bit_set[0 ..< MAX_CHECKED_ARGS], args: ..any) -> int { i := index // Prefix @@ -809,7 +809,7 @@ wprintf :: proc(w: io.Writer, fmt: string, #no_capture args: ..any, flush := tru // // Returns: The number of bytes written. // -wprintfln :: proc(w: io.Writer, format: string, #no_capture args: ..any, flush := true) -> int { +wprintfln :: proc(w: io.Writer, format: string, args: ..any, flush := true) -> int { return wprintf(w, format, ..args, flush=flush, newline=true) } // Writes a ^runtime.Type_Info value to an io.Writer diff --git a/core/fmt/fmt_js.odin b/core/fmt/fmt_js.odin index 4389b8d87..acf218eb5 100644 --- a/core/fmt/fmt_js.odin +++ b/core/fmt/fmt_js.odin @@ -43,7 +43,7 @@ fd_to_writer :: proc(fd: os.Handle, loc := #caller_location) -> io.Writer { } // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -54,7 +54,7 @@ fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { +fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -66,7 +66,7 @@ fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := tr } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false, loc := #caller_location) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false, loc := #caller_location) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -78,24 +78,24 @@ fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := tr } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, loc := #caller_location) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, loc := #caller_location) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true, loc=loc) } // print formats using the default print settings and writes to stdout -print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } +print :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stdout, args=args, sep=sep, flush=flush) } // println formats using the default print settings and writes to stdout -println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } +println :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stdout, args=args, sep=sep, flush=flush) } // printf formats according to the specififed format string and writes to stdout -printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to stdout, followed by a newline. -printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to stderr -eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } +eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return wprint(w=stderr, args=args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to stderr -eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } +eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return wprintln(w=stderr, args=args, sep=sep, flush=flush) } // eprintf formats according to the specififed format string and writes to stderr -eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to stderr, followed by a newline. -eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return wprintf(stdout, fmt, ..args, flush=flush, newline=true) } diff --git a/core/fmt/fmt_os.odin b/core/fmt/fmt_os.odin index 538f7a08b..9de0d43be 100644 --- a/core/fmt/fmt_os.odin +++ b/core/fmt/fmt_os.odin @@ -9,7 +9,7 @@ import "core:io" import "core:bufio" // fprint formats using the default print settings and writes to fd -fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { +fprint :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -20,7 +20,7 @@ fprint :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true } // fprintln formats using the default print settings and writes to fd -fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := true) -> int { +fprintln :: proc(fd: os.Handle, args: ..any, sep := " ", flush := true) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -31,7 +31,7 @@ fprintln :: proc(fd: os.Handle, #no_capture args: ..any, sep := " ", flush := tr return wprintln(w, ..args, sep=sep, flush=flush) } // fprintf formats according to the specified format string and writes to fd -fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true, newline := false) -> int { +fprintf :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true, newline := false) -> int { buf: [1024]byte b: bufio.Writer defer bufio.writer_flush(&b) @@ -42,7 +42,7 @@ fprintf :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := tr return wprintf(w, fmt, ..args, flush=flush, newline=newline) } // fprintfln formats according to the specified format string and writes to fd, followed by a newline. -fprintfln :: proc(fd: os.Handle, fmt: string, #no_capture args: ..any, flush := true) -> int { +fprintfln :: proc(fd: os.Handle, fmt: string, args: ..any, flush := true) -> int { return fprintf(fd, fmt, ..args, flush=flush, newline=true) } fprint_type :: proc(fd: os.Handle, info: ^runtime.Type_Info, flush := true) -> (n: int, err: io.Error) { @@ -67,19 +67,19 @@ fprint_typeid :: proc(fd: os.Handle, id: typeid, flush := true) -> (n: int, err: } // print formats using the default print settings and writes to os.stdout -print :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } +print :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stdout, ..args, sep=sep, flush=flush) } // println formats using the default print settings and writes to os.stdout -println :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } +println :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stdout, ..args, sep=sep, flush=flush) } // printf formats according to the specified format string and writes to os.stdout -printf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } +printf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush) } // printfln formats according to the specified format string and writes to os.stdout, followed by a newline. -printfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } +printfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stdout, fmt, ..args, flush=flush, newline=true) } // eprint formats using the default print settings and writes to os.stderr -eprint :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } +eprint :: proc(args: ..any, sep := " ", flush := true) -> int { return fprint(os.stderr, ..args, sep=sep, flush=flush) } // eprintln formats using the default print settings and writes to os.stderr -eprintln :: proc(#no_capture args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } +eprintln :: proc(args: ..any, sep := " ", flush := true) -> int { return fprintln(os.stderr, ..args, sep=sep, flush=flush) } // eprintf formats according to the specified format string and writes to os.stderr -eprintf :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } +eprintf :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush) } // eprintfln formats according to the specified format string and writes to os.stderr, followed by a newline. -eprintfln :: proc(fmt: string, #no_capture args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } +eprintfln :: proc(fmt: string, args: ..any, flush := true) -> int { return fprintf(os.stderr, fmt, ..args, flush=flush, newline=true) } diff --git a/core/log/log.odin b/core/log/log.odin index 35dff086f..0d89fdb74 100644 --- a/core/log/log.odin +++ b/core/log/log.odin @@ -75,43 +75,43 @@ nil_logger :: proc() -> Logger { return Logger{nil_logger_proc, nil, Level.Debug, nil} } -debugf :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) { +debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) { logf(.Debug, fmt_str, ..args, location=location) } -infof :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) { +infof :: proc(fmt_str: string, args: ..any, location := #caller_location) { logf(.Info, fmt_str, ..args, location=location) } -warnf :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) { +warnf :: proc(fmt_str: string, args: ..any, location := #caller_location) { logf(.Warning, fmt_str, ..args, location=location) } -errorf :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) { +errorf :: proc(fmt_str: string, args: ..any, location := #caller_location) { logf(.Error, fmt_str, ..args, location=location) } -fatalf :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) { +fatalf :: proc(fmt_str: string, args: ..any, location := #caller_location) { logf(.Fatal, fmt_str, ..args, location=location) } -debug :: proc(#no_capture args: ..any, sep := " ", location := #caller_location) { +debug :: proc(args: ..any, sep := " ", location := #caller_location) { log(.Debug, ..args, sep=sep, location=location) } -info :: proc(#no_capture args: ..any, sep := " ", location := #caller_location) { +info :: proc(args: ..any, sep := " ", location := #caller_location) { log(.Info, ..args, sep=sep, location=location) } -warn :: proc(#no_capture args: ..any, sep := " ", location := #caller_location) { +warn :: proc(args: ..any, sep := " ", location := #caller_location) { log(.Warning, ..args, sep=sep, location=location) } -error :: proc(#no_capture args: ..any, sep := " ", location := #caller_location) { +error :: proc(args: ..any, sep := " ", location := #caller_location) { log(.Error, ..args, sep=sep, location=location) } -fatal :: proc(#no_capture args: ..any, sep := " ", location := #caller_location) { +fatal :: proc(args: ..any, sep := " ", location := #caller_location) { log(.Fatal, ..args, sep=sep, location=location) } -panic :: proc(#no_capture args: ..any, location := #caller_location) -> ! { +panic :: proc(args: ..any, location := #caller_location) -> ! { log(.Fatal, ..args, location=location) runtime.panic("log.panic", location) } -panicf :: proc(fmt_str: string, #no_capture args: ..any, location := #caller_location) -> ! { +panicf :: proc(fmt_str: string, args: ..any, location := #caller_location) -> ! { logf(.Fatal, fmt_str, ..args, location=location) runtime.panic("log.panicf", location) } @@ -133,14 +133,14 @@ assert :: proc(condition: bool, message := "", loc := #caller_location) { } @(disabled=ODIN_DISABLE_ASSERT) -assertf :: proc(condition: bool, fmt_str: string, #no_capture args: ..any, loc := #caller_location) { +assertf :: proc(condition: bool, fmt_str: string, args: ..any, loc := #caller_location) { if !condition { // NOTE(dragos): We are using the same trick as in builtin.assert // to improve performance to make the CPU not // execute speculatively, making it about an order of // magnitude faster @(cold) - internal :: proc(loc: runtime.Source_Code_Location, fmt_str: string, #no_capture args: ..any) { + internal :: proc(loc: runtime.Source_Code_Location, fmt_str: string, args: ..any) { p := context.assertion_failure_proc if p == nil { p = runtime.default_assertion_failure_proc @@ -155,7 +155,7 @@ assertf :: proc(condition: bool, fmt_str: string, #no_capture args: ..any, loc : -log :: proc(level: Level, #no_capture args: ..any, sep := " ", location := #caller_location) { +log :: proc(level: Level, args: ..any, sep := " ", location := #caller_location) { logger := context.logger if logger.procedure == nil { return @@ -167,7 +167,7 @@ log :: proc(level: Level, #no_capture args: ..any, sep := " ", location := #call logger.procedure(logger.data, level, str, logger.options, location) } -logf :: proc(level: Level, fmt_str: string, #no_capture args: ..any, location := #caller_location) { +logf :: proc(level: Level, fmt_str: string, args: ..any, location := #caller_location) { logger := context.logger if logger.procedure == nil { return diff --git a/core/math/big/helpers.odin b/core/math/big/helpers.odin index c82b5eead..ee09bb2c7 100644 --- a/core/math/big/helpers.odin +++ b/core/math/big/helpers.odin @@ -404,7 +404,7 @@ clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.allocator) return #force_inline internal_clear_if_uninitialized_single(arg, allocator) } -clear_if_uninitialized_multi :: proc(#no_capture args: ..^Int, allocator := context.allocator) -> (err: Error) { +clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) { args := args assert_if_nil(..args) @@ -420,7 +420,7 @@ error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) { return nil } -error_if_immutable_multi :: proc(#no_capture args: ..^Int) -> (err: Error) { +error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) { for i in args { if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable } } @@ -431,7 +431,7 @@ error_if_immutable :: proc {error_if_immutable_single, error_if_immutable_multi, /* Allocates several `Int`s at once. */ -int_init_multi :: proc(#no_capture integers: ..^Int, allocator := context.allocator) -> (err: Error) { +int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err: Error) { assert_if_nil(..integers) integers := integers @@ -812,13 +812,13 @@ assert_if_nil :: proc{ assert_if_nil_rat, } -assert_if_nil_int :: #force_inline proc(#no_capture integers: ..^Int, loc := #caller_location) { +assert_if_nil_int :: #force_inline proc(integers: ..^Int, loc := #caller_location) { for i in integers { assert(i != nil, "(nil)", loc) } } -assert_if_nil_rat :: #force_inline proc(#no_capture rationals: ..^Rat, loc := #caller_location) { +assert_if_nil_rat :: #force_inline proc(rationals: ..^Rat, loc := #caller_location) { for r in rationals { assert(r != nil, "(nil)", loc) } diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 9eaa0c8e1..c9b331e55 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -1844,7 +1844,7 @@ internal_root_n :: proc { internal_int_root_n, } Deallocates the backing memory of one or more `Int`s. Asssumes none of the `integers` to be a `nil`. */ -internal_int_destroy :: proc(#no_capture integers: ..^Int) { +internal_int_destroy :: proc(integers: ..^Int) { integers := integers for &a in integers { @@ -2872,7 +2872,7 @@ internal_clear_if_uninitialized_single :: proc(arg: ^Int, allocator := context.a return err } -internal_clear_if_uninitialized_multi :: proc(#no_capture args: ..^Int, allocator := context.allocator) -> (err: Error) { +internal_clear_if_uninitialized_multi :: proc(args: ..^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator for i in args { @@ -2890,7 +2890,7 @@ internal_error_if_immutable_single :: proc(arg: ^Int) -> (err: Error) { return nil } -internal_error_if_immutable_multi :: proc(#no_capture args: ..^Int) -> (err: Error) { +internal_error_if_immutable_multi :: proc(args: ..^Int) -> (err: Error) { for i in args { if i != nil && .Immutable in i.flags { return .Assignment_To_Immutable } } @@ -2901,7 +2901,7 @@ internal_error_if_immutable :: proc {internal_error_if_immutable_single, interna /* Allocates several `Int`s at once. */ -internal_int_init_multi :: proc(#no_capture integers: ..^Int, allocator := context.allocator) -> (err: Error) { +internal_int_init_multi :: proc(integers: ..^Int, allocator := context.allocator) -> (err: Error) { context.allocator = allocator integers := integers diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index 3ae3b5dba..dec892f84 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -5,8 +5,8 @@ import "core:odin/tokenizer" import "core:fmt" -Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, #no_capture args: ..any) -Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, #no_capture args: ..any) +Warning_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) +Error_Handler :: #type proc(pos: tokenizer.Pos, fmt: string, args: ..any) Flag :: enum u32 { Optional_Semicolons, @@ -67,25 +67,25 @@ Import_Decl_Kind :: enum { -default_warning_handler :: proc(pos: tokenizer.Pos, msg: string, #no_capture args: ..any) { +default_warning_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d): Warning: ", pos.file, pos.line, pos.column) fmt.eprintf(msg, ..args) fmt.eprintf("\n") } -default_error_handler :: proc(pos: tokenizer.Pos, msg: string, #no_capture args: ..any) { +default_error_handler :: proc(pos: tokenizer.Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d): ", pos.file, pos.line, pos.column) fmt.eprintf(msg, ..args) fmt.eprintf("\n") } -warn :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, #no_capture args: ..any) { +warn :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) { if p.warn != nil { p.warn(pos, msg, ..args) } p.file.syntax_warning_count += 1 } -error :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, #no_capture args: ..any) { +error :: proc(p: ^Parser, pos: tokenizer.Pos, msg: string, args: ..any) { if p.err != nil { p.err(pos, msg, ..args) } diff --git a/core/odin/tokenizer/tokenizer.odin b/core/odin/tokenizer/tokenizer.odin index c5992e5f4..62170aa10 100644 --- a/core/odin/tokenizer/tokenizer.odin +++ b/core/odin/tokenizer/tokenizer.odin @@ -4,7 +4,7 @@ import "core:fmt" import "core:unicode" import "core:unicode/utf8" -Error_Handler :: #type proc(pos: Pos, fmt: string, #no_capture args: ..any) +Error_Handler :: #type proc(pos: Pos, fmt: string, args: ..any) Flag :: enum { Insert_Semicolon, @@ -62,13 +62,13 @@ offset_to_pos :: proc(t: ^Tokenizer, offset: int) -> Pos { } } -default_error_handler :: proc(pos: Pos, msg: string, #no_capture args: ..any) { +default_error_handler :: proc(pos: Pos, msg: string, args: ..any) { fmt.eprintf("%s(%d:%d) ", pos.file, pos.line, pos.column) fmt.eprintf(msg, ..args) fmt.eprintf("\n") } -error :: proc(t: ^Tokenizer, offset: int, msg: string, #no_capture args: ..any) { +error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) { pos := offset_to_pos(t, offset) if t.err != nil { t.err(pos, msg, ..args) diff --git a/core/testing/testing.odin b/core/testing/testing.odin index 04dc79095..29fe853ef 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -53,12 +53,12 @@ T :: struct { @(deprecated="prefer `log.error`") -error :: proc(t: ^T, #no_capture args: ..any, loc := #caller_location) { +error :: proc(t: ^T, args: ..any, loc := #caller_location) { pkg_log.error(..args, location = loc) } @(deprecated="prefer `log.errorf`") -errorf :: proc(t: ^T, format: string, #no_capture args: ..any, loc := #caller_location) { +errorf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { pkg_log.errorf(format, ..args, location = loc) } @@ -87,12 +87,12 @@ failed :: proc(t: ^T) -> bool { } @(deprecated="prefer `log.info`") -log :: proc(t: ^T, #no_capture args: ..any, loc := #caller_location) { +log :: proc(t: ^T, args: ..any, loc := #caller_location) { pkg_log.info(..args, location = loc) } @(deprecated="prefer `log.infof`") -logf :: proc(t: ^T, format: string, #no_capture args: ..any, loc := #caller_location) { +logf :: proc(t: ^T, format: string, args: ..any, loc := #caller_location) { pkg_log.infof(format, ..args, location = loc) } @@ -121,7 +121,7 @@ expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bo return ok } -expectf :: proc(t: ^T, ok: bool, format: string, #no_capture args: ..any, loc := #caller_location) -> bool { +expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_location) -> bool { if !ok { pkg_log.errorf(format, ..args, location=loc) } diff --git a/core/text/scanner/scanner.odin b/core/text/scanner/scanner.odin index 6eb366b49..d27c66f24 100644 --- a/core/text/scanner/scanner.odin +++ b/core/text/scanner/scanner.odin @@ -250,7 +250,7 @@ error :: proc(s: ^Scanner, msg: string) { } } -errorf :: proc(s: ^Scanner, format: string, #no_capture args: ..any) { +errorf :: proc(s: ^Scanner, format: string, args: ..any) { error(s, fmt.tprintf(format, ..args)) } diff --git a/core/text/table/table.odin b/core/text/table/table.odin index 4d0baef64..27c99b1f1 100644 --- a/core/text/table/table.odin +++ b/core/text/table/table.odin @@ -145,7 +145,7 @@ set_cell_value_and_alignment :: proc(tbl: ^Table, row, col: int, value: any, ali cell.alignment = alignment } -format :: proc(tbl: ^Table, _fmt: string, #no_capture args: ..any) -> string { +format :: proc(tbl: ^Table, _fmt: string, args: ..any) -> string { context.allocator = tbl.format_allocator return fmt.aprintf(_fmt, ..args) } diff --git a/core/unicode/tools/generate_entity_table.odin b/core/unicode/tools/generate_entity_table.odin index 238a3e219..16baa1adf 100644 --- a/core/unicode/tools/generate_entity_table.odin +++ b/core/unicode/tools/generate_entity_table.odin @@ -12,7 +12,7 @@ import "core:fmt" /* Silent error handler for the parser. */ -Error_Handler :: proc(pos: xml.Pos, fmt: string, #no_capture args: ..any) {} +Error_Handler :: proc(pos: xml.Pos, fmt: string, args: ..any) {} OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, }, expected_doctype = "unicode", } diff --git a/src/check_type.cpp b/src/check_type.cpp index d1c9bb381..466b9b3cd 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2065,9 +2065,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } else if (p->flags & FieldFlag_c_vararg) { error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); p->flags &= ~FieldFlag_no_capture; + } else { + error(name, "'#no_capture' is already implied on all variadic parameter"); } } - if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { error(name, "'#no_alias' can only be applied to non constant values"); @@ -2085,6 +2086,11 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para error(name, "'#by_ptr' can only be applied to variable fields"); p->flags &= ~FieldFlag_by_ptr; } + if (p->flags&FieldFlag_no_capture) { + error(name, "'#no_capture' can only be applied to variable fields"); + p->flags &= ~FieldFlag_no_capture; + } + if (!is_type_polymorphic(type) && check_constant_parameter_value(type, params[i])) { // failed @@ -2104,6 +2110,8 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para param->flags |= EntityFlag_Ellipsis; if (is_c_vararg) { param->flags |= EntityFlag_CVarArg; + } else { + param->flags |= EntityFlag_NoCapture; } } diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index dd1041702..71fa1dbd0 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -344,7 +344,6 @@ struct lbProcedure { Array no_captures; LLVMValueRef temp_callee_return_struct_memory; - Ast *curr_stmt; Array scope_stack; diff --git a/src/parser.hpp b/src/parser.hpp index 15176f789..451cdf53d 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -330,10 +330,11 @@ enum FieldFlag : u32 { FieldFlag_subtype = 1<<7, FieldFlag_by_ptr = 1<<8, FieldFlag_no_broadcast = 1<<9, // disallow array programming - FieldFlag_no_capture = 1<<10, + + FieldFlag_no_capture = 1<<11, // Internal use by the parser only - FieldFlag_Tags = 1<<11, + FieldFlag_Tags = 1<<15, FieldFlag_Results = 1<<16, diff --git a/tests/core/encoding/xml/test_core_xml.odin b/tests/core/encoding/xml/test_core_xml.odin index 811ee27dc..b29431e10 100644 --- a/tests/core/encoding/xml/test_core_xml.odin +++ b/tests/core/encoding/xml/test_core_xml.odin @@ -8,7 +8,7 @@ import "core:fmt" import "core:log" import "core:hash" -Silent :: proc(pos: xml.Pos, format: string, #no_capture args: ..any) {} +Silent :: proc(pos: xml.Pos, format: string, args: ..any) {} OPTIONS :: xml.Options{ flags = { .Ignore_Unsupported, .Intern_Comments, }, expected_doctype = "", diff --git a/tests/core/fmt/test_core_fmt.odin b/tests/core/fmt/test_core_fmt.odin index 0aaef93a4..49142e24d 100644 --- a/tests/core/fmt/test_core_fmt.odin +++ b/tests/core/fmt/test_core_fmt.odin @@ -373,7 +373,7 @@ test_odin_value_export :: proc(t: ^testing.T) { } @(private) -check :: proc(t: ^testing.T, exp: string, format: string, #no_capture args: ..any, loc := #caller_location) { +check :: proc(t: ^testing.T, exp: string, format: string, args: ..any, loc := #caller_location) { got := fmt.tprintf(format, ..args) testing.expectf(t, got == exp, "(%q, %v): %q != %q", format, args, got, exp, loc = loc) } diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin index 7fc37b9f0..8a798d6c5 100644 --- a/tests/documentation/documentation_tester.odin +++ b/tests/documentation/documentation_tester.odin @@ -51,7 +51,7 @@ common_prefix :: proc(strs: []string) -> string { return prefix } -errorf :: proc(format: string, #no_capture args: ..any) -> ! { +errorf :: proc(format: string, args: ..any) -> ! { fmt.eprintf("%s ", os.args[0]) fmt.eprintf(format, ..args) fmt.eprintln() diff --git a/vendor/OpenGL/wrappers.odin b/vendor/OpenGL/wrappers.odin index 971452be5..1eb8fc72f 100644 --- a/vendor/OpenGL/wrappers.odin +++ b/vendor/OpenGL/wrappers.odin @@ -754,7 +754,7 @@ when !GL_DEBUG { MultiDrawElementsIndirectCount :: proc "c" (mode: i32, type: i32, indirect: [^]DrawElementsIndirectCommand, drawcount: i32, maxdrawcount, stride: i32) { impl_MultiDrawElementsIndirectCount(mode, type, indirect, drawcount, maxdrawcount, stride) } PolygonOffsetClamp :: proc "c" (factor, units, clamp: f32) { impl_PolygonOffsetClamp(factor, units, clamp) } } else { - debug_helper :: proc"c"(from_loc: runtime.Source_Code_Location, num_ret: int, #no_capture args: ..any, loc := #caller_location) { + debug_helper :: proc"c"(from_loc: runtime.Source_Code_Location, num_ret: int, args: ..any, loc := #caller_location) { context = runtime.default_context() Error_Enum :: enum { diff --git a/vendor/raylib/raylib.odin b/vendor/raylib/raylib.odin index c2995ba36..0dd3bd4fd 100644 --- a/vendor/raylib/raylib.odin +++ b/vendor/raylib/raylib.odin @@ -1667,7 +1667,7 @@ IsGestureDetected :: proc "c" (gesture: Gesture) -> bool { // Text formatting with variables (sprintf style) -TextFormat :: proc(text: cstring, #no_capture args: ..any) -> cstring { +TextFormat :: proc(text: cstring, args: ..any) -> cstring { @static buffers: [MAX_TEXTFORMAT_BUFFERS][MAX_TEXT_BUFFER_LENGTH]byte @static index: u32 @@ -1683,7 +1683,7 @@ TextFormat :: proc(text: cstring, #no_capture args: ..any) -> cstring { } // Text formatting with variables (sprintf style) and allocates (must be freed with 'MemFree') -TextFormatAlloc :: proc(text: cstring, #no_capture args: ..any) -> cstring { +TextFormatAlloc :: proc(text: cstring, args: ..any) -> cstring { str := fmt.tprintf(string(text), ..args) return strings.clone_to_cstring(str, MemAllocator()) } -- cgit v1.2.3 From 3dff83f3dc2914cdfb9a8f19cf990682cda41b03 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 12:39:30 +0100 Subject: Mock out `#no_capture` for future use --- src/check_expr.cpp | 13 ++++++------- src/check_type.cpp | 32 ++++++++++++++++++++++++-------- src/checker.cpp | 2 +- src/checker.hpp | 4 ++-- src/llvm_abi.cpp | 6 ++++++ src/llvm_backend.hpp | 4 ++-- src/llvm_backend_proc.cpp | 32 +++++++++++++------------------- 7 files changed, 54 insertions(+), 39 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 645d8ac5a..4edd34990 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6034,19 +6034,18 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A Entity *vt = pt->params->Tuple.variables[pt->variadic_index]; o.type = vt->type; - // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameter that use `#no_capture` - // on the variadic parameter - if (c->decl && (vt->flags & EntityFlag_NoCapture)) { + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array + if (c->decl) { bool found = false; - for (NoCaptureData &nc : c->decl->no_captures) { - if (are_types_identical(vt->type, nc.slice_type)) { - nc.max_count = gb_max(nc.max_count, variadic_operands.count); + for (auto &vr : c->decl->variadic_reuses) { + if (are_types_identical(vt->type, vr.slice_type)) { + vr.max_count = gb_max(vr.max_count, variadic_operands.count); found = true; break; } } if (!found) { - array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count}); + array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count}); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 466b9b3cd..7b75bf503 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1954,7 +1954,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para p->flags &= ~FieldFlag_by_ptr; } if (p->flags&FieldFlag_no_capture) { - error(name, "'#no_capture' can only be applied to variable variadic fields"); + error(name, "'#no_capture' can only be applied to variable fields"); p->flags &= ~FieldFlag_no_capture; } @@ -2059,16 +2059,32 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } } if (p->flags&FieldFlag_no_capture) { - if (!(is_variadic && variadic_index == variables.count)) { - error(name, "'#no_capture' can only be applied to a variadic parameter"); - p->flags &= ~FieldFlag_no_capture; - } else if (p->flags & FieldFlag_c_vararg) { - error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); - p->flags &= ~FieldFlag_no_capture; + if (is_variadic && variadic_index == variables.count) { + if (p->flags & FieldFlag_c_vararg) { + error(name, "'#no_capture' cannot be applied to a #c_vararg parameter"); + p->flags &= ~FieldFlag_no_capture; + } else { + error(name, "'#no_capture' is already implied on all variadic parameter"); + } + } else if (is_type_polymorphic(type)) { + // ignore } else { - error(name, "'#no_capture' is already implied on all variadic parameter"); + if (is_type_internally_pointer_like(type)) { + // okay + } else if (is_type_slice(type) || is_type_string(type)) { + // okay + } else if (is_type_dynamic_array(type)) { + // okay + } else { + ERROR_BLOCK(); + error(name, "'#no_capture' can only be applied to pointer-like types, slices, strings, and dynamic arrays"); + error_line("\t'#no_capture' does not currently do anything useful\n"); + p->flags &= ~FieldFlag_no_capture; + } } } + + if (is_poly_name) { if (p->flags&FieldFlag_no_alias) { error(name, "'#no_alias' can only be applied to non constant values"); diff --git a/src/checker.cpp b/src/checker.cpp index abacc13cb..9adf4ef3c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -184,7 +184,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { ptr_set_init(&d->deps, 0); ptr_set_init(&d->type_info_deps, 0); d->labels.allocator = heap_allocator(); - d->no_captures.allocator = heap_allocator(); + d->variadic_reuses.allocator = heap_allocator(); } gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) { diff --git a/src/checker.hpp b/src/checker.hpp index 17722f6b6..2fadbe56a 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -181,7 +181,7 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] { "Checked", }; -struct NoCaptureData { +struct VariadicReuseData { Type *slice_type; // ..elem_type isize max_count; }; @@ -224,7 +224,7 @@ struct DeclInfo { Array labels; - Array no_captures; + Array variadic_reuses; // NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time struct lbModule *code_gen_module; diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index b2e485d01..9a3479b34 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -15,6 +15,7 @@ struct lbArgType { LLVMAttributeRef align_attribute; // Optional i64 byval_alignment; bool is_byval; + bool no_capture; }; @@ -159,6 +160,11 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute); } + if (arg->no_capture) { + LLVMAddAttributeAtIndex(fn, arg_index+1, nocapture_attr); + } + + if (ft->multiple_return_original_type) { if (ft->original_arg_count <= i) { LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr); diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 71fa1dbd0..24494e2af 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -296,7 +296,7 @@ enum lbProcedureFlag : u32 { lbProcedureFlag_DebugAllocaCopy = 1<<1, }; -struct lbNoCaptureData { +struct lbVariadicReuseData { Type *slice_type; lbAddr base_array; }; @@ -341,7 +341,7 @@ struct lbProcedure { bool in_multi_assignment; Array raw_input_parameters; - Array no_captures; + Array variadic_reuses; LLVMValueRef temp_callee_return_struct_memory; Ast *curr_stmt; diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index ec244e185..1585df865 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -517,7 +517,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { lb_start_block(p, p->entry_block); map_init(&p->direct_parameters); - p->no_captures.allocator = heap_allocator(); + p->variadic_reuses.allocator = heap_allocator(); GB_ASSERT(p->type != nullptr); @@ -3452,28 +3452,22 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { isize slice_len = var_args.count; if (slice_len > 0) { lbAddr base_array = {}; - if (e->flags & EntityFlag_NoCapture) { - for (lbNoCaptureData const &nc : p->no_captures) { - if (are_types_identical(nc.slice_type, slice_type)) { - base_array = nc.base_array; - break; - } + for (auto const &vr : p->variadic_reuses) { + if (are_types_identical(vr.slice_type, slice_type)) { + base_array = vr.base_array; + break; } - DeclInfo *d = decl_info_of_entity(p->entity); - if (d != nullptr && base_array.addr.value == nullptr) { - for (NoCaptureData const &nc : d->no_captures) { - if (are_types_identical(nc.slice_type, slice_type)) { - base_array = lb_add_local_generated(p, alloc_type_array(elem_type, nc.max_count), true); - array_add(&p->no_captures, lbNoCaptureData{slice_type, base_array}); - break; - } + } + DeclInfo *d = decl_info_of_entity(p->entity); + if (d != nullptr && base_array.addr.value == nullptr) { + for (auto const &vr : d->variadic_reuses) { + if (are_types_identical(vr.slice_type, slice_type)) { + base_array = lb_add_local_generated(p, alloc_type_array(elem_type, vr.max_count), true); + array_add(&p->variadic_reuses, lbVariadicReuseData{slice_type, base_array}); + break; } } } - - if (base_array.addr.value == nullptr) { - base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true); - } GB_ASSERT(base_array.addr.value != nullptr); lbAddr slice = lb_add_local_generated(p, slice_type, true); -- cgit v1.2.3 From 3533094cc2fc8cae8229b9887efae4541ccd278b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 12:44:13 +0100 Subject: Restrict `#no_capture` to pointer-like types only --- src/check_type.cpp | 6 +----- src/llvm_backend_proc.cpp | 4 +++- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index 7b75bf503..d0dddb62b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2071,13 +2071,9 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para } else { if (is_type_internally_pointer_like(type)) { // okay - } else if (is_type_slice(type) || is_type_string(type)) { - // okay - } else if (is_type_dynamic_array(type)) { - // okay } else { ERROR_BLOCK(); - error(name, "'#no_capture' can only be applied to pointer-like types, slices, strings, and dynamic arrays"); + error(name, "'#no_capture' can only be applied to pointer-like types"); error_line("\t'#no_capture' does not currently do anything useful\n"); p->flags &= ~FieldFlag_no_capture; } diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index 825434c31..272ffb474 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -254,7 +254,9 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i lb_add_proc_attribute_at_index(p, offset+parameter_index, "noalias"); } if (e->flags&EntityFlag_NoCapture) { - lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); + if (is_type_internally_pointer_like(e->type)) { + lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture"); + } } parameter_index += 1; } -- cgit v1.2.3 From 0a530b5ce8642508c5df2fdb9ec43682be07d5cd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 14 Jul 2024 13:20:12 +0100 Subject: Add error for `#no_capture` being reserved for future use --- src/check_type.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_type.cpp') diff --git a/src/check_type.cpp b/src/check_type.cpp index d0dddb62b..fea937e4e 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -2070,7 +2070,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para // ignore } else { if (is_type_internally_pointer_like(type)) { - // okay + error(name, "'#no_capture' is currently reserved for future use"); } else { ERROR_BLOCK(); error(name, "'#no_capture' can only be applied to pointer-like types"); -- cgit v1.2.3 From 1e37eaf54daf885636ea3ad9606a2b54e01721f9 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 15 Jul 2024 14:49:20 +0100 Subject: Begin work for `bit_set[...; [N]T]` (not working) --- src/build_settings.cpp | 2 + src/check_expr.cpp | 6 ++- src/check_type.cpp | 21 ++------ src/llvm_backend_const.cpp | 2 + src/llvm_backend_expr.cpp | 120 ++++++++++++++++++++++++++++++++++--------- src/llvm_backend_general.cpp | 2 + src/llvm_backend_proc.cpp | 5 ++ src/main.cpp | 5 ++ src/types.cpp | 21 ++++++++ 9 files changed, 141 insertions(+), 43 deletions(-) (limited to 'src/check_type.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index e0e7810e6..49bb83b22 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -440,6 +440,8 @@ struct BuildContext { bool cached; BuildCacheData build_cache_data; + bool internal_no_inline; + bool no_threaded_checker; bool show_debug_messages; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3fcfe29f5..01ff9da5b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9947,10 +9947,14 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } Type *et = base_type(t->BitSet.elem); isize field_count = 0; - if (et->kind == Type_Enum) { + if (et != nullptr && et->kind == Type_Enum) { field_count = et->Enum.fields.count; } + if (is_type_array(bit_set_to_int(t))) { + is_constant = false; + } + if (cl->elems[0]->kind == Ast_FieldValue) { error(cl->elems[0], "'field = value' in a bit_set a literal is not allowed"); is_constant = false; diff --git a/src/check_type.cpp b/src/check_type.cpp index fea937e4e..e3609970a 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -939,22 +939,6 @@ 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 false; - } - 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); @@ -1268,11 +1252,14 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t Type *t = default_type(lhs.type); if (bs->underlying != nullptr) { Type *u = check_type(c, bs->underlying); + // if (!is_valid_bit_field_backing_type(u)) { if (!is_type_integer(u)) { gbString ts = type_to_string(u); error(bs->underlying, "Expected an underlying integer for the bit set, got %s", ts); gb_string_free(ts); - return; + if (!is_valid_bit_field_backing_type(u)) { + return; + } } type->BitSet.underlying = u; } diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 5d9caeba1..12bcc4e1f 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -434,6 +434,8 @@ gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, Bi } } + GB_ASSERT(!is_type_array(original_type)); + LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((sz+7)/8), cast(u64 *)rop); if (big_int_is_neg(a)) { value = LLVMConstNeg(value); diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index bcacc0537..dfb7e162e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -296,12 +296,6 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu GB_ASSERT(vector_type0 == vector_type1); LLVMTypeRef vector_type = vector_type0; - LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), ""); - LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, ""); - LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, ""); - LLVMValueRef z = nullptr; - Type *integral_type = base_type(elem_type); if (is_type_simd_vector(integral_type)) { integral_type = core_array_type(integral_type); @@ -311,8 +305,18 @@ gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValu case Token_Add: op = Token_Or; break; case Token_Sub: op = Token_AndNot; break; } + Type *u = bit_set_to_int(type); + if (is_type_array(u)) { + return false; + } } + LLVMValueRef lhs_vp = LLVMBuildPointerCast(p->builder, lhs_ptr.value, LLVMPointerType(vector_type, 0), ""); + LLVMValueRef rhs_vp = LLVMBuildPointerCast(p->builder, rhs_ptr.value, LLVMPointerType(vector_type, 0), ""); + LLVMValueRef x = LLVMBuildLoad2(p->builder, vector_type, lhs_vp, ""); + LLVMValueRef y = LLVMBuildLoad2(p->builder, vector_type, rhs_vp, ""); + LLVMValueRef z = nullptr; + if (is_type_float(integral_type)) { switch (op) { case Token_Add: @@ -1286,6 +1290,14 @@ handle_op:; case Token_Add: op = Token_Or; break; case Token_Sub: op = Token_AndNot; break; } + Type *u = bit_set_to_int(type); + if (is_type_array(u)) { + lhs.type = u; + rhs.type = u; + res = lb_emit_arith(p, op, lhs, rhs, u); + res.type = type; + return res; + } } Type *integral_type = type; @@ -1441,6 +1453,7 @@ gb_internal lbValue lb_build_binary_in(lbProcedure *p, lbValue left, lbValue rig GB_ASSERT(are_types_identical(left.type, key_type)); Type *it = bit_set_to_int(rt); + left = lb_emit_conv(p, left, it); if (is_type_different_to_arch_endianness(it)) { left = lb_emit_byte_swap(p, left, integer_endian_type_to_platform_type(it)); @@ -2054,6 +2067,26 @@ gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) { } } + // bit_set <-> backing type + if (is_type_bit_set(src)) { + Type *backing = bit_set_to_int(src); + if (are_types_identical(backing, dst)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + if (is_type_bit_set(dst)) { + Type *backing = bit_set_to_int(dst); + if (are_types_identical(src, backing)) { + lbValue res = {}; + res.type = t; + res.value = value.value; + return res; + } + } + // Pointer <-> uintptr if (is_type_pointer(src) && is_type_uintptr(dst)) { @@ -2951,13 +2984,32 @@ gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, case Type_Pointer: case Type_MultiPointer: case Type_Proc: - case Type_BitSet: if (op_kind == Token_CmpEq) { res.value = LLVMBuildIsNull(p->builder, x.value, ""); } else if (op_kind == Token_NotEq) { res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); } return res; + case Type_BitSet: + { + Type *u = bit_set_to_int(bt); + if (is_type_array(u)) { + auto args = array_make(permanent_allocator(), 2); + lbValue lhs = lb_address_from_load_or_generate_local(p, x); + args[0] = lb_emit_conv(p, lhs, t_rawptr); + args[1] = lb_const_int(p->module, t_int, type_size_of(t)); + lbValue val = lb_emit_runtime_call(p, "memory_compare_zero", args); + lbValue res = lb_emit_comp(p, op_kind, val, lb_const_int(p->module, t_int, 0)); + return res; + } else { + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, x.value, ""); + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, x.value, ""); + } + } + return res; + } case Type_Slice: { @@ -4878,29 +4930,47 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) { case Type_BitSet: { i64 sz = type_size_of(type); if (cl->elems.count > 0 && sz > 0) { - lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr))); - lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower)); - for (Ast *elem : cl->elems) { - GB_ASSERT(elem->kind != Ast_FieldValue); - if (lb_is_elem_const(elem, et)) { - continue; + Type *backing = bit_set_to_int(type); + if (is_type_array(backing)) { + GB_PANIC("TODO: bit_set [N]T"); + Type *base_it = core_array_type(backing); + i64 bits_per_elem = 8*type_size_of(base_it); + gb_unused(bits_per_elem); + lbValue one = lb_const_value(p->module, t_i64, exact_value_i64(1)); + for (Ast *elem : cl->elems) { + GB_ASSERT(elem->kind != Ast_FieldValue); + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + lbValue e = lb_emit_conv(p, expr, t_i64); + e = lb_emit_arith(p, Token_Sub, e, lower, t_i64); + // lbValue idx = lb_emit_arith(p, Token_Div, e, bits_per_elem, t_i64); + // lbValue val = lb_emit_arith(p, Token_Div, e, bits_per_elem, t_i64); } - - lbValue expr = lb_build_expr(p, elem); - GB_ASSERT(expr.type->kind != Type_Tuple); - + } else { Type *it = bit_set_to_int(bt); lbValue one = lb_const_value(p->module, it, exact_value_i64(1)); - lbValue e = lb_emit_conv(p, expr, it); - e = lb_emit_arith(p, Token_Sub, e, lower, it); - e = lb_emit_arith(p, Token_Shl, one, e, it); - - lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); - lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); - new_value = lb_emit_transmute(p, new_value, type); - lb_addr_store(p, v, new_value); + for (Ast *elem : cl->elems) { + GB_ASSERT(elem->kind != Ast_FieldValue); + + if (lb_is_elem_const(elem, et)) { + continue; + } + + lbValue expr = lb_build_expr(p, elem); + GB_ASSERT(expr.type->kind != Type_Tuple); + + lbValue e = lb_emit_conv(p, expr, it); + e = lb_emit_arith(p, Token_Sub, e, lower, it); + e = lb_emit_arith(p, Token_Shl, one, e, it); + + lbValue old_value = lb_emit_transmute(p, lb_addr_load(p, v), it); + lbValue new_value = lb_emit_arith(p, Token_Or, old_value, e, it); + new_value = lb_emit_transmute(p, new_value, type); + lb_addr_store(p, v, new_value); + } } } break; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index bb04fc746..a91c1d1fe 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -1023,6 +1023,8 @@ gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr); LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0); LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, "")); + } else if (is_type_bit_set(a)) { + lb_mem_zero_ptr(p, ptr.value, a, 1); } else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) { LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value); } else { diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index eefe1c422..4ee4fb769 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -159,6 +159,11 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i case ProcInlining_no_inline: lb_add_attribute_to_proc(m, p->value, "noinline"); break; + default: + if (build_context.internal_no_inline) { + lb_add_attribute_to_proc(m, p->value, "noinline"); + break; + } } switch (entity->Procedure.optimization_mode) { diff --git a/src/main.cpp b/src/main.cpp index 0c3ef1399..e7f4ccc0a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -394,6 +394,7 @@ enum BuildFlagKind { BuildFlag_InternalIgnorePanic, BuildFlag_InternalModulePerFile, BuildFlag_InternalCached, + BuildFlag_InternalNoInline, BuildFlag_Tilde, @@ -598,6 +599,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalModulePerFile, str_lit("internal-module-per-file"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalCached, str_lit("internal-cached"), BuildFlagParam_None, Command_all); + add_flag(&build_flags, BuildFlag_InternalNoInline, str_lit("internal-no-inline"), BuildFlagParam_None, Command_all); #if ALLOW_TILDE add_flag(&build_flags, BuildFlag_Tilde, str_lit("tilde"), BuildFlagParam_None, Command__does_build); @@ -1422,6 +1424,9 @@ gb_internal bool parse_build_flags(Array args) { build_context.cached = true; build_context.use_separate_modules = true; break; + case BuildFlag_InternalNoInline: + build_context.internal_no_inline = true; + break; case BuildFlag_Tilde: build_context.tilde_backend = true; diff --git a/src/types.cpp b/src/types.cpp index fdc174d81..3f86d4c50 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2011,6 +2011,24 @@ gb_internal bool is_type_valid_bit_set_elem(Type *t) { return false; } + +gb_internal bool is_valid_bit_field_backing_type(Type *type) { + if (type == nullptr) { + return false; + } + 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 Type *bit_set_to_int(Type *t) { GB_ASSERT(is_type_bit_set(t)); Type *bt = base_type(t); @@ -2018,6 +2036,9 @@ gb_internal Type *bit_set_to_int(Type *t) { if (underlying != nullptr && is_type_integer(underlying)) { return underlying; } + if (underlying != nullptr && is_valid_bit_field_backing_type(underlying)) { + return underlying; + } i64 sz = type_size_of(t); switch (sz) { -- cgit v1.2.3