From c969bee86d300871103d8cc1441e37f5c60e2b86 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Fri, 23 Aug 2024 17:18:10 -0300 Subject: fix ambiguous generic type names --- src/check_expr.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9cdba2710..b06f804ae 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7625,7 +7625,7 @@ 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)); - TypeTuple *tuple = get_record_polymorphic_params(e->type); + TypeTuple *tuple = get_record_polymorphic_params(bt); if (tuple != nullptr) for_array(i, tuple->variables) { Entity *v = tuple->variables[i]; String name = v->token.string; @@ -7640,8 +7640,10 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = write_type_to_string(s, v->type, false); } } else if (v->kind == Entity_Constant) { - s = gb_string_append_fmt(s, "="); - s = write_exact_value_to_string(s, v->Constant.value); + if (v->type->kind != ExactValue_Invalid) { + s = gb_string_append_fmt(s, "="); + s = write_exact_value_to_string(s, v->Constant.value); + } } } s = gb_string_append_fmt(s, ")"); -- cgit v1.2.3 From 5ef8a092f663d5a092c6eff026ce3122020da349 Mon Sep 17 00:00:00 2001 From: fusion32 Date: Fri, 23 Aug 2024 17:50:27 -0300 Subject: fix wrong exact value kind comparison --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index b06f804ae..1a5b8c9a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7640,7 +7640,7 @@ gb_internal CallArgumentError check_polymorphic_record_type(CheckerContext *c, O s = write_type_to_string(s, v->type, false); } } else if (v->kind == Entity_Constant) { - if (v->type->kind != ExactValue_Invalid) { + if (v->Constant.value.kind != ExactValue_Invalid) { s = gb_string_append_fmt(s, "="); s = write_exact_value_to_string(s, v->Constant.value); } -- cgit v1.2.3 From 4458ca4585666b1e2bc9438b6a2402a1ad93bbc2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:40:02 +0100 Subject: Fix #4126 --- src/check_expr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9cdba2710..24cc8868a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3782,10 +3782,10 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ // NOTE(bill): Allow comparisons between types if (is_ise_expr(be->left)) { // Evalute the right before the left for an '.X' expression - check_expr_or_type(c, y, be->right, type_hint); + check_expr_or_type(c, y, be->right, nullptr /* ignore type hint */); check_expr_or_type(c, x, be->left, y->type); } else { - check_expr_or_type(c, x, be->left, type_hint); + check_expr_or_type(c, x, be->left, nullptr /* ignore type hint */); check_expr_or_type(c, y, be->right, x->type); } bool xt = x->mode == Addressing_Type; -- cgit v1.2.3 From 68a83abcd62210fac764806445fd28296d722c26 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:44:59 +0100 Subject: #4119 Add error when doing `{.A | .B}` instead of `{.A, .B}` with a suggestion to do surround it in parentheses to make it clear it is intended --- src/check_expr.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 24cc8868a..8e16bd0e9 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10055,6 +10055,22 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * is_constant = o->mode == Addressing_Constant; } + if (elem->kind == Ast_BinaryExpr) { + switch (elem->BinaryExpr.op.kind) { + case Token_Or: + { + gbString x = expr_to_string(elem->BinaryExpr.left); + gbString y = expr_to_string(elem->BinaryExpr.right); + gbString e = expr_to_string(elem); + error(elem, "Was the following intended? '%s, %s'; if not, surround the expression with parentheses '(%s)'", x, y, e); + gb_string_free(e); + gb_string_free(y); + gb_string_free(x); + } + break; + } + } + check_assignment(c, o, t->BitSet.elem, str_lit("bit_set literal")); if (o->mode == Addressing_Constant) { i64 lower = t->BitSet.lower; -- cgit v1.2.3 From 00fb60d3d96877935012a4cc9cbd39525dc52d17 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 11:48:32 +0100 Subject: #4115 Add `Suggestion: 'typeid_of(T)'` --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8e16bd0e9..a2500048e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1180,11 +1180,15 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ LIT(article), LIT(context_name)); } else { + ERROR_BLOCK(); error(operand->expr, "Cannot assign '%s', a type, to %.*s%.*s", op_type_str, LIT(article), LIT(context_name)); + if (type && are_types_identical(type, t_any)) { + error_line("\tSuggestion: 'typeid_of(%s)'", expr_str); + } } break; default: -- cgit v1.2.3 From ca4d91a8a33c2209ef9f6708fb5effc278a2b9f5 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 12:26:41 +0100 Subject: Fix #4079 --- src/check_expr.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index a878911d9..7ac09ac56 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4662,7 +4662,8 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open check_expr_with_type_hint(c, &operand, index_value, type_hint); if (operand.mode == Addressing_Invalid) { if (value) *value = 0; - return false; + // NOTE(bill): return true here to propagate the errors better + return true; } Type *index_type = t_int; @@ -4883,7 +4884,7 @@ gb_internal ExactValue get_constant_field_single(CheckerContext *c, ExactValue v TypeAndValue tav = fv->value->tav; if (success_) *success_ = true; if (finish_) *finish_ = false; - return tav.value;; + return tav.value; } } @@ -4958,7 +4959,6 @@ gb_internal ExactValue get_constant_field(CheckerContext *c, Operand const *oper return value; } } - if (success_) *success_ = true; return value; } else if (value.kind == ExactValue_Quaternion) { @@ -10566,7 +10566,8 @@ gb_internal ExprKind check_index_expr(CheckerContext *c, Operand *o, Ast *node, o->expr = node; return kind; } else if (ok && !is_type_matrix(t)) { - ExactValue value = type_and_value_of_expr(ie->expr).value; + TypeAndValue tav = type_and_value_of_expr(ie->expr); + ExactValue value = tav.value; o->mode = Addressing_Constant; bool success = false; bool finish = false; -- cgit v1.2.3 From 683dde1fa011056477423ded1bc6098ac2636675 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 12:47:29 +0100 Subject: Disallow labelled branches in `defer` - fix #3960 --- src/check_stmt.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 12156df01..1ef51e585 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -199,6 +199,9 @@ gb_internal bool check_has_break(Ast *stmt, String const &label, bool implicit) } break; + case Ast_DeferStmt: + return check_has_break(stmt->DeferStmt.stmt, label, implicit); + case Ast_BlockStmt: return check_has_break_list(stmt->BlockStmt.stmts, label, implicit); @@ -2706,6 +2709,7 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) error(bs->label, "A branch statement's label name must be an identifier"); return; } + Ast *ident = bs->label; String name = ident->Ident.token.string; Operand o = {}; @@ -2737,6 +2741,10 @@ gb_internal void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) break; } + + if (ctx->in_defer) { + error(bs->label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(token.string)); + } } case_end; -- cgit v1.2.3 From a4cc207022712c238e827bda9e871870970cca25 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 12:59:17 +0100 Subject: Add a recursion depth limit for #3987 with a consideration to use a `switch` statement or refactor the code to not use a large if-else chain --- src/parser.cpp | 8 ++++++++ src/parser.hpp | 2 ++ 2 files changed, 10 insertions(+) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 5796012d9..6461c9dd0 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4532,6 +4532,12 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { return ast_bad_stmt(f, f->curr_token, f->curr_token); } + if (f->recursion_depth_else_if > 256) { + syntax_error(f->curr_token, "if-else chain recursion depth limit hit. Consider using a 'switch' statement instead or refactor the code to not require a large if-else chain"); + f->recursion_depth_else_if = 0; + return ast_bad_stmt(f, f->curr_token, f->curr_token); + } + Token token = expect_token(f, Token_if); Ast *init = nullptr; Ast *cond = nullptr; @@ -4577,7 +4583,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { case Token_if: + f->recursion_depth_else_if += 1; else_stmt = parse_if_stmt(f); + f->recursion_depth_else_if -= 1; break; case Token_OpenBrace: else_stmt = parse_block_stmt(f, false); diff --git a/src/parser.hpp b/src/parser.hpp index 565a8e621..711e6f060 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -120,6 +120,8 @@ struct AstFile { bool allow_type; bool in_when_statement; + isize recursion_depth_else_if; + isize total_file_decl_count; isize delayed_decl_count; Slice decls; -- cgit v1.2.3 From b6d9a0c32e64fd4ce4d3350fca9a671d5daac126 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 13:16:55 +0100 Subject: Manually implement tail-recursion for `parse_if_stmt` --- src/parser.cpp | 30 ++++++++++++++++++++---------- src/parser.hpp | 2 -- 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 6461c9dd0..1a45c4ea5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4532,12 +4532,10 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { return ast_bad_stmt(f, f->curr_token, f->curr_token); } - if (f->recursion_depth_else_if > 256) { - syntax_error(f->curr_token, "if-else chain recursion depth limit hit. Consider using a 'switch' statement instead or refactor the code to not require a large if-else chain"); - f->recursion_depth_else_if = 0; - return ast_bad_stmt(f, f->curr_token, f->curr_token); - } + Ast *top_if_stmt = nullptr; + Ast *prev_if_stmt = nullptr; +if_else_chain:; Token token = expect_token(f, Token_if); Ast *init = nullptr; Ast *cond = nullptr; @@ -4579,14 +4577,24 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { ignore_strict_style = true; } skip_possible_newline_for_literal(f, ignore_strict_style); + + Ast *curr_if_stmt = ast_if_stmt(f, token, init, cond, body, nullptr); + if (top_if_stmt == nullptr) { + top_if_stmt = curr_if_stmt; + } + if (prev_if_stmt != nullptr) { + prev_if_stmt->IfStmt.else_stmt = curr_if_stmt; + } + if (f->curr_token.kind == Token_else) { Token else_token = expect_token(f, Token_else); switch (f->curr_token.kind) { case Token_if: - f->recursion_depth_else_if += 1; - else_stmt = parse_if_stmt(f); - f->recursion_depth_else_if -= 1; - break; + // NOTE(bill): Instead of relying on recursive descent for an if-else chain + // we can just inline the tail-recursion manually with a simple loop like + // construct using a `goto` + prev_if_stmt = curr_if_stmt; + goto if_else_chain; case Token_OpenBrace: else_stmt = parse_block_stmt(f, false); break; @@ -4601,7 +4609,9 @@ gb_internal Ast *parse_if_stmt(AstFile *f) { } } - return ast_if_stmt(f, token, init, cond, body, else_stmt); + curr_if_stmt->IfStmt.else_stmt = else_stmt; + + return top_if_stmt; } gb_internal Ast *parse_when_stmt(AstFile *f) { diff --git a/src/parser.hpp b/src/parser.hpp index 711e6f060..565a8e621 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -120,8 +120,6 @@ struct AstFile { bool allow_type; bool in_when_statement; - isize recursion_depth_else_if; - isize total_file_decl_count; isize delayed_decl_count; Slice decls; -- cgit v1.2.3 From 8b248673c10b7301b7bbab3ace73b631d3964aee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 13:36:43 +0100 Subject: Fix #4105 --- src/llvm_backend_debug.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index c896f889d..5d90dccea 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -55,6 +55,16 @@ gb_internal void lb_debug_file_line(lbModule *m, Ast *node, LLVMMetadataRef *fil } } +gb_internal LLVMMetadataRef lb_debug_procedure_parameters(lbModule *m, Type *type) { + if (is_type_proc(type)) { + return lb_debug_type(m, t_rawptr); + } + if (type->kind == Type_Tuple && type->Tuple.variables.count == 1) { + return lb_debug_procedure_parameters(m, type->Tuple.variables[0]->type); + } + return lb_debug_type(m, type); +} + gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) { i64 size = type_size_of(type); // Check size gb_unused(size); @@ -78,7 +88,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (type->Proc.result_count == 0) { parameters[param_index++] = nullptr; } else { - parameters[param_index++] = lb_debug_type(m, type->Proc.results); + parameters[param_index++] = lb_debug_procedure_parameters(m, type->Proc.results); } LLVMMetadataRef file = nullptr; @@ -88,7 +98,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (e->kind != Entity_Variable) { continue; } - parameters[param_index] = lb_debug_type(m, e->type); + parameters[param_index] = lb_debug_procedure_parameters(m, e->type); param_index += 1; } @@ -969,7 +979,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { return lb_debug_struct(m, type, bt, name, scope, file, line); } - case Type_Struct: return lb_debug_struct(m, type, base_type(type), name, scope, file, line); + case Type_Struct: return lb_debug_struct(m, type, bt, name, scope, file, line); case Type_Slice: return lb_debug_slice(m, type, name, scope, file, line); case Type_DynamicArray: return lb_debug_dynamic_array(m, type, name, scope, file, line); case Type_Union: return lb_debug_union(m, type, name, scope, file, line); -- cgit v1.2.3 From 8ba87e01bd9a26ffd391d2ad69ff0eb6a023d1cf Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 13:56:30 +0100 Subject: Improve `parse_enforce_tabs` usage --- src/parser.cpp | 22 +++++++++++++++++----- src/parser.hpp | 5 ++++- 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 1a45c4ea5..b250a3163 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1921,6 +1921,9 @@ gb_internal Array parse_enum_field_list(AstFile *f) { f->curr_token.kind != Token_EOF) { CommentGroup *docs = f->lead_comment; CommentGroup *comment = nullptr; + + parse_enforce_tabs(f); + Ast *name = parse_value(f); Ast *value = nullptr; if (f->curr_token.kind == Token_Eq) { @@ -2259,6 +2262,7 @@ gb_internal Array parse_union_variant_list(AstFile *f) { auto variants = array_make(ast_allocator(f)); while (f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { + parse_enforce_tabs(f); Ast *type = parse_type(f); if (type->kind != Ast_BadExpr) { array_add(&variants, type); @@ -4274,6 +4278,7 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl while (f->curr_token.kind != follow && f->curr_token.kind != Token_Colon && f->curr_token.kind != Token_EOF) { + if (!is_signature) parse_enforce_tabs(f); u32 flags = parse_field_prefixes(f); Ast *param = parse_var_type(f, allow_ellipsis, allow_typeid_token); if (param->kind == Ast_Ellipsis) { @@ -4363,6 +4368,8 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl f->curr_token.kind != Token_EOF && f->curr_token.kind != Token_Semicolon) { CommentGroup *docs = f->lead_comment; + + if (!is_signature) parse_enforce_tabs(f); u32 set_flags = parse_field_prefixes(f); Token tag = {}; Array names = parse_ident_list(f, allow_poly_names); @@ -5375,6 +5382,11 @@ gb_internal u64 check_vet_flags(AstFile *file) { gb_internal void parse_enforce_tabs(AstFile *f) { + // Checks to see if tabs have been used for indentation + if ((check_vet_flags(f) & VetFlag_Tabs) == 0) { + return; + } + Token prev = f->prev_token; Token curr = f->curr_token; if (prev.pos.line < curr.pos.line) { @@ -5391,6 +5403,10 @@ gb_internal void parse_enforce_tabs(AstFile *f) { isize len = end-it; for (isize i = 0; i < len; i++) { + if (it[i] == '/') { + // ignore comments + break; + } if (it[i] == ' ') { syntax_error(curr, "With '-vet-tabs', tabs must be used for indentation"); break; @@ -5405,11 +5421,7 @@ gb_internal Array parse_stmt_list(AstFile *f) { while (f->curr_token.kind != Token_case && f->curr_token.kind != Token_CloseBrace && f->curr_token.kind != Token_EOF) { - - // Checks to see if tabs have been used for indentation - if (check_vet_flags(f) & VetFlag_Tabs) { - parse_enforce_tabs(f); - } + parse_enforce_tabs(f); Ast *stmt = parse_stmt(f); if (stmt && stmt->kind != Ast_EmptyStmt) { diff --git a/src/parser.hpp b/src/parser.hpp index 565a8e621..f1794f79a 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -885,4 +885,7 @@ gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) { gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind); gb_internal gbString expr_to_string(Ast *expression); -gb_internal bool allow_field_separator(AstFile *f); \ No newline at end of file +gb_internal bool allow_field_separator(AstFile *f); + + +gb_internal void parse_enforce_tabs(AstFile *f); \ No newline at end of file -- cgit v1.2.3 From d0eaf7642dcf38f6f98c50e4daa53d31e2fadd71 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 14:36:18 +0100 Subject: Add `intrinsics.type_has_shared_fields` --- base/intrinsics/intrinsics.odin | 2 ++ src/check_builtin.cpp | 53 +++++++++++++++++++++++++++++++++++++++++ src/checker_builtin_procs.hpp | 3 +++ 3 files changed, 58 insertions(+) (limited to 'src') diff --git a/base/intrinsics/intrinsics.odin b/base/intrinsics/intrinsics.odin index b7e8c1189..3cf99bbd2 100644 --- a/base/intrinsics/intrinsics.odin +++ b/base/intrinsics/intrinsics.odin @@ -219,6 +219,8 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info --- type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) --- type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) --- +type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) --- + constant_utf16_cstring :: proc($literal: string) -> [^]u16 --- constant_log2 :: proc($v: $T) -> T where type_is_integer(T) --- diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 1c4b88101..fa03da946 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5665,6 +5665,59 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As break; } break; + + case BuiltinProc_type_has_shared_fields: + { + Type *u = check_type(c, ce->args[0]); + Type *ut = base_type(u); + if (ut == nullptr || ut == t_invalid) { + error(ce->args[0], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (ut->kind != Type_Struct || ut->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(ut); + error(ce->args[0], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + Type *v = check_type(c, ce->args[1]); + Type *vt = base_type(v); + if (vt == nullptr || vt == t_invalid) { + error(ce->args[1], "Expected a type for '%.*s'", LIT(builtin_name)); + return false; + } + if (vt->kind != Type_Struct || vt->Struct.soa_kind != StructSoa_None) { + gbString t = type_to_string(vt); + error(ce->args[1], "Expected a struct type for '%.*s', got %s", LIT(builtin_name), t); + gb_string_free(t); + return false; + } + + bool is_shared = true; + + for (Entity *v_field : vt->Struct.fields) { + bool found = false; + for (Entity *u_field : ut->Struct.fields) { + if (v_field->token.string == u_field->token.string && + are_types_identical(v_field->type, u_field->type)) { + found = true; + break; + } + } + + if (!found) { + is_shared = false; + break; + } + } + + operand->mode = Addressing_Constant; + operand->value = exact_value_bool(is_shared); + operand->type = t_untyped_bool; + break; + } + case BuiltinProc_type_field_type: { Operand op = {}; diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index ef07938c7..300397be9 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -313,6 +313,8 @@ BuiltinProc__type_simple_boolean_end, BuiltinProc_type_map_info, BuiltinProc_type_map_cell_info, + BuiltinProc_type_has_shared_fields, + BuiltinProc__type_end, BuiltinProc_procedure_of, @@ -647,6 +649,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("type_map_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("type_map_cell_info"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, + {STR_LIT("type_has_shared_fields"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From aa659a637a70af21feb60ee08c11c46718defa30 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 24 Aug 2024 15:46:54 +0100 Subject: Fix #4132 --- src/check_stmt.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1ef51e585..c8717ba98 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1698,7 +1698,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } } } - bool is_ptr = type_deref(operand.type); + bool is_ptr = is_type_pointer(type_deref(operand.type)); Type *t = base_type(type_deref(operand.type)); switch (t->kind) { @@ -1738,6 +1738,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; case Type_EnumeratedArray: + is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr; array_add(&vals, t->EnumeratedArray.elem); array_add(&vals, t->EnumeratedArray.index); break; -- cgit v1.2.3 From 8c952878fbff18986f4f39415158980fb1b69e1d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 25 Aug 2024 14:03:14 +0100 Subject: Allow empty strings in `link_prefix` and `link_suffix` --- src/checker.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index b24a7afdb..637659582 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3175,7 +3175,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } else if (name == "link_prefix") { if (ev.kind == ExactValue_String) { String link_prefix = ev.value_string; - if (!is_foreign_name_valid(link_prefix)) { + if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) { error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); } else { c->foreign_context.link_prefix = link_prefix; @@ -3187,7 +3187,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { } else if (name == "link_suffix") { if (ev.kind == ExactValue_String) { String link_suffix = ev.value_string; - if (!is_foreign_name_valid(link_suffix)) { + if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) { error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); } else { c->foreign_context.link_suffix = link_suffix; @@ -3489,7 +3489,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3501,7 +3501,7 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) { if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { @@ -3774,7 +3774,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_prefix = ev.value_string; - if (!is_foreign_name_valid(ac->link_prefix)) { + if (ac->link_prefix.len != 0 && !is_foreign_name_valid(ac->link_prefix)) { error(elem, "Invalid link prefix: %.*s", LIT(ac->link_prefix)); } } else { @@ -3785,7 +3785,7 @@ gb_internal DECL_ATTRIBUTE_PROC(var_decl_attribute) { ExactValue ev = check_decl_attribute_value(c, value); if (ev.kind == ExactValue_String) { ac->link_suffix = ev.value_string; - if (!is_foreign_name_valid(ac->link_suffix)) { + if (ac->link_suffix.len != 0 && !is_foreign_name_valid(ac->link_suffix)) { error(elem, "Invalid link suffix: %.*s", LIT(ac->link_suffix)); } } else { -- cgit v1.2.3 From d299d4e1cd009a66ce72371b4e7ab6c61811f9fc Mon Sep 17 00:00:00 2001 From: Laytan Date: Sun, 25 Aug 2024 21:15:25 +0200 Subject: riscv: add an error when atomics are used without the atomics extension --- src/check_builtin.cpp | 8 ++++++++ src/checker_builtin_procs.hpp | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index fa03da946..3742caeda 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -2048,6 +2048,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return ok; } + if (BuiltinProc__atomic_begin < id && id < BuiltinProc__atomic_end) { + if (build_context.metrics.arch == TargetArch_riscv64) { + if (!check_target_feature_is_enabled(str_lit("a"), nullptr)) { + error(call, "missing required target feature \"a\" for atomics, enable it by setting a different -microarch or explicitly adding it through -target-features"); + } + } + } + switch (id) { default: GB_PANIC("Implement built-in procedure: %.*s", LIT(builtin_name)); diff --git a/src/checker_builtin_procs.hpp b/src/checker_builtin_procs.hpp index 300397be9..2dfd570e4 100644 --- a/src/checker_builtin_procs.hpp +++ b/src/checker_builtin_procs.hpp @@ -99,6 +99,7 @@ enum BuiltinProcId { BuiltinProc_prefetch_write_instruction, BuiltinProc_prefetch_write_data, +BuiltinProc__atomic_begin, BuiltinProc_atomic_type_is_lock_free, BuiltinProc_atomic_thread_fence, BuiltinProc_atomic_signal_fence, @@ -124,6 +125,7 @@ enum BuiltinProcId { BuiltinProc_atomic_compare_exchange_strong_explicit, BuiltinProc_atomic_compare_exchange_weak, BuiltinProc_atomic_compare_exchange_weak_explicit, +BuiltinProc__atomic_end, BuiltinProc_fixed_point_mul, BuiltinProc_fixed_point_div, @@ -438,6 +440,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("prefetch_write_instruction"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("prefetch_write_data"), 2, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_type_is_lock_free"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_thread_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("atomic_signal_fence"), 1, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, @@ -463,6 +466,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = { {STR_LIT("atomic_compare_exchange_strong_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, {STR_LIT("atomic_compare_exchange_weak_explicit"), 5, false, Expr_Expr, BuiltinProcPkg_intrinsics, false, true}, + {STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_mul"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("fixed_point_div"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics}, -- cgit v1.2.3 From c424c940303b497f694ed2246adb1a7b97ff6d9b Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Mon, 26 Aug 2024 04:48:31 -0400 Subject: Fix inline transmutation of `[16]i8` to `i128` Forbids LLVM from generating SSE aligned loads on unaligned data. --- src/llvm_backend_utility.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_utility.cpp b/src/llvm_backend_utility.cpp index 68c1e9d1e..f63c42ab9 100644 --- a/src/llvm_backend_utility.cpp +++ b/src/llvm_backend_utility.cpp @@ -263,7 +263,7 @@ gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) { if (is_type_simd_vector(src) && is_type_simd_vector(dst)) { res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), ""); return res; - } else if (is_type_array_like(src) && is_type_simd_vector(dst)) { + } else if (is_type_array_like(src) && (is_type_simd_vector(dst) || is_type_integer_128bit(dst))) { unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst)); lbValue ptr = lb_address_from_load_or_generate_local(p, value); if (lb_try_update_alignment(ptr, align)) { -- cgit v1.2.3 From d7e977069a96916627d2f0b8e9ae848279a22784 Mon Sep 17 00:00:00 2001 From: avanspector Date: Mon, 26 Aug 2024 19:59:15 +0200 Subject: Update checker.cpp --- src/checker.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 637659582..35b84c155 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -3174,7 +3174,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_prefix") { if (ev.kind == ExactValue_String) { - String link_prefix = ev.value_string; + String link_prefix = string_trim_whitespace(ev.value_string); if (link_prefix.len != 0 && !is_foreign_name_valid(link_prefix)) { error(elem, "Invalid link prefix: '%.*s'", LIT(link_prefix)); } else { @@ -3186,7 +3186,7 @@ gb_internal DECL_ATTRIBUTE_PROC(foreign_block_decl_attribute) { return true; } else if (name == "link_suffix") { if (ev.kind == ExactValue_String) { - String link_suffix = ev.value_string; + String link_suffix = string_trim_whitespace(ev.value_string); if (link_suffix.len != 0 && !is_foreign_name_valid(link_suffix)) { error(elem, "Invalid link suffix: '%.*s'", LIT(link_suffix)); } else { @@ -4474,6 +4474,8 @@ gb_internal void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { } } +bool is_collect_entities_post = false; + // NOTE(bill): If file_scopes == nullptr, this will act like a local scope gb_internal void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; @@ -4532,7 +4534,9 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n case_end; case_ast_node(fb, ForeignBlockDecl, decl); - check_add_foreign_block_decl(c, decl); + if (is_collect_entities_post) { + check_add_foreign_block_decl(c, decl); + } case_end; default: @@ -6437,6 +6441,10 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("export entities - post"); check_export_entities(c); + TIME_SECTION("collect entities - post"); + is_collect_entities_post = true; + check_collect_entities_all(c); + TIME_SECTION("add entities from packages"); check_merge_queues_into_arrays(c); -- cgit v1.2.3 From 43ec2b9253379d03b69f40b57ef2aafd2c968416 Mon Sep 17 00:00:00 2001 From: avanspector Date: Mon, 26 Aug 2024 20:59:16 +0200 Subject: checker: delay foreign block checking if file scope, otherwise as before --- src/checker.cpp | 28 ++++++++++++++++++++-------- src/parser.cpp | 2 +- src/parser.hpp | 1 + 3 files changed, 22 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 35b84c155..fdc1ce840 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4474,8 +4474,6 @@ gb_internal void correct_type_aliases_in_scope(CheckerContext *c, Scope *s) { } } -bool is_collect_entities_post = false; - // NOTE(bill): If file_scopes == nullptr, this will act like a local scope gb_internal void check_collect_entities(CheckerContext *c, Slice const &nodes) { AstFile *curr_file = nullptr; @@ -4534,8 +4532,8 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n case_end; case_ast_node(fb, ForeignBlockDecl, decl); - if (is_collect_entities_post) { - check_add_foreign_block_decl(c, decl); + if (curr_file != nullptr) { + array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl); } case_end; @@ -4552,6 +4550,14 @@ gb_internal void check_collect_entities(CheckerContext *c, Slice const &n // NOTE(bill): 'when' stmts need to be handled after the other as the condition may refer to something // declared after this stmt in source if (curr_file == nullptr) { + // For 'foreign' block statements that are not in file scope. + for_array(decl_index, nodes) { + Ast *decl = nodes[decl_index]; + if (decl->kind == Ast_ForeignBlockDecl) { + check_add_foreign_block_decl(c, decl); + } + } + for_array(decl_index, nodes) { Ast *decl = nodes[decl_index]; if (decl->kind == Ast_WhenStmt) { @@ -5512,6 +5518,16 @@ gb_internal void check_import_entities(Checker *c) { correct_type_aliases_in_scope(&ctx, pkg->scope); } + for_array(i, pkg->files) { + AstFile *f = pkg->files[i]; + reset_checker_context(&ctx, f, &untyped); + + for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) { + check_add_foreign_block_decl(&ctx, decl); + } + array_clear(&f->delayed_decls_queues[AstDelayQueue_ForeignBlock]); + } + for_array(i, pkg->files) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); @@ -6441,10 +6457,6 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("export entities - post"); check_export_entities(c); - TIME_SECTION("collect entities - post"); - is_collect_entities_post = true; - check_collect_entities_all(c); - TIME_SECTION("add entities from packages"); check_merge_queues_into_arrays(c); diff --git a/src/parser.cpp b/src/parser.cpp index b250a3163..e3143dd33 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6446,7 +6446,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->total_file_decl_count += calc_decl_count(stmt); - if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl) { + if (stmt->kind == Ast_WhenStmt || stmt->kind == Ast_ExprStmt || stmt->kind == Ast_ImportDecl || stmt->kind == Ast_ForeignBlockDecl) { f->delayed_decl_count += 1; } } diff --git a/src/parser.hpp b/src/parser.hpp index f1794f79a..d5117a31e 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -82,6 +82,7 @@ enum AstFileFlag : u32 { enum AstDelayQueueKind { AstDelayQueue_Import, AstDelayQueue_Expr, + AstDelayQueue_ForeignBlock, AstDelayQueue_COUNT, }; -- cgit v1.2.3 From 9866c83d619d9d32154ab1452bdbd255f3510bf7 Mon Sep 17 00:00:00 2001 From: avanspector Date: Thu, 29 Aug 2024 23:43:01 +0200 Subject: Add missing checker delaying --- src/checker.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index fdc1ce840..bab2d9f86 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5228,9 +5228,9 @@ gb_internal bool collect_file_decl(CheckerContext *ctx, Ast *decl) { case_end; case_ast_node(fb, ForeignBlockDecl, decl); - if (check_add_foreign_block_decl(ctx, decl)) { - return true; - } + GB_ASSERT(ctx->collect_delayed_decls); + decl->state_flags |= StateFlag_BeenHandled; + array_add(&curr_file->delayed_decls_queues[AstDelayQueue_ForeignBlock], decl); case_end; case_ast_node(ws, WhenStmt, decl); -- cgit v1.2.3 From 47f423c12386c2d886bb8a5a8ab70e80364f9c66 Mon Sep 17 00:00:00 2001 From: avanspector Date: Fri, 30 Aug 2024 01:32:06 +0200 Subject: Set a flag for delayed checking --- src/checker.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index bab2d9f86..d5234c01c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -5513,8 +5513,6 @@ gb_internal void check_import_entities(Checker *c) { for_array(i, pkg->files) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); - ctx.collect_delayed_decls = false; - correct_type_aliases_in_scope(&ctx, pkg->scope); } @@ -5522,6 +5520,7 @@ gb_internal void check_import_entities(Checker *c) { AstFile *f = pkg->files[i]; reset_checker_context(&ctx, f, &untyped); + ctx.collect_delayed_decls = true; for (Ast *decl : f->delayed_decls_queues[AstDelayQueue_ForeignBlock]) { check_add_foreign_block_decl(&ctx, decl); } -- cgit v1.2.3 From 38ea276231cba6860ac013ffb338b96afb6cd2fa Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 30 Aug 2024 10:48:21 +0100 Subject: Make `~some_bit_set` work on only the possible bits by doing a mask with the full set --- src/check_expr.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++++- src/llvm_backend_expr.cpp | 12 ++++++- 2 files changed, 96 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7ac09ac56..ba198b5ca 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2575,6 +2575,84 @@ gb_internal bool check_is_not_addressable(CheckerContext *c, Operand *o) { return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable; } +gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) { + type = base_type(type); + GB_ASSERT(type->kind == Type_BitSet); + + i64 lower = type->BitSet.lower; + i64 upper = type->BitSet.upper; + Type *elem = type->BitSet.elem; + Type *underlying = type->BitSet.underlying; + bool is_backed = underlying != nullptr; + gb_unused(is_backed); + + BigInt b_lower = {}; + BigInt b_upper = {}; + big_int_from_i64(&b_lower, lower); + big_int_from_i64(&b_upper, upper); + + + BigInt one = {}; + big_int_from_u64(&one, 1); + + BigInt mask = {}; + + if (elem == nullptr) { + big_int_from_i64(&mask, -1); + } else if (is_type_enum(elem)) { + Type *e = base_type(elem); + GB_ASSERT(e->kind == Type_Enum); + gb_unused(e); + + if ((big_int_cmp(&e->Enum.min_value->value_integer, &b_lower) == 0 || is_backed) && + big_int_cmp(&e->Enum.max_value->value_integer, &b_upper) == 0) { + + i64 lower_base = is_backed ? gb_min(0, lower) : lower; + BigInt b_lower_base = {}; + big_int_from_i64(&b_lower_base, lower_base); + + for (Entity *f : e->Enum.fields) { + if (f->kind != Entity_Constant) { + continue; + } + if (f->Constant.value.kind != ExactValue_Integer) { + continue; + } + + BigInt shift_amount = f->Constant.value.value_integer; + big_int_sub_eq(&shift_amount, &b_lower_base); + + + BigInt value = {}; + big_int_shl(&value, &one, &shift_amount); + + big_int_or(&mask, &mask, &value); + } + + } else { + // TODO(bill): enum range based + big_int_from_i64(&mask, -1); + } + } else { + i64 lower_base = lower; + for (i64 x = lower; x <= upper; x++) { + BigInt shift_amount = {}; + big_int_from_i64(&shift_amount, x - lower_base); + + BigInt value = {}; + big_int_shl(&value, &one, &shift_amount); + + big_int_or(&mask, &mask, &value); + } + } + + + ExactValue res = {}; + res.kind = ExactValue_Integer; + res.value_integer = mask; + return res; +} + gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { switch (op.kind) { case Token_And: { // Pointer address @@ -2714,6 +2792,10 @@ gb_internal void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast * } o->value = exact_unary_operator_value(op.kind, o->value, precision, is_unsigned); + if (op.kind == Token_Xor && is_type_bit_set(type)) { + ExactValue mask = exact_bit_set_all_set_mask(type); + o->value = exact_binary_operator_value(Token_And, o->value, mask); + } if (is_type_typed(type)) { if (node != nullptr) { @@ -10085,7 +10167,9 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * if (lower <= v && v <= upper) { // okay } else { - error(elem, "Bit field value out of bounds, %lld not in the range %lld .. %lld", v, lower, upper); + gbString s = expr_to_string(o->expr); + error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, v, lower, upper); + gb_string_free(s); continue; } } diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index c2707612a..b10b7745a 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -136,6 +136,11 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, switch (op) { case Token_Xor: opv = LLVMBuildNot(p->builder, v, ""); + if (is_type_bit_set(elem_type)) { + ExactValue ev_mask = exact_bit_set_all_set_mask(elem_type); + lbValue mask = lb_const_value(p->module, elem_type, ev_mask); + opv = LLVMBuildAnd(p->builder, opv, mask.value, ""); + } break; case Token_Sub: if (is_type_float(elem_type)) { @@ -176,8 +181,13 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, if (op == Token_Xor) { lbValue cmp = {}; - cmp.value = LLVMBuildNot(p->builder, x.value, ""); cmp.type = x.type; + cmp.value = LLVMBuildNot(p->builder, x.value, ""); + if (is_type_bit_set(x.type)) { + ExactValue ev_mask = exact_bit_set_all_set_mask(x.type); + lbValue mask = lb_const_value(p->module, x.type, ev_mask); + cmp.value = LLVMBuildAnd(p->builder, cmp.value, mask.value, ""); + } return lb_emit_conv(p, cmp, type); } -- cgit v1.2.3 From 9197a126fcb7042ede78c26178314342e23c58b6 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 30 Aug 2024 10:52:11 +0100 Subject: Use XOR directly rather than `(~x) & mask` --- src/llvm_backend_expr.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index b10b7745a..f6b9934ef 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -182,11 +182,12 @@ gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, if (op == Token_Xor) { lbValue cmp = {}; cmp.type = x.type; - cmp.value = LLVMBuildNot(p->builder, x.value, ""); if (is_type_bit_set(x.type)) { ExactValue ev_mask = exact_bit_set_all_set_mask(x.type); lbValue mask = lb_const_value(p->module, x.type, ev_mask); - cmp.value = LLVMBuildAnd(p->builder, cmp.value, mask.value, ""); + cmp.value = LLVMBuildXor(p->builder, x.value, mask.value, ""); + } else { + cmp.value = LLVMBuildNot(p->builder, x.value, ""); } return lb_emit_conv(p, cmp, type); } -- cgit v1.2.3 From a4e865f90bd3a6f7e5ff004d691863827d0b9399 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 30 Aug 2024 11:01:06 +0100 Subject: Fix #4166 --- src/checker.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index d5234c01c..fa04911ac 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -1786,7 +1786,9 @@ gb_internal void add_entity_use(CheckerContext *c, Ast *identifier, Entity *enti entity->flags |= EntityFlag_Used; if (entity_has_deferred_procedure(entity)) { Entity *deferred = entity->Procedure.deferred_procedure.entity; - add_entity_use(c, nullptr, deferred); + if (deferred != entity) { + add_entity_use(c, nullptr, deferred); + } } if (identifier == nullptr || identifier->kind != Ast_Ident) { return; @@ -6114,6 +6116,11 @@ gb_internal void check_deferred_procedures(Checker *c) { case DeferredProcedure_in_out_by_ptr: attribute = "deferred_in_out_by_ptr"; break; } + if (src == dst) { + error(src->token, "'%.*s' cannot be used as its own %s", LIT(dst->token.string), attribute); + continue; + } + if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) { error(src->token, "'%s' cannot be used with a polymorphic procedure", attribute); continue; -- cgit v1.2.3 From 3072a02d5d48bdfcd7c491f4d35a1de0508be3d1 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Fri, 30 Aug 2024 18:54:51 +0200 Subject: Attempt to account for BuildTools installer's lack of \ --- src/microsoft_craziness.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/microsoft_craziness.h b/src/microsoft_craziness.h index 899583143..b0fd22a23 100644 --- a/src/microsoft_craziness.h +++ b/src/microsoft_craziness.h @@ -684,8 +684,14 @@ gb_internal void find_visual_studio_paths_from_env_vars(Find_Result *result) { ? str_lit("lib\\x64\\") : str_lit("lib\\x86\\"); - result->vs_exe_path = mc_concat(vctid, exe); - result->vs_library_path = mc_concat(vctid, lib); + if (string_ends_with(vctid, str_lit("\\"))) { + result->vs_exe_path = mc_concat(vctid, exe); + result->vs_library_path = mc_concat(vctid, lib); + } else { + result->vs_exe_path = mc_concat(vctid, str_lit("\\"), exe); + result->vs_library_path = mc_concat(vctid, str_lit("\\"), lib); + } + vs_found = true; } -- cgit v1.2.3 From 7624ecf4ba2a14611a80000f2b3de06b1eb0724e Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 31 Aug 2024 02:30:32 +0200 Subject: fix some issues with the "bad import name" errors There was so much wrong here: - The `if` statement was never entered because even on invalid import names `path_to_entity_name` returns "_" - Two errors were shown where one doesn't make sense, need to choose one based on context - Structure of the messages were different from other error messages - Suggestion was using the wrong import path --- src/checker.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index fa04911ac..543763fc3 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4946,12 +4946,18 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { } - if (import_name.len == 0) { + if (is_blank_ident(import_name) && !is_blank_ident(id->import_name.string)) { String invalid_name = id->fullpath; invalid_name = get_invalid_import_name(invalid_name); - error(id->token, "Import name %.*s, is not a valid identifier. Perhaps you want to reference the package by a different name like this: import \"%.*s\" ", LIT(invalid_name), LIT(invalid_name)); - error(token, "Import name, %.*s, cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + ERROR_BLOCK(); + + if (id->import_name.string.len > 0) { + error(token, "Import name, '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + } else { + error(id->token, "Import name '%.*s' is not a valid identifier", LIT(invalid_name)); + error_line("\tSuggestion: Rename the directory or explicitly set an import name like this 'import %.*s'", LIT(id->relpath.string)); + } } else { GB_ASSERT(id->import_name.pos.line != 0); id->import_name.string = import_name; -- cgit v1.2.3 From 7f3d8e115f389d9064905ff5aa8d359399dda20b Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 31 Aug 2024 02:45:17 +0200 Subject: remove comma --- src/checker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/checker.cpp b/src/checker.cpp index 543763fc3..64c66c8a6 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -4953,7 +4953,7 @@ gb_internal void check_add_import_decl(CheckerContext *ctx, Ast *decl) { ERROR_BLOCK(); if (id->import_name.string.len > 0) { - error(token, "Import name, '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); + error(token, "Import name '%.*s' cannot be use as an import name as it is not a valid identifier", LIT(id->import_name.string)); } else { error(id->token, "Import name '%.*s' is not a valid identifier", LIT(invalid_name)); error_line("\tSuggestion: Rename the directory or explicitly set an import name like this 'import %.*s'", LIT(id->relpath.string)); -- cgit v1.2.3 From 476030dd2890a4fc0c46afcd8dab3247982a3bd7 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2024 13:51:35 +0100 Subject: Fix #4156 --- src/check_expr.cpp | 2 +- src/llvm_backend_stmt.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ba198b5ca..3b0198431 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2630,7 +2630,7 @@ gb_internal ExactValue exact_bit_set_all_set_mask(Type *type) { } } else { - // TODO(bill): enum range based + // TODO(bill): enum range based"); big_int_from_i64(&mask, -1); } } else { diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index f2fe4f7dc..bef516283 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1404,6 +1404,10 @@ gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, boo } + if (is_typeid) { + return false; + } + return true; } -- cgit v1.2.3 From b4bdb73158d1c6ec8d3b16d2d5f956e749a98817 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 31 Aug 2024 15:06:20 +0100 Subject: Fix `new(sync.Mutex)` --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3b0198431..cbfde4f4b 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5738,7 +5738,7 @@ gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = fals gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) { if (o.type && is_type_no_copy(o.type)) { Ast *expr = unparen_expr(o.expr); - if (expr && o.mode != Addressing_Constant) { + if (expr && o.mode != Addressing_Constant && o.mode != Addressing_Type) { if (expr->kind == Ast_CallExpr) { // Okay } else { -- cgit v1.2.3 From a4ac50a5b455a4ebc21806d4b9e0529b8a4b796c Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 31 Aug 2024 19:06:17 +0200 Subject: Check for `#assert` condition to be a constant bool Fixes #4170 --- src/check_builtin.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 3742caeda..d2ad304bc 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1792,7 +1792,17 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o error(call, "'#assert' expects either 1 or 2 arguments, got %td", ce->args.count); return false; } - if (!is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { + + // operand->type can be nil if the condition is a procedure, for example: #assert(assert()) + // So let's check it before we use it, so we get the same error as if we wrote `#exists(assert()) + Ast *arg = ce->args[0]; + Entity *e = nullptr; + Operand o = {}; + if (arg->kind == Ast_Ident) { + e = check_ident(c, &o, arg, nullptr, nullptr, true); + } + + if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args[0]); error(call, "'%s' is not a constant boolean", str); gb_string_free(str); -- cgit v1.2.3 From c1cb1a3d7e546bcb73a012eda04521d1adbb6366 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 31 Aug 2024 19:13:37 +0200 Subject: Simplified #assert check --- src/check_builtin.cpp | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index d2ad304bc..910e7ffdb 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1795,13 +1795,6 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o // operand->type can be nil if the condition is a procedure, for example: #assert(assert()) // So let's check it before we use it, so we get the same error as if we wrote `#exists(assert()) - Ast *arg = ce->args[0]; - Entity *e = nullptr; - Operand o = {}; - if (arg->kind == Ast_Ident) { - e = check_ident(c, &o, arg, nullptr, nullptr, true); - } - if (operand->type == nullptr || !is_type_boolean(operand->type) || operand->mode != Addressing_Constant) { gbString str = expr_to_string(ce->args[0]); error(call, "'%s' is not a constant boolean", str); -- cgit v1.2.3 From 722b638e2cbefcc1735256ef712cf2b28078a7fb Mon Sep 17 00:00:00 2001 From: Laytan Date: Sat, 31 Aug 2024 19:40:05 +0200 Subject: "fix" #4169, looks like llvm 14 bug --- src/llvm_backend_stmt.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index bef516283..df3d4bc03 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -2199,8 +2199,7 @@ gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) { // and `LLVMConstIntGetZExtValue()` calls below will be valid and `LLVMInstructionEraseFromParent()` // will target the correct (& only) branch statement - - if (cond.value && LLVMIsConstant(cond.value)) { + if (cond.value && LLVMIsAConstantInt(cond.value)) { // NOTE(bill): Do a compile time short circuit for when the condition is constantly known. // This done manually rather than relying on the SSA passes because sometimes the SSA passes // miss some even if they are constantly known, especially with few optimization passes. -- cgit v1.2.3 From 28c643d23f989937c8d530b49a2369e8cd9d39e2 Mon Sep 17 00:00:00 2001 From: Laytan Date: Sun, 1 Sep 2024 15:51:39 +0200 Subject: riscv compiler support --- src/bug_report.cpp | 8 +++++++- src/build_settings.cpp | 4 +++- src/gb/gb.h | 17 +++++++++++++++-- src/main.cpp | 6 ++++++ src/threading.cpp | 3 +++ 5 files changed, 34 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 916d4016a..5f768f57f 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -155,7 +155,7 @@ gb_internal void report_windows_product_type(DWORD ProductType) { #endif gb_internal void odin_cpuid(int leaf, int result[]) { - #if defined(GB_CPU_ARM) + #if defined(GB_CPU_ARM) || defined(GB_CPU_RISCV) return; #elif defined(GB_CPU_X86) @@ -225,6 +225,12 @@ gb_internal void report_cpu_info() { gb_printf("ARM\n"); #endif } + #elif defined(GB_CPU_RISCV) + #if defined(GB_ARCH_64_BIT) + gb_printf("RISCV64\n"); + #else + gb_printf("RISCV32\n"); + #endif #else gb_printf("Unknown\n"); #endif diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 3d56f4202..fe0e478c7 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -1525,6 +1525,8 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta metrics = &target_haiku_amd64; #elif defined(GB_CPU_ARM) metrics = &target_linux_arm64; + #elif defined(GB_CPU_RISCV) + metrics = &target_linux_riscv64; #else metrics = &target_linux_amd64; #endif @@ -1647,7 +1649,7 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta // Disallow on wasm bc->use_separate_modules = false; - } if(bc->metrics.arch == TargetArch_riscv64) { + } if(bc->metrics.arch == TargetArch_riscv64 && bc->cross_compiling) { bc->link_flags = str_lit("-target riscv64 "); } else { // NOTE: for targets other than darwin, we don't specify a `-target` link flag. diff --git a/src/gb/gb.h b/src/gb/gb.h index 38dabc9bd..0e65696e2 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -39,7 +39,7 @@ extern "C" { #endif #endif -#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) || defined(__aarch64__) +#if defined(_WIN64) || defined(__x86_64__) || defined(_M_X64) || defined(__64BIT__) || defined(__powerpc64__) || defined(__ppc64__) || defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) #ifndef GB_ARCH_64_BIT #define GB_ARCH_64_BIT 1 #endif @@ -144,6 +144,13 @@ extern "C" { #define GB_CACHE_LINE_SIZE 64 #endif +#elif defined(__riscv) + #ifndef GB_CPU_RISCV + #define GB_CPU_RISCV 1 + #endif + #ifndef GB_CACHE_LINE_SIZE + #define GB_CACHE_LINE_SIZE 64 + #endif #else #error Unknown CPU Type #endif @@ -2562,7 +2569,7 @@ gb_inline void *gb_memcopy(void *dest, void const *source, isize n) { void *dest_copy = dest; __asm__ __volatile__("rep movsb" : "+D"(dest_copy), "+S"(source), "+c"(n) : : "memory"); -#elif defined(GB_CPU_ARM) +#elif defined(GB_CPU_ARM) || defined(GB_CPU_RISCV) u8 *s = cast(u8 *)source; u8 *d = cast(u8 *)dest; for (isize i = 0; i < n; i++) { @@ -6267,6 +6274,12 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value)); return virtual_timer_value; } +#elif defined(__riscv) + gb_inline u64 gb_rdtsc(void) { + u64 result = 0; + __asm__ volatile("rdcycle %0" : "=r"(result)); + return result; + } #else #warning "gb_rdtsc not supported" gb_inline u64 gb_rdtsc(void) { return 0; } diff --git a/src/main.cpp b/src/main.cpp index 5131bdc21..34f3c832d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3252,6 +3252,12 @@ int main(int arg_count, char const **arg_ptr) { gb_printf_err("missing required target feature: \"%.*s\", enable it by setting a different -microarch or explicitly adding it through -target-features\n", LIT(disabled)); gb_exit(1); } + + // NOTE(laytan): some weird errors on LLVM 14 that LLVM 17 fixes. + if (LLVM_VERSION_MAJOR < 17) { + gb_printf_err("Invalid LLVM version %s, RISC-V targets require at least LLVM 17\n", LLVM_VERSION_STRING); + gb_exit(1); + } } if (build_context.show_debug_messages) { diff --git a/src/threading.cpp b/src/threading.cpp index e30a20a06..af8fd803c 100644 --- a/src/threading.cpp +++ b/src/threading.cpp @@ -529,6 +529,9 @@ gb_internal gb_inline void yield_thread(void) { _mm_pause(); #elif defined(GB_CPU_ARM) __asm__ volatile ("yield" : : : "memory"); +#elif defined(GB_CPU_RISCV) + // I guess? + __asm__ volatile ("nop" : : : "memory"); #else #error Unknown architecture #endif -- cgit v1.2.3 From 9871ad5fc8c0bd2a3ae63c5446d65dda832385b0 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Sun, 1 Sep 2024 17:50:50 -0400 Subject: Remove extra format item at end of `context` error message --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index cbfde4f4b..6ab87da09 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -10928,7 +10928,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case Token_context: { if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) { - error(node, "'context' is only allowed within procedures %p", c->curr_proc_decl); + error(node, "'context' is only allowed within procedures"); return kind; } if (unparen_expr(c->assignment_lhs_hint) == node) { -- cgit v1.2.3 From b24157738f4c85430038565465d9b2f38db4aa26 Mon Sep 17 00:00:00 2001 From: Dimension4 Date: Mon, 2 Sep 2024 23:40:13 +0200 Subject: Add missing help text for -build-mode:test --- src/main.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 34f3c832d..a03126caf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2268,6 +2268,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Sets the build mode."); print_usage_line(2, "Available options:"); print_usage_line(3, "-build-mode:exe Builds as an executable."); + print_usage_line(3, "-build-mode:test Builds as an executable that executes tests."); print_usage_line(3, "-build-mode:dll Builds as a dynamically linked library."); print_usage_line(3, "-build-mode:shared Builds as a dynamically linked library."); print_usage_line(3, "-build-mode:lib Builds as a statically linked library."); -- cgit v1.2.3 From dcf339517e5139a07cc45a2835567538b716d45c Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 18:47:08 +0200 Subject: make c vararg with any vs concrete type similar enough --- src/check_decl.cpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src') diff --git a/src/check_decl.cpp b/src/check_decl.cpp index c60084ec3..3b532a727 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -768,6 +768,19 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) { if (a->result_count != b->result_count) { return false; } + + if (a->c_vararg != b->c_vararg) { + return false; + } + + if (a->variadic != b->variadic) { + return false; + } + + if (a->variadic && a->variadic_index != b->variadic_index) { + return false; + } + for (isize i = 0; i < a->param_count; i++) { Type *x = core_type(a->params->Tuple.variables[i]->type); Type *y = core_type(b->params->Tuple.variables[i]->type); @@ -779,6 +792,17 @@ gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) { y = core_type(y->BitSet.underlying); } + // Allow a `#c_vararg args: ..any` with `#c_vararg args: ..foo`. + if (a->variadic && i == a->variadic_index) { + GB_ASSERT(x->kind == Type_Slice); + GB_ASSERT(y->kind == Type_Slice); + Type *x_elem = core_type(x->Slice.elem); + Type *y_elem = core_type(y->Slice.elem); + if (is_type_any(x_elem) || is_type_any(y_elem)) { + continue; + } + } + if (!signature_parameter_similar_enough(x, y)) { return false; } -- cgit v1.2.3 From 578de0977527a9cef7d1d77fab785363997b7cb6 Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 18:48:11 +0200 Subject: types with explicit custom alignment are identical to types with the same natural alignment --- src/types.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/types.cpp b/src/types.cpp index 21dd6ad39..63182f5c4 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -2810,8 +2810,14 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple case Type_Union: if (x->Union.variants.count == y->Union.variants.count && - x->Union.custom_align == y->Union.custom_align && x->Union.kind == y->Union.kind) { + + if (x->Union.custom_align != y->Union.custom_align) { + if (type_align_of(x) != type_align_of(y)) { + return false; + } + } + // NOTE(bill): zeroth variant is nullptr for_array(i, x->Union.variants) { if (!are_types_identical(x->Union.variants[i], y->Union.variants[i])) { @@ -2827,10 +2833,16 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple x->Struct.is_no_copy == y->Struct.is_no_copy && x->Struct.fields.count == y->Struct.fields.count && x->Struct.is_packed == y->Struct.is_packed && - x->Struct.custom_align == y->Struct.custom_align && x->Struct.soa_kind == y->Struct.soa_kind && x->Struct.soa_count == y->Struct.soa_count && are_types_identical(x->Struct.soa_elem, y->Struct.soa_elem)) { + + if (x->Struct.custom_align != y->Struct.custom_align) { + if (type_align_of(x) != type_align_of(y)) { + return false; + } + } + for_array(i, x->Struct.fields) { Entity *xf = x->Struct.fields[i]; Entity *yf = y->Struct.fields[i]; -- cgit v1.2.3 From 1a7c1d107a26df00bc6c9379178fccb55569b667 Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 22:18:55 +0200 Subject: set -rpath to \$ORIGIN and expect libraries next to executable just like Windows --- src/linker.cpp | 14 ++++++++------ src/parser.cpp | 14 -------------- 2 files changed, 8 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/linker.cpp b/src/linker.cpp index faca28932..25b9cfdc3 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -548,14 +548,12 @@ gb_internal i32 linker_stage(LinkerData *gen) { // available at runtime wherever the executable is run, so we make require those to be // local to the executable (unless the system collection is used, in which case we search // the system library paths for the library file). - if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o"))) { + if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { // static libs and object files, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - } else if (string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { - // dynamic lib, relative path to executable - // NOTE(vassvik): it is the user's responsibility to make sure the shared library files are visible - // at runtime to the executable - lib_str = gb_string_append_fmt(lib_str, " -l:\"%s/%.*s\" ", cwd, LIT(lib)); + + // NOTE(laytan): If .so, I think we can check for the existence of "$OUT_DIRECTORY/$lib" here and print an error telling the user to copy over the file, or we can even do the copy for them? + } else { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); @@ -643,6 +641,10 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } + // Set the rpath to the $ORIGIN (the path of the executable), + // so that dynamic libraries are looked for at that path. + gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (!build_context.no_crt) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); if (build_context.metrics.os == TargetOs_darwin) { diff --git a/src/parser.cpp b/src/parser.cpp index e3143dd33..88147d465 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5932,20 +5932,6 @@ gb_internal bool determine_path_from_string(BlockingMutex *file_mutex, Ast *node do_error(node, "Unknown library collection: '%.*s'", LIT(collection_name)); return false; } - } else { -#if !defined(GB_SYSTEM_WINDOWS) - // @NOTE(vassvik): foreign imports of shared libraries that are not in the system collection on - // linux/mac have to be local to the executable for consistency with shared libraries. - // Unix does not have a concept of "import library" for shared/dynamic libraries, - // so we need to pass the relative path to the linker, and add the current - // working directory of the exe to the library search paths. - // Static libraries can be linked directly with the full pathname - // - if (node->kind == Ast_ForeignImportDecl && (string_ends_with(file_str, str_lit(".so")) || string_contains_string(file_str, str_lit(".so.")))) { - *path = file_str; - return true; - } -#endif } if (is_package_name_reserved(file_str)) { -- cgit v1.2.3 From 0aa971207ba14f791b1cae3652e67e674710cf8e Mon Sep 17 00:00:00 2001 From: Laytan Date: Wed, 4 Sep 2024 22:38:19 +0200 Subject: add -no-rpath --- src/build_settings.cpp | 1 + src/linker.cpp | 8 +++++--- src/main.cpp | 9 +++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index fe0e478c7..fb10a25f6 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -411,6 +411,7 @@ struct BuildContext { bool no_dynamic_literals; bool no_output_files; bool no_crt; + bool no_rpath; bool no_entry_point; bool no_thread_local; bool use_lld; diff --git a/src/linker.cpp b/src/linker.cpp index 25b9cfdc3..cdda87697 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -641,9 +641,11 @@ gb_internal i32 linker_stage(LinkerData *gen) { } } - // Set the rpath to the $ORIGIN (the path of the executable), - // so that dynamic libraries are looked for at that path. - gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (!build_context.no_rpath) { + // Set the rpath to the $ORIGIN (the path of the executable), + // so that dynamic libraries are looked for at that path. + gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + } if (!build_context.no_crt) { platform_lib_str = gb_string_appendc(platform_lib_str, "-lm "); diff --git a/src/main.cpp b/src/main.cpp index a03126caf..d13065364 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -325,6 +325,7 @@ enum BuildFlagKind { BuildFlag_NoTypeAssert, BuildFlag_NoDynamicLiterals, BuildFlag_NoCRT, + BuildFlag_NoRPath, BuildFlag_NoEntryPoint, BuildFlag_UseLLD, BuildFlag_UseSeparateModules, @@ -532,6 +533,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_NoThreadLocal, str_lit("no-thread-local"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoDynamicLiterals, str_lit("no-dynamic-literals"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_NoCRT, str_lit("no-crt"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_NoRPath, str_lit("no-rpath"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test); add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build); add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build); @@ -1181,6 +1183,9 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_NoCRT: build_context.no_crt = true; break; + case BuildFlag_NoRPath: + build_context.no_rpath = true; + break; case BuildFlag_NoEntryPoint: build_context.no_entry_point = true; break; @@ -2310,6 +2315,10 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(2, "Disables automatic linking with the C Run Time."); print_usage_line(0, ""); + print_usage_line(1, "-no-rpath"); + print_usage_line(2, "Disables automatic addition of an rpath linked to the executable directory."); + print_usage_line(0, ""); + print_usage_line(1, "-no-thread-local"); print_usage_line(2, "Ignores @thread_local attribute, effectively treating the program as if it is single-threaded."); print_usage_line(0, ""); -- cgit v1.2.3 From 6778598bc648a4c605fb1b488185fad59668185a Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 4 Sep 2024 23:45:30 +0200 Subject: support the rpath changes on macos --- .github/workflows/ci.yml | 10 +++++----- src/linker.cpp | 12 ++++++------ 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e547959aa..421b5c586 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -257,16 +257,16 @@ jobs: run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross - name: Odin run - run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Odin run -debug - run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Normal Core library tests - run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Optimized Core library tests - run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath - name: Internals tests - run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" + run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static" -no-rpath diff --git a/src/linker.cpp b/src/linker.cpp index cdda87697..500fead69 100644 --- a/src/linker.cpp +++ b/src/linker.cpp @@ -549,11 +549,7 @@ gb_internal i32 linker_stage(LinkerData *gen) { // local to the executable (unless the system collection is used, in which case we search // the system library paths for the library file). if (string_ends_with(lib, str_lit(".a")) || string_ends_with(lib, str_lit(".o")) || string_ends_with(lib, str_lit(".so")) || string_contains_string(lib, str_lit(".so."))) { - // static libs and object files, absolute full path relative to the file in which the lib was imported from lib_str = gb_string_append_fmt(lib_str, " -l:\"%.*s\" ", LIT(lib)); - - // NOTE(laytan): If .so, I think we can check for the existence of "$OUT_DIRECTORY/$lib" here and print an error telling the user to copy over the file, or we can even do the copy for them? - } else { // dynamic or static system lib, just link regularly searching system library paths lib_str = gb_string_append_fmt(lib_str, " -l%.*s ", LIT(lib)); @@ -642,9 +638,13 @@ gb_internal i32 linker_stage(LinkerData *gen) { } if (!build_context.no_rpath) { - // Set the rpath to the $ORIGIN (the path of the executable), + // Set the rpath to the $ORIGIN/@loader_path (the path of the executable), // so that dynamic libraries are looked for at that path. - gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + if (build_context.metrics.os == TargetOs_darwin) { + link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,@loader_path "); + } else { + link_settings = gb_string_appendc(link_settings, "-Wl,-rpath,\\$ORIGIN "); + } } if (!build_context.no_crt) { -- cgit v1.2.3 From 490f8c15680ef62c4180940d8a41711a92cbdb0c Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 5 Sep 2024 15:55:55 +0200 Subject: add fixed point sign extend to 128 int deps --- src/check_builtin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 910e7ffdb..888aa074d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5203,6 +5203,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } + if (sz >= 64) { + if (is_type_unsigned(x.type)) { + add_package_dependency(c, "runtime", "umodti3", true); + add_package_dependency(c, "runtime", "udivti3", true); + } else { + add_package_dependency(c, "runtime", "modti3", true); + add_package_dependency(c, "runtime", "divti3", true); + } + } + operand->type = x.type; operand->mode = Addressing_Value; } -- cgit v1.2.3 From 0a08a65202ca40857e580036c561bcbf940a6870 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 7 Sep 2024 12:21:29 +0100 Subject: Simplify #row_major matrix and `matrix_flatten` behaviour --- src/llvm_backend_expr.cpp | 56 ++++++++++++++++++++++++++--------------------- src/types.cpp | 20 ++++++++++++----- 2 files changed, 45 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f6b9934ef..f20c52e88 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -705,31 +705,37 @@ gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type lbAddr res = lb_add_local_generated(p, type, true); - i64 row_count = mt->Matrix.row_count; - i64 column_count = mt->Matrix.column_count; - TEMPORARY_ALLOCATOR_GUARD(); - - auto srcs = array_make(temporary_allocator(), 0, row_count*column_count); - auto dsts = array_make(temporary_allocator(), 0, row_count*column_count); - - for (i64 j = 0; j < column_count; j++) { - for (i64 i = 0; i < row_count; i++) { - lbValue src = lb_emit_matrix_ev(p, m, i, j); - array_add(&srcs, src); - } - } - - for (i64 j = 0; j < column_count; j++) { - for (i64 i = 0; i < row_count; i++) { - lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); - array_add(&dsts, dst); - } - } - - GB_ASSERT(srcs.count == dsts.count); - for_array(i, srcs) { - lb_emit_store(p, dsts[i], srcs[i]); - } + GB_ASSERT(type_size_of(type) == type_size_of(m.type)); + + lbValue m_ptr = lb_address_from_load_or_generate_local(p, m); + lbValue n = lb_const_int(p->module, t_int, type_size_of(type)); + lb_mem_copy_non_overlapping(p, res.addr, m_ptr, n); + + // i64 row_count = mt->Matrix.row_count; + // i64 column_count = mt->Matrix.column_count; + // TEMPORARY_ALLOCATOR_GUARD(); + + // auto srcs = array_make(temporary_allocator(), 0, row_count*column_count); + // auto dsts = array_make(temporary_allocator(), 0, row_count*column_count); + + // for (i64 j = 0; j < column_count; j++) { + // for (i64 i = 0; i < row_count; i++) { + // lbValue src = lb_emit_matrix_ev(p, m, i, j); + // array_add(&srcs, src); + // } + // } + + // for (i64 j = 0; j < column_count; j++) { + // for (i64 i = 0; i < row_count; i++) { + // lbValue dst = lb_emit_array_epi(p, res.addr, i + j*row_count); + // array_add(&dsts, dst); + // } + // } + + // GB_ASSERT(srcs.count == dsts.count); + // for_array(i, srcs) { + // lb_emit_store(p, dsts[i], srcs[i]); + // } return lb_addr_load(p, res); } diff --git a/src/types.cpp b/src/types.cpp index 63182f5c4..a9a7d6dda 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -1474,6 +1474,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { Type *elem = t->Matrix.elem; i64 row_count = gb_max(t->Matrix.row_count, 1); + i64 column_count = gb_max(t->Matrix.column_count, 1); bool pop = type_path_push(tp, elem); if (tp->failure) { @@ -1491,7 +1492,7 @@ gb_internal i64 matrix_align_of(Type *t, struct TypePath *tp) { // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - i64 total_expected_size = row_count*t->Matrix.column_count*elem_size; + i64 total_expected_size = row_count*column_count*elem_size; // i64 min_alignment = prev_pow2(elem_align * row_count); i64 min_alignment = prev_pow2(total_expected_size); while (total_expected_size != 0 && (total_expected_size % min_alignment) != 0) { @@ -1523,12 +1524,15 @@ gb_internal i64 matrix_type_stride_in_bytes(Type *t, struct TypePath *tp) { i64 stride_in_bytes = 0; // NOTE(bill, 2021-10-25): The alignment strategy here is to have zero padding - // It would be better for performance to pad each column so that each column + // It would be better for performance to pad each column/row so that each column/row // could be maximally aligned but as a compromise, having no padding will be // beneficial to third libraries that assume no padding - i64 row_count = t->Matrix.row_count; - stride_in_bytes = elem_size*row_count; - + + if (t->Matrix.is_row_major) { + stride_in_bytes = elem_size*t->Matrix.column_count; + } else { + stride_in_bytes = elem_size*t->Matrix.row_count; + } t->Matrix.stride_in_bytes = stride_in_bytes; return stride_in_bytes; } @@ -4217,7 +4221,11 @@ gb_internal i64 type_size_of_internal(Type *t, TypePath *path) { case Type_Matrix: { i64 stride_in_bytes = matrix_type_stride_in_bytes(t, path); - return stride_in_bytes * t->Matrix.column_count; + if (t->Matrix.is_row_major) { + return stride_in_bytes * t->Matrix.row_count; + } else { + return stride_in_bytes * t->Matrix.column_count; + } } case Type_BitField: -- cgit v1.2.3 From 5a4746c3a077b8a815475a205aaa49233acc92d4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sat, 7 Sep 2024 17:41:16 +0100 Subject: Improve debug information for procedure types --- src/llvm_backend_debug.cpp | 55 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 5d90dccea..68e1efc1c 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -82,13 +82,36 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) parameter_count += 1; } } - LLVMMetadataRef *parameters = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, parameter_count); - unsigned param_index = 0; - if (type->Proc.result_count == 0) { - parameters[param_index++] = nullptr; - } else { - parameters[param_index++] = lb_debug_procedure_parameters(m, type->Proc.results); + auto parameters = array_make(permanent_allocator(), 0, type->Proc.param_count+type->Proc.result_count+2); + + array_add(¶meters, cast(LLVMMetadataRef)nullptr); + + bool return_is_tuple = false; + if (type->Proc.result_count != 0) { + Type *single_ret = reduce_tuple_to_single_type(type->Proc.results); + if (is_type_proc(single_ret)) { + single_ret = t_rawptr; + } + if (is_type_tuple(single_ret) && is_calling_convention_odin(type->Proc.calling_convention)) { + LLVMTypeRef actual = lb_type_internal_for_procedures_raw(m, type); + actual = LLVMGetReturnType(actual); + if (actual == nullptr) { + // results were passed as a single pointer + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } else { + LLVMTypeRef possible = lb_type(m, type->Proc.results); + if (possible == actual) { + // results were returned directly + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } else { + // resulsts were returned separately + return_is_tuple = true; + } + } + } else { + parameters[0] = lb_debug_procedure_parameters(m, single_ret); + } } LLVMMetadataRef file = nullptr; @@ -98,8 +121,22 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) if (e->kind != Entity_Variable) { continue; } - parameters[param_index] = lb_debug_procedure_parameters(m, e->type); - param_index += 1; + array_add(¶meters, lb_debug_procedure_parameters(m, e->type)); + } + + + if (return_is_tuple) { + Type *results = type->Proc.results; + GB_ASSERT(results != nullptr && results->kind == Type_Tuple); + isize count = results->Tuple.variables.count; + parameters[0] = lb_debug_procedure_parameters(m, results->Tuple.variables[count-1]->type); + for (isize i = 0; i < count-1; i++) { + array_add(¶meters, lb_debug_procedure_parameters(m, results->Tuple.variables[i]->type)); + } + } + + if (type->Proc.calling_convention == ProcCC_Odin) { + array_add(¶meters, lb_debug_type(m, t_context_ptr)); } LLVMDIFlags flags = LLVMDIFlagZero; @@ -107,7 +144,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) flags = LLVMDIFlagNoReturn; } - return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags); + return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters.data, cast(unsigned)parameters.count, flags); } gb_internal LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) { -- cgit v1.2.3 From 466a90010f7e4a19e496ba13f4c815d83d1f5288 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 7 Sep 2024 21:07:29 +0200 Subject: Fix #4211 --- src/build_settings.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index fe0e478c7..d8b63b947 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -2048,10 +2048,11 @@ gb_internal bool init_build_paths(String init_filename) { gbFile output_file_test; const char* output_file_name = (const char*)output_file.text; gbFileError output_test_err = gb_file_open_mode(&output_file_test, gbFileMode_Append | gbFileMode_Rw, output_file_name); - gb_file_close(&output_file_test); - gb_file_remove(output_file_name); - if (output_test_err != 0) { + if (output_test_err == 0) { + gb_file_close(&output_file_test); + gb_file_remove(output_file_name); + } else { String output_file = path_to_string(ha, bc->build_paths[BuildPath_Output]); defer (gb_free(ha, output_file.text)); gb_printf_err("No write permissions for output path: %.*s\n", LIT(output_file)); -- cgit v1.2.3 From dc767da12b0e03a6cd9ff20085565c95c06ef7bc Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Thu, 5 Sep 2024 21:17:40 +0200 Subject: Make tags use #+ syntax instead of //+ syntax so it no longer looks like a comment. Old style still works but is deprecated with a warning. Using unknown tags is now an error instead of a warning. There is a new token for #+ which consumes the whole line (or until it hits a comment). The tags are parsed like before. There are errors to tell you if you use something invalid in the pre-package-line block. --- src/parser.cpp | 155 +++++++++++++++++++++++++++++++++++++----------------- src/tokenizer.cpp | 15 ++++++ 2 files changed, 123 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index e3143dd33..03ed725c5 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -5337,6 +5337,12 @@ gb_internal Ast *parse_stmt(AstFile *f) { s = ast_empty_stmt(f, token); expect_semicolon(f); return s; + + case Token_FileTag: + // This is always an error because all valid file tags will have been processed in `parse_file` already. + // Any remaining file tags must be past the package line and thus invalid. + syntax_error(token, "Lines starting with #+ (file tags) are only allowed before the package line."); + return ast_bad_stmt(f, token, f->curr_token); } // Error correction statements @@ -6091,7 +6097,7 @@ gb_internal String build_tag_get_token(String s, String *out) { } gb_internal bool parse_build_tag(Token token_for_pos, String s) { - String const prefix = str_lit("+build"); + String const prefix = str_lit("build"); GB_ASSERT(string_starts_with(s, prefix)); s = string_trim_whitespace(substring(s, prefix.len, s.len)); @@ -6176,7 +6182,7 @@ gb_internal String vet_tag_get_token(String s, String *out) { gb_internal u64 parse_vet_tag(Token token_for_pos, String s) { - String const prefix = str_lit("+vet"); + String const prefix = str_lit("vet"); GB_ASSERT(string_starts_with(s, prefix)); s = string_trim_whitespace(substring(s, prefix.len, s.len)); @@ -6281,7 +6287,7 @@ gb_internal isize calc_decl_count(Ast *decl) { } gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s) { - String const prefix = str_lit("+build-project-name"); + String const prefix = str_lit("build-project-name"); GB_ASSERT(string_starts_with(s, prefix)); s = string_trim_whitespace(substring(s, prefix.len, s.len)); if (s.len == 0) { @@ -6325,6 +6331,48 @@ gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s return any_correct; } +gb_internal bool process_file_tag(const String &lc, const Token &tok, AstFile *f) { + if (string_starts_with(lc, str_lit("build-project-name"))) { + if (!parse_build_project_directory_tag(tok, lc)) { + return false; + } + } else if (string_starts_with(lc, str_lit("build"))) { + if (!parse_build_tag(tok, lc)) { + return false; + } + } else if (string_starts_with(lc, str_lit("vet"))) { + f->vet_flags = parse_vet_tag(tok, lc); + f->vet_flags_set = true; + } else if (string_starts_with(lc, str_lit("ignore"))) { + return false; + } else if (string_starts_with(lc, str_lit("private"))) { + f->flags |= AstFile_IsPrivatePkg; + String command = string_trim_starts_with(lc, str_lit("private ")); + command = string_trim_whitespace(command); + if (lc == "private") { + f->flags |= AstFile_IsPrivatePkg; + } else if (command == "package") { + f->flags |= AstFile_IsPrivatePkg; + } else if (command == "file") { + f->flags |= AstFile_IsPrivateFile; + } + } else if (lc == "lazy") { + if (build_context.ignore_lazy) { + // Ignore + } else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) { + // Ignore + } else { + f->flags |= AstFile_IsLazy; + } + } else if (lc == "no-instrumentation") { + f->flags |= AstFile_NoInstrumentation; + } else { + error(tok, "Unknown tag '%.*s'", LIT(lc)); + } + + return true; +} + gb_internal bool parse_file(Parser *p, AstFile *f) { if (f->tokens.count == 0) { return true; @@ -6337,15 +6385,38 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = dir_from_path(filepath); - if (f->curr_token.kind == Token_Comment) { - consume_comment_groups(f, f->prev_token); + + Array tags = array_make(ast_allocator(f)); + + bool has_first_invalid_pre_package_token = false; + Token first_invalid_pre_package_token; + + while (f->curr_token.kind != Token_package && f->curr_token.kind != Token_EOF) { + if (f->curr_token.kind == Token_Comment) { + consume_comment_groups(f, f->prev_token); + } else if (f->curr_token.kind == Token_FileTag) { + array_add(&tags, f->curr_token); + advance_token(f); + } else { + if (!has_first_invalid_pre_package_token) { + has_first_invalid_pre_package_token = true; + first_invalid_pre_package_token = f->curr_token; + } + + advance_token(f); + } } CommentGroup *docs = f->lead_comment; if (f->curr_token.kind != Token_package) { ERROR_BLOCK(); - syntax_error(f->curr_token, "Expected a package declaration at the beginning of the file"); + + // The while loop above scanned until it found the package token. If we never + // found one, then make this error appear on the first invalid token line. + Token t = has_first_invalid_pre_package_token ? first_invalid_pre_package_token : f->curr_token; + syntax_error(t, "Expected a package declaration at the beginning of the file"); + // IMPORTANT NOTE(bill): this is technically a race condition with the suggestion, but it's ony a suggession // so in practice is should be "fine" if (f->pkg && f->pkg->name != "") { @@ -6354,6 +6425,12 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { return false; } + // There was an OK package declaration. But there some invalid token was hit before the package declaration. + if (has_first_invalid_pre_package_token) { + syntax_error(first_invalid_pre_package_token, "There can only be lines starting with #+ or // before package declaration"); + return false; + } + f->package_token = expect_token(f, Token_package); if (f->package_token.kind != Token_package) { return false; @@ -6379,55 +6456,39 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; - if (!f->pkg->is_single_file && docs != nullptr && docs->list.count > 0) { - for (Token const &tok : docs->list) { - GB_ASSERT(tok.kind == Token_Comment); - String str = tok.string; - if (string_starts_with(str, str_lit("//"))) { - String lc = string_trim_whitespace(substring(str, 2, str.len)); - if (lc.len > 0 && lc[0] == '+') { - if (string_starts_with(lc, str_lit("+build-project-name"))) { - if (!parse_build_project_directory_tag(tok, lc)) { - return false; - } - } else if (string_starts_with(lc, str_lit("+build"))) { - if (!parse_build_tag(tok, lc)) { + if (!f->pkg->is_single_file) { + if (docs != nullptr && docs->list.count > 0) { + for (Token const &tok : docs->list) { + GB_ASSERT(tok.kind == Token_Comment); + String str = tok.string; + if (string_starts_with(str, str_lit("//"))) { + String lc = string_trim_whitespace(substring(str, 2, str.len)); + if (string_starts_with(lc, str_lit("+"))) { + syntax_warning(tok, "//+ is deprecated: Use #+ instead"); + String lt = substring(lc, 1, lc.len); + if (process_file_tag(lt, tok, f) == false) { return false; } - } else if (string_starts_with(lc, str_lit("+vet"))) { - f->vet_flags = parse_vet_tag(tok, lc); - f->vet_flags_set = true; - } else if (string_starts_with(lc, str_lit("+ignore"))) { - return false; - } else if (string_starts_with(lc, str_lit("+private"))) { - f->flags |= AstFile_IsPrivatePkg; - String command = string_trim_starts_with(lc, str_lit("+private ")); - command = string_trim_whitespace(command); - if (lc == "+private") { - f->flags |= AstFile_IsPrivatePkg; - } else if (command == "package") { - f->flags |= AstFile_IsPrivatePkg; - } else if (command == "file") { - f->flags |= AstFile_IsPrivateFile; - } - } else if (lc == "+lazy") { - if (build_context.ignore_lazy) { - // Ignore - } else if (f->pkg->kind == Package_Init && build_context.command_kind == Command_doc) { - // Ignore - } else { - f->flags |= AstFile_IsLazy; - } - } else if (lc == "+no-instrumentation") { - f->flags |= AstFile_NoInstrumentation; - } else { - warning(tok, "Ignoring unknown tag '%.*s'", LIT(lc)); } } } } + + for (Token const &tok : tags) { + GB_ASSERT(tok.kind == Token_FileTag); + String str = tok.string; + + if (string_starts_with(str, str_lit("#+"))) { + String lt = string_trim_whitespace(substring(str, 2, str.len)); + if (process_file_tag(lt, tok, f) == false) { + return false; + } + } + } } + array_free(&tags); + Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment); expect_semicolon(f); f->pkg_decl = pd; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 4425bee29..e9bad390e 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -2,6 +2,7 @@ TOKEN_KIND(Token_Invalid, "Invalid"), \ TOKEN_KIND(Token_EOF, "EOF"), \ TOKEN_KIND(Token_Comment, "Comment"), \ + TOKEN_KIND(Token_FileTag, "FileTag"), \ \ TOKEN_KIND(Token__LiteralBegin, ""), \ TOKEN_KIND(Token_Ident, "identifier"), \ @@ -939,6 +940,20 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { if (t->curr_rune == '!') { token->kind = Token_Comment; tokenizer_skip_line(t); + } else if (t->curr_rune == '+') { + token->kind = Token_FileTag; + + // Skip the line or until it ends or until we hit was is probably a comment. + // The parsing of tags happens in `parse_file`. + while (t->curr_rune != GB_RUNE_EOF) { + if (t->curr_rune == '\n') { + break; + } + if (t->curr_rune == '/') { + break; + } + advance_to_next_rune(t); + } } break; case '/': -- cgit v1.2.3 From 73e495434666b230e16ea7300c957ddc978e3e1a Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Sun, 8 Sep 2024 02:52:43 +0200 Subject: Better #+build tag error messages: Error when using more than one !notted operating system per build line. Error when using more than one operating system within a 'kind', such as writing #+build windows linux. --- src/parser.cpp | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 03ed725c5..7f2fa9b70 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6106,9 +6106,12 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { } bool any_correct = false; + bool any_notted_os_seen = false; + bool any_os_seen = false; while (s.len > 0) { bool this_kind_correct = true; + bool this_kind_os_seen = false; do { String p = string_trim_whitespace(build_tag_get_token(s, &s)); @@ -6133,12 +6136,30 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { continue; } + TargetOsKind os = get_target_os_from_string(p); TargetArchKind arch = get_target_arch_from_string(p); if (os != TargetOs_Invalid) { + // Catches cases where you have multiple !notted operating systems on a line. This never does what you think since + // you need a new build line to get a logical AND. + if (any_notted_os_seen && is_notted) { + syntax_error(token_for_pos, "Invalid build tag: Use a separate '#+build' line for each platform that has '!' in front."); + break; + } + + // Catches 'windows linux', which is an impossible combination. + if (this_kind_os_seen) { + syntax_error(token_for_pos, "Invalid build tag: Missing ',' before '%.*s'. Format: '#+build linux, windows, darwin' or '#+build linux amd64, darwin, windows i386'", LIT(p)); + break; + } + + this_kind_os_seen = true; + any_os_seen = true; + GB_ASSERT(arch == TargetArch_Invalid); if (is_notted) { this_kind_correct = this_kind_correct && (os != build_context.metrics.os); + any_notted_os_seen = true; } else { this_kind_correct = this_kind_correct && (os == build_context.metrics.os); } @@ -6427,7 +6448,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { // There was an OK package declaration. But there some invalid token was hit before the package declaration. if (has_first_invalid_pre_package_token) { - syntax_error(first_invalid_pre_package_token, "There can only be lines starting with #+ or // before package declaration"); + syntax_error(first_invalid_pre_package_token, "There can only be lines starting with '#+' or '//' before package declaration"); return false; } @@ -6464,7 +6485,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (string_starts_with(str, str_lit("//"))) { String lc = string_trim_whitespace(substring(str, 2, str.len)); if (string_starts_with(lc, str_lit("+"))) { - syntax_warning(tok, "//+ is deprecated: Use #+ instead"); + syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); String lt = substring(lc, 1, lc.len); if (process_file_tag(lt, tok, f) == false) { return false; -- cgit v1.2.3 From 0dddd2b97e4ad526fa5e33d270301c1b807e520e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Sep 2024 14:39:53 +0100 Subject: Add internal flag `-internal-fast-isel` --- src/build_settings.cpp | 1 + src/llvm_backend.cpp | 5 +++++ src/main.cpp | 5 +++++ 3 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index d8b63b947..e86224665 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -430,6 +430,7 @@ struct BuildContext { bool json_errors; bool has_ansi_terminal_colours; + bool fast_isel; bool ignore_lazy; bool ignore_llvm_build; bool ignore_panic; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index f852636a6..19b5ced67 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3081,6 +3081,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { lbModule *m = entry.value; m->target_machine = target_machine; LLVMSetModuleDataLayout(m->mod, LLVMCreateTargetDataLayout(target_machine)); + + if (build_context.fast_isel) { + LLVMSetTargetMachineFastISel(m->target_machine, true); + } + array_add(&target_machines, target_machine); } diff --git a/src/main.cpp b/src/main.cpp index a03126caf..0a84b2f97 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -389,6 +389,7 @@ enum BuildFlagKind { BuildFlag_PrintLinkerFlags, // internal use only + BuildFlag_InternalFastISel, BuildFlag_InternalIgnoreLazy, BuildFlag_InternalIgnoreLLVMBuild, BuildFlag_InternalIgnorePanic, @@ -594,6 +595,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_PrintLinkerFlags, str_lit("print-linker-flags"), BuildFlagParam_None, Command_build); + add_flag(&build_flags, BuildFlag_InternalFastISel, str_lit("internal-fast-isel"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_InternalIgnorePanic, str_lit("internal-ignore-panic"), BuildFlagParam_None, Command_all); @@ -1408,6 +1410,9 @@ gb_internal bool parse_build_flags(Array args) { build_context.print_linker_flags = true; break; + case BuildFlag_InternalFastISel: + build_context.fast_isel = true; + break; case BuildFlag_InternalIgnoreLazy: build_context.ignore_lazy = true; break; -- cgit v1.2.3 From a25a9e6ebe58510cfac20e1187f41a01ec3ec2b2 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Mon, 9 Sep 2024 14:47:44 +0100 Subject: Check for `LLVM_VERSION_MAJOR >= 18` --- src/llvm_backend.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 19b5ced67..01ded321e 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -3082,9 +3082,11 @@ gb_internal bool lb_generate_code(lbGenerator *gen) { m->target_machine = target_machine; LLVMSetModuleDataLayout(m->mod, LLVMCreateTargetDataLayout(target_machine)); + #if LLVM_VERSION_MAJOR >= 18 if (build_context.fast_isel) { LLVMSetTargetMachineFastISel(m->target_machine, true); } + #endif array_add(&target_machines, target_machine); } -- cgit v1.2.3 From 3637dcbd04d328a110f0626171f2d49f7a96b09b Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 9 Sep 2024 21:03:23 +0200 Subject: Simplified error messages in parse_build_tag, removed the idea of making multiple notted operating systems since it was misinformed. --- src/parser.cpp | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 7f2fa9b70..2df876d73 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6106,12 +6106,13 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { } bool any_correct = false; - bool any_notted_os_seen = false; - bool any_os_seen = false; while (s.len > 0) { bool this_kind_correct = true; + bool this_kind_os_seen = false; + bool this_kind_arch_seen = false; + int num_tokens = 0; do { String p = string_trim_whitespace(build_tag_get_token(s, &s)); @@ -6136,34 +6137,29 @@ gb_internal bool parse_build_tag(Token token_for_pos, String s) { continue; } - TargetOsKind os = get_target_os_from_string(p); TargetArchKind arch = get_target_arch_from_string(p); - if (os != TargetOs_Invalid) { - // Catches cases where you have multiple !notted operating systems on a line. This never does what you think since - // you need a new build line to get a logical AND. - if (any_notted_os_seen && is_notted) { - syntax_error(token_for_pos, "Invalid build tag: Use a separate '#+build' line for each platform that has '!' in front."); - break; - } + num_tokens += 1; - // Catches 'windows linux', which is an impossible combination. - if (this_kind_os_seen) { - syntax_error(token_for_pos, "Invalid build tag: Missing ',' before '%.*s'. Format: '#+build linux, windows, darwin' or '#+build linux amd64, darwin, windows i386'", LIT(p)); - break; - } + // Catches 'windows linux', which is an impossible combination. + // Also catches usage of more than two things within a comma separated group. + if (num_tokens > 2 || (this_kind_os_seen && os != TargetOs_Invalid) || (this_kind_arch_seen && arch != TargetArch_Invalid)) { + syntax_error(token_for_pos, "Invalid build tag: Missing ',' before '%.*s'. Format: '#+build linux, windows amd64, darwin'", LIT(p)); + break; + } + if (os != TargetOs_Invalid) { this_kind_os_seen = true; - any_os_seen = true; GB_ASSERT(arch == TargetArch_Invalid); if (is_notted) { this_kind_correct = this_kind_correct && (os != build_context.metrics.os); - any_notted_os_seen = true; } else { this_kind_correct = this_kind_correct && (os == build_context.metrics.os); } } else if (arch != TargetArch_Invalid) { + this_kind_arch_seen = true; + if (is_notted) { this_kind_correct = this_kind_correct && (arch != build_context.metrics.arch); } else { -- cgit v1.2.3 From 957cd64699f1f8f1d1f689025c708aebc3c32476 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 9 Sep 2024 21:06:43 +0200 Subject: Rename process_file_tag -> parse_file_tag --- src/parser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 2df876d73..3634da7fa 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6348,7 +6348,7 @@ gb_internal bool parse_build_project_directory_tag(Token token_for_pos, String s return any_correct; } -gb_internal bool process_file_tag(const String &lc, const Token &tok, AstFile *f) { +gb_internal bool parse_file_tag(const String &lc, const Token &tok, AstFile *f) { if (string_starts_with(lc, str_lit("build-project-name"))) { if (!parse_build_project_directory_tag(tok, lc)) { return false; @@ -6483,7 +6483,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (string_starts_with(lc, str_lit("+"))) { syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); String lt = substring(lc, 1, lc.len); - if (process_file_tag(lt, tok, f) == false) { + if (parse_file_tag(lt, tok, f) == false) { return false; } } @@ -6497,7 +6497,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (string_starts_with(str, str_lit("#+"))) { String lt = string_trim_whitespace(substring(str, 2, str.len)); - if (process_file_tag(lt, tok, f) == false) { + if (parse_file_tag(lt, tok, f) == false) { return false; } } -- cgit v1.2.3 From cc724ff5d2ecc358f36c6c0ed3a25db6373ac95c Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 9 Sep 2024 21:13:39 +0200 Subject: Made error handling code in parse_file clearer. --- src/parser.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 3634da7fa..aaaf02cee 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6405,8 +6405,8 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { Array tags = array_make(ast_allocator(f)); - bool has_first_invalid_pre_package_token = false; - Token first_invalid_pre_package_token; + bool first_invalid_token_set = false; + Token first_invalid_token = {}; while (f->curr_token.kind != Token_package && f->curr_token.kind != Token_EOF) { if (f->curr_token.kind == Token_Comment) { @@ -6415,9 +6415,9 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { array_add(&tags, f->curr_token); advance_token(f); } else { - if (!has_first_invalid_pre_package_token) { - has_first_invalid_pre_package_token = true; - first_invalid_pre_package_token = f->curr_token; + if (!first_invalid_token_set) { + first_invalid_token_set = true; + first_invalid_token = f->curr_token; } advance_token(f); @@ -6431,7 +6431,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { // The while loop above scanned until it found the package token. If we never // found one, then make this error appear on the first invalid token line. - Token t = has_first_invalid_pre_package_token ? first_invalid_pre_package_token : f->curr_token; + Token t = first_invalid_token_set ? first_invalid_token : f->curr_token; syntax_error(t, "Expected a package declaration at the beginning of the file"); // IMPORTANT NOTE(bill): this is technically a race condition with the suggestion, but it's ony a suggession @@ -6443,8 +6443,8 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } // There was an OK package declaration. But there some invalid token was hit before the package declaration. - if (has_first_invalid_pre_package_token) { - syntax_error(first_invalid_pre_package_token, "There can only be lines starting with '#+' or '//' before package declaration"); + if (first_invalid_token_set) { + syntax_error(first_invalid_token, "There can only be lines starting with '#+' or '//' before package declaration"); return false; } @@ -6481,7 +6481,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (string_starts_with(str, str_lit("//"))) { String lc = string_trim_whitespace(substring(str, 2, str.len)); if (string_starts_with(lc, str_lit("+"))) { - syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); + //syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); String lt = substring(lc, 1, lc.len); if (parse_file_tag(lt, tok, f) == false) { return false; -- cgit v1.2.3 From 580f0599cde713f5e1c7495174821abe6dc4a2a1 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 9 Sep 2024 21:24:41 +0200 Subject: parse_file: Removed some nesting and removed probable incorrect safety check. --- src/parser.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index aaaf02cee..c2a9ff138 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6452,14 +6452,6 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { if (f->package_token.kind != Token_package) { return false; } - if (docs != nullptr) { - TokenPos end = token_pos_end(docs->list[docs->list.count-1]); - if (end.line == f->package_token.pos.line || end.line+1 == f->package_token.pos.line) { - // Okay - } else { - docs = nullptr; - } - } Token package_name = expect_token_after(f, Token_Ident, "package"); if (package_name.kind == Token_Ident) { @@ -6478,14 +6470,17 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { for (Token const &tok : docs->list) { GB_ASSERT(tok.kind == Token_Comment); String str = tok.string; - if (string_starts_with(str, str_lit("//"))) { - String lc = string_trim_whitespace(substring(str, 2, str.len)); - if (string_starts_with(lc, str_lit("+"))) { - //syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); - String lt = substring(lc, 1, lc.len); - if (parse_file_tag(lt, tok, f) == false) { - return false; - } + + if (!string_starts_with(str, str_lit("//"))) { + continue; + } + + String lc = string_trim_whitespace(substring(str, 2, str.len)); + if (string_starts_with(lc, str_lit("+"))) { + syntax_warning(tok, "'//+' is deprecated: Use '#+' instead"); + String lt = substring(lc, 1, lc.len); + if (parse_file_tag(lt, tok, f) == false) { + return false; } } } -- cgit v1.2.3 From f9de8fdaba12746b9c458e916ba6bb9d7c5b7aa7 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Mon, 9 Sep 2024 21:51:29 +0200 Subject: Documentation typo fix in tokenizer. --- src/tokenizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index e9bad390e..53f6135d0 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -943,7 +943,7 @@ gb_internal void tokenizer_get_token(Tokenizer *t, Token *token, int repeat=0) { } else if (t->curr_rune == '+') { token->kind = Token_FileTag; - // Skip the line or until it ends or until we hit was is probably a comment. + // Skip until end of line or until we hit what is probably a comment. // The parsing of tags happens in `parse_file`. while (t->curr_rune != GB_RUNE_EOF) { if (t->curr_rune == '\n') { -- cgit v1.2.3 From 564c7821c59c0ea8244f281587920e42ce701009 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Tue, 10 Sep 2024 04:27:16 +0200 Subject: Allow ExactValue_Invalid in assert. Fixes #4225 --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6ab87da09..27ba2448e 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3615,7 +3615,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (is_type_integer(src_t) && is_type_integer(dst_t)) { if (types_have_same_internal_endian(src_t, dst_t)) { ExactValue src_v = exact_value_to_integer(o->value); - GB_ASSERT(src_v.kind == ExactValue_Integer); + GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid); BigInt v = src_v.value_integer; BigInt smax = {}; -- cgit v1.2.3 From 9b06ea5bfd57c386194438a6a1afd34aa18bb229 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Sep 2024 12:01:01 +0100 Subject: Fix #4229 for edge case `os.Error`/`os.Errno` legacy bodge --- src/check_expr.cpp | 2 +- src/llvm_backend_expr.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 27ba2448e..45c3e9a3c 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4602,7 +4602,7 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar (operand->value.kind == ExactValue_Integer || operand->value.kind == ExactValue_Float)) { operand->mode = Addressing_Value; - target_type = t_untyped_nil; + // target_type = t_untyped_nil; operand->value = empty_exact_value; update_untyped_expr_value(c, operand->expr, operand->value); break; diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index f20c52e88..58467db2e 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -3451,8 +3451,14 @@ gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) { switch (expr->kind) { case_ast_node(bl, BasicLit, expr); + if (type != nullptr && type->Named.name == "Error") { + Entity *e = type->Named.type_name; + if (e->pkg && e->pkg->name == "os") { + return lb_const_nil(p->module, type); + } + } TokenPos pos = bl->token.pos; - GB_PANIC("Non-constant basic literal %s - %.*s", token_pos_to_string(pos), LIT(token_strings[bl->token.kind])); + GB_PANIC("Non-constant basic literal %s - %.*s (%s)", token_pos_to_string(pos), LIT(token_strings[bl->token.kind]), type_to_string(type)); case_end; case_ast_node(bd, BasicDirective, expr); -- cgit v1.2.3 From 2938655a3d8801d1327b0076812edcf357d760df Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 11 Sep 2024 07:07:09 -0400 Subject: Fix CPU count detection in FreeBSD & NetBSD --- core/os/os_freebsd.odin | 2 +- core/os/os_netbsd.odin | 2 +- src/gb/gb.h | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/core/os/os_freebsd.odin b/core/os/os_freebsd.odin index c05a06129..241f42c0b 100644 --- a/core/os/os_freebsd.odin +++ b/core/os/os_freebsd.odin @@ -920,7 +920,7 @@ get_page_size :: proc() -> int { _processor_core_count :: proc() -> int { count : int = 0 count_size := size_of(count) - if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 { + if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 { if count > 0 { return count } diff --git a/core/os/os_netbsd.odin b/core/os/os_netbsd.odin index a56c0b784..ba9b40fc3 100644 --- a/core/os/os_netbsd.odin +++ b/core/os/os_netbsd.odin @@ -978,7 +978,7 @@ get_page_size :: proc() -> int { _processor_core_count :: proc() -> int { count : int = 0 count_size := size_of(count) - if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 { + if _sysctlbyname("hw.ncpu", &count, &count_size, nil, 0) == 0 { if count > 0 { return count } diff --git a/src/gb/gb.h b/src/gb/gb.h index 0e65696e2..1fef4b4f5 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -3195,11 +3195,11 @@ void gb_affinity_init(gbAffinity *a) { a->core_count = 1; a->threads_per_core = 1; - if (sysctlbyname("hw.logicalcpu", &count, &count_size, NULL, 0) == 0) { + if (sysctlbyname("kern.smp.cpus", &count, &count_size, NULL, 0) == 0) { if (count > 0) { a->thread_count = count; // Get # of physical cores - if (sysctlbyname("hw.physicalcpu", &count, &count_size, NULL, 0) == 0) { + if (sysctlbyname("kern.smp.cores", &count, &count_size, NULL, 0) == 0) { if (count > 0) { a->core_count = count; a->threads_per_core = a->thread_count / count; @@ -3210,6 +3210,14 @@ void gb_affinity_init(gbAffinity *a) { } } } + } else if (sysctlbyname("hw.ncpu", &count, &count_size, NULL, 0) == 0) { + // SMP disabled or unavailable. + if (count > 0) { + a->is_accurate = true; + a->thread_count = count; + a->core_count = count; + a->threads_per_core = 1; + } } } -- cgit v1.2.3 From 1025b9e6c067edfbb43f8119ec68d5684d1b18ca Mon Sep 17 00:00:00 2001 From: InKryption Date: Wed, 11 Sep 2024 18:56:49 +0200 Subject: Enable -out: for doc subcommand The logic for writing the .odin-doc file to the value assigned to out_filepath already exists, this just enables it on the CLI frontend. --- src/main.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 3f458364f..06c200442 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -509,7 +509,7 @@ gb_internal bool parse_build_flags(Array args) { auto build_flags = array_make(heap_allocator(), 0, BuildFlag_COUNT); add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all); add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check); - add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test); + add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test | Command_doc); add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ShowMoreTimings, str_lit("show-more-timings"), BuildFlagParam_None, Command__does_check); @@ -2164,6 +2164,12 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-doc-format"); print_usage_line(2, "Generates documentation as the .odin-doc format (useful for external tooling)."); print_usage_line(0, ""); + + print_usage_line(1, "-out:"); + print_usage_line(2, "Sets the base name of the resultig .odin-doc file."); + print_usage_line(2, "The extension can be optionally included; the resulting file will always have an extension of '.odin-doc'."); + print_usage_line(2, "Example: -out:foo"); + print_usage_line(0, ""); } if (run_or_build) { -- cgit v1.2.3 From 3b22c0854c0a64ae27ca43f59b5f6cdffcae56ab Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Wed, 11 Sep 2024 22:45:16 +0200 Subject: fix some LLVM assertions --- src/llvm_backend_const.cpp | 4 ++-- src/llvm_backend_type.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index 6a6b119aa..754bbfca2 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -154,7 +154,7 @@ gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValue GB_ASSERT(value_count_ == bt->Struct.fields.count); auto field_remapping = lb_get_struct_remapping(m, t); - unsigned values_with_padding_count = LLVMCountStructElementTypes(struct_type); + unsigned values_with_padding_count = elem_count; LLVMValueRef *values_with_padding = gb_alloc_array(permanent_allocator(), LLVMValueRef, values_with_padding_count); for (unsigned i = 0; i < value_count; i++) { @@ -722,7 +722,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bo } case ExactValue_Integer: - if (is_type_pointer(type) || is_type_multi_pointer(type)) { + if (is_type_pointer(type) || is_type_multi_pointer(type) || is_type_proc(type)) { LLVMTypeRef t = lb_type(m, original_type); LLVMValueRef i = lb_big_int_to_llvm(m, t_uintptr, &value.value_integer); res.value = LLVMConstIntToPtr(i, t); diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp index 638170bfc..9d4505bb0 100644 --- a/src/llvm_backend_type.cpp +++ b/src/llvm_backend_type.cpp @@ -826,7 +826,7 @@ gb_internal void lb_setup_type_info_data_giant_array(lbModule *m, i64 global_typ if (t->Struct.soa_kind != StructSoa_None) { - Type *kind_type = get_struct_field_type(tag_type, 10); + Type *kind_type = get_struct_field_type(tag_type, 7); lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind)); LLVMValueRef soa_type = get_type_info_ptr(m, t->Struct.soa_elem); -- cgit v1.2.3 From 27ed10746db72fd3e5ba9aea922cb064aa3f8995 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 11 Sep 2024 23:08:38 +0100 Subject: Allow `transmute(Bit_Set)~T(0)` --- src/check_expr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 45c3e9a3c..760551a72 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3612,7 +3612,8 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (are_types_identical(src_bt, dst_bt)) { return true; } - if (is_type_integer(src_t) && is_type_integer(dst_t)) { + if ((is_type_integer(src_t) && is_type_integer(dst_t)) || + is_type_integer(src_t) && is_type_bit_set(dst_t)) { if (types_have_same_internal_endian(src_t, dst_t)) { ExactValue src_v = exact_value_to_integer(o->value); GB_ASSERT(src_v.kind == ExactValue_Integer || src_v.kind == ExactValue_Invalid); -- cgit v1.2.3 From 387f56634d337152d7aba07b740cf5821db9e67f Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 12 Sep 2024 02:16:04 +0200 Subject: fix reuse of slice for varargs with poly types --- src/check_expr.cpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 760551a72..f1bf86992 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6204,22 +6204,6 @@ 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 parameters with the backing array - if (c->decl) { - bool found = false; - 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->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count}); - } - } - } else { dummy_argument_count += 1; o.type = t_untyped_nil; @@ -6413,6 +6397,23 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A } score += eval_param_and_score(c, o, t, err, true, var_entity, show_error); } + + if (!vari_expand && variadic_operands.count != 0) { + // NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array + if (c->decl) { + bool found = false; + for (auto &vr : c->decl->variadic_reuses) { + if (are_types_identical(slice, vr.slice_type)) { + vr.max_count = gb_max(vr.max_count, variadic_operands.count); + found = true; + break; + } + } + if (!found) { + array_add(&c->decl->variadic_reuses, VariadicReuseData{slice, variadic_operands.count}); + } + } + } } if (data) { -- cgit v1.2.3 From 3166c7bef921dcf48ac233738ec2064362bcbbd8 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 Sep 2024 10:07:09 +0100 Subject: Add `Suggested Example` for using an inline procedure which enables a target feature --- src/check_expr.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index f1bf86992..7f82fb58a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8087,7 +8087,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c GB_ASSERT(c->curr_proc_decl->entity->type->kind == Type_Proc); String scope_features = c->curr_proc_decl->entity->type->Proc.enable_target_feature; if (!check_target_feature_is_superset_of(scope_features, pt->Proc.enable_target_feature, &invalid)) { + ERROR_BLOCK(); error(call, "Inlined procedure enables target feature '%.*s', this requires the calling procedure to at least enable the same feature", LIT(invalid)); + + error_line("\tSuggested Example: @(enable_target_feature=\"%.*s\")\n", LIT(invalid)); } } } -- cgit v1.2.3 From 8b84b9a4a26d7f2fb07a7e5dcd49b678d1c9be91 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Sat, 14 Sep 2024 14:32:46 +0200 Subject: Docs are generated as expected again. --- src/parser.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 51da21e9d..523dad8b8 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6388,9 +6388,13 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { String filepath = f->tokenizer.fullpath; String base_dir = dir_from_path(filepath); + if (f->curr_token.kind == Token_Comment) { + consume_comment_groups(f, f->prev_token); + } - Array tags = array_make(ast_allocator(f)); + CommentGroup *docs = f->lead_comment; + Array tags = array_make(temporary_allocator()); bool first_invalid_token_set = false; Token first_invalid_token = {}; @@ -6410,8 +6414,6 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } } - CommentGroup *docs = f->lead_comment; - if (f->curr_token.kind != Token_package) { ERROR_BLOCK(); @@ -6451,6 +6453,8 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } f->package_name = package_name.string; + // TODO: Shouldn't single file only matter for build tags? no-instrumentation for example + // should be respected even when in single file mode. if (!f->pkg->is_single_file) { if (docs != nullptr && docs->list.count > 0) { for (Token const &tok : docs->list) { @@ -6485,8 +6489,6 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { } } - array_free(&tags); - Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment); expect_semicolon(f); f->pkg_decl = pd; -- cgit v1.2.3 From c24e18bf1063cd86c200d51d585059f8aa099615 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Sat, 14 Sep 2024 14:36:33 +0200 Subject: Fix incorrect syntax error in parse_file --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/parser.cpp b/src/parser.cpp index 523dad8b8..22d92e87b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -6432,7 +6432,7 @@ gb_internal bool parse_file(Parser *p, AstFile *f) { // There was an OK package declaration. But there some invalid token was hit before the package declaration. if (first_invalid_token_set) { - syntax_error(first_invalid_token, "There can only be lines starting with '#+' or '//' before package declaration"); + syntax_error(first_invalid_token, "Expected only comments or lines starting with '#+' before the package declaration"); return false; } -- cgit v1.2.3 From 4f3f256375e3ae7e9ac0420fa41a7e6cead4ad72 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 14 Sep 2024 15:52:37 +0200 Subject: improve bit field debug info --- src/llvm_backend_debug.cpp | 80 +++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 36 deletions(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index 68e1efc1c..bb6a1ba4f 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -552,6 +552,48 @@ gb_internal LLVMMetadataRef lb_debug_bitset(lbModule *m, Type *type, String name return final_decl; } +gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) { + Type *bt = base_type(type); + GB_ASSERT(bt->kind == Type_BitField); + + lb_debug_file_line(m, bt->BitField.node, &file, &line); + + u64 size_in_bits = 8*type_size_of(bt); + u32 align_in_bits = 8*cast(u32)type_align_of(bt); + + unsigned element_count = cast(unsigned)bt->BitField.fields.count; + LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); + + u64 offset_in_bits = 0; + for (unsigned i = 0; i < element_count; i++) { + Entity *f = bt->BitField.fields[i]; + u8 bit_size = bt->BitField.bit_sizes[i]; + GB_ASSERT(f->kind == Entity_Variable); + String name = f->token.string; + elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line, + bit_size, offset_in_bits, offset_in_bits, + LLVMDIFlagZero, lb_debug_type(m, f->type) + ); + + offset_in_bits += bit_size; + } + + LLVMMetadataRef final_decl = LLVMDIBuilderCreateStructType( + m->debug_builder, scope, + cast(char const *)name.text, cast(size_t)name.len, + file, line, + size_in_bits, align_in_bits, + LLVMDIFlagZero, + nullptr, + elements, element_count, + 0, + nullptr, + "", 0 + ); + lb_set_llvm_metadata(m, type, final_decl); + return final_decl; +} + gb_internal LLVMMetadataRef lb_debug_enum(lbModule *m, Type *type, String name, LLVMMetadataRef scope, LLVMMetadataRef file, unsigned line) { Type *bt = base_type(type); GB_ASSERT(bt->kind == Type_Enum); @@ -816,6 +858,7 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { case Type_Union: return lb_debug_union( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); case Type_BitSet: return lb_debug_bitset( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); case Type_Enum: return lb_debug_enum( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); + case Type_BitField: return lb_debug_bitfield( m, type, make_string_c(type_to_string(type, temporary_allocator())), nullptr, nullptr, 0); case Type_Tuple: if (type->Tuple.variables.count == 1) { @@ -901,42 +944,6 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) { lb_debug_type(m, type->Matrix.elem), subscripts, gb_count_of(subscripts)); } - - case Type_BitField: { - LLVMMetadataRef parent_scope = nullptr; - LLVMMetadataRef scope = nullptr; - LLVMMetadataRef file = nullptr; - unsigned line = 0; - u64 size_in_bits = 8*cast(u64)type_size_of(type); - u32 align_in_bits = 8*cast(u32)type_align_of(type); - LLVMDIFlags flags = LLVMDIFlagZero; - - unsigned element_count = cast(unsigned)type->BitField.fields.count; - LLVMMetadataRef *elements = gb_alloc_array(permanent_allocator(), LLVMMetadataRef, element_count); - - u64 offset_in_bits = 0; - for (unsigned i = 0; i < element_count; i++) { - Entity *f = type->BitField.fields[i]; - u8 bit_size = type->BitField.bit_sizes[i]; - GB_ASSERT(f->kind == Entity_Variable); - String name = f->token.string; - unsigned field_line = 0; - LLVMDIFlags field_flags = LLVMDIFlagZero; - elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, field_line, - bit_size, offset_in_bits, offset_in_bits, - field_flags, lb_debug_type(m, f->type) - ); - - offset_in_bits += bit_size; - } - - - return LLVMDIBuilderCreateStructType(m->debug_builder, parent_scope, "", 0, file, line, - size_in_bits, align_in_bits, flags, - nullptr, elements, element_count, 0, nullptr, - "", 0 - ); - } } GB_PANIC("Invalid type %s", type_to_string(type)); @@ -1022,6 +1029,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) { case Type_Union: return lb_debug_union(m, type, name, scope, file, line); case Type_BitSet: return lb_debug_bitset(m, type, name, scope, file, line); case Type_Enum: return lb_debug_enum(m, type, name, scope, file, line); + case Type_BitField: return lb_debug_bitfield(m, type, name, scope, file, line); } } -- cgit v1.2.3 From 603efa860a5631f1708f6761d753146b6d47b4ba Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sat, 14 Sep 2024 21:43:25 +0200 Subject: add '#caller_expression' --- base/runtime/core_builtin.odin | 4 +-- core/odin/parser/parser.odin | 10 +++++++ core/testing/testing.odin | 12 +++++--- src/check_builtin.cpp | 16 +++++++++++ src/check_expr.cpp | 7 ++++- src/check_type.cpp | 32 ++++++++++++++++++++++ src/entity.cpp | 1 + src/llvm_backend.hpp | 2 +- src/llvm_backend_proc.cpp | 62 ++++++++++++++++++++++++++++++++++++++---- 9 files changed, 133 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/base/runtime/core_builtin.odin b/base/runtime/core_builtin.odin index 8157afe09..67d249d11 100644 --- a/base/runtime/core_builtin.odin +++ b/base/runtime/core_builtin.odin @@ -913,7 +913,7 @@ card :: proc "contextless" (s: $S/bit_set[$E; $U]) -> int { @builtin @(disabled=ODIN_DISABLE_ASSERT) -assert :: proc(condition: bool, message := "", loc := #caller_location) { +assert :: proc(condition: bool, message := #caller_expression(condition), loc := #caller_location) { if !condition { // NOTE(bill): This is wrapped in a procedure call // to improve performance to make the CPU not @@ -952,7 +952,7 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! { @builtin @(disabled=ODIN_DISABLE_ASSERT) -assert_contextless :: proc "contextless" (condition: bool, message := "", loc := #caller_location) { +assert_contextless :: proc "contextless" (condition: bool, message := #caller_expression(condition), loc := #caller_location) { if !condition { // NOTE(bill): This is wrapped in a procedure call // to improve performance to make the CPU not diff --git a/core/odin/parser/parser.odin b/core/odin/parser/parser.odin index aab59c29d..6f42c17db 100644 --- a/core/odin/parser/parser.odin +++ b/core/odin/parser/parser.odin @@ -2277,6 +2277,16 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr { bd.name = name.text return bd + case "caller_expression": + bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) + bd.tok = tok + bd.name = name.text + + if peek_token_kind(p, .Open_Paren) { + return parse_call_expr(p, bd) + } + return bd + case "location", "exists", "load", "load_directory", "load_hash", "hash", "assert", "panic", "defined", "config": bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) bd.tok = tok diff --git a/core/testing/testing.odin b/core/testing/testing.odin index d5e7c6830..09bf6dc0e 100644 --- a/core/testing/testing.odin +++ b/core/testing/testing.odin @@ -105,9 +105,13 @@ cleanup :: proc(t: ^T, procedure: proc(rawptr), user_data: rawptr) { append(&t.cleanups, Internal_Cleanup{procedure, user_data, context}) } -expect :: proc(t: ^T, ok: bool, msg: string = "", loc := #caller_location) -> bool { +expect :: proc(t: ^T, ok: bool, msg := "", expr := #caller_expression(ok), loc := #caller_location) -> bool { if !ok { - log.error(msg, location=loc) + if msg == "" { + log.errorf("expected %v to be true", expr, location=loc) + } else { + log.error(msg, location=loc) + } } return ok } @@ -119,10 +123,10 @@ expectf :: proc(t: ^T, ok: bool, format: string, args: ..any, loc := #caller_loc return ok } -expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location) -> bool where intrinsics.type_is_comparable(T) { +expect_value :: proc(t: ^T, value, expected: $T, loc := #caller_location, value_expr := #caller_expression(value)) -> bool where intrinsics.type_is_comparable(T) { ok := value == expected || reflect.is_nil(value) && reflect.is_nil(expected) if !ok { - log.errorf("expected %v, got %v", expected, value, location=loc) + log.errorf("expected %v to be %v, got %v", value_expr, expected, value, location=loc) } return ok } diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 888aa074d..909eb668e 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -1632,6 +1632,22 @@ gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *o operand->type = t_source_code_location; operand->mode = Addressing_Value; + } else if (name == "caller_expression") { + if (ce->args.count > 1) { + error(ce->args[0], "'#caller_expression' expects either 0 or 1 arguments, got %td", ce->args.count); + } + if (ce->args.count > 0) { + Ast *arg = ce->args[0]; + Operand o = {}; + Entity *e = check_ident(c, &o, arg, nullptr, nullptr, true); + if (e == nullptr || (e->flags & EntityFlag_Param) == 0) { + error(ce->args[0], "'#caller_expression' expected a valid earlier parameter name"); + } + arg->Ident.entity = e; + } + + operand->type = t_string; + operand->mode = Addressing_Value; } else if (name == "exists") { if (ce->args.count != 1) { error(ce->close, "'#exists' expects 1 argument, got %td", ce->args.count); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7f82fb58a..6776094bf 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -7807,7 +7807,8 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c name == "load" || name == "load_directory" || name == "load_hash" || - name == "hash" + name == "hash" || + name == "caller_expression" ) { operand->mode = Addressing_Builtin; operand->builtin_id = BuiltinProc_DIRECTIVE; @@ -8725,6 +8726,10 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A error(node, "#caller_location may only be used as a default argument parameter"); o->type = t_source_code_location; o->mode = Addressing_Value; + } else if (name == "caller_expression") { + error(node, "#caller_expression may only be used as a default argument parameter"); + o->type = t_string; + o->mode = Addressing_Value; } else { if (name == "location") { init_core_source_code_location(c->checker); diff --git a/src/check_type.cpp b/src/check_type.cpp index 3767f7666..f0e0acb9b 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -1605,6 +1605,25 @@ gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) { return false; } +gb_internal bool is_caller_expression(Ast *expr) { + if (expr->kind == Ast_BasicDirective && expr->BasicDirective.name.string == "caller_expression") { + return true; + } + + Ast *call = unparen_expr(expr); + if (call->kind != Ast_CallExpr) { + return false; + } + + ast_node(ce, CallExpr, call); + if (ce->proc->kind != Ast_BasicDirective) { + return false; + } + + ast_node(bd, BasicDirective, ce->proc); + String name = bd->name.string; + return name == "caller_expression"; +} gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) { ParameterValue param_value = {}; @@ -1626,7 +1645,19 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_ if (in_type) { check_assignment(ctx, &o, in_type, str_lit("parameter value")); } + } else if (is_caller_expression(expr)) { + if (expr->kind != Ast_BasicDirective) { + check_builtin_procedure_directive(ctx, &o, expr, t_string); + } + + param_value.kind = ParameterValue_Expression; + o.type = t_string; + o.mode = Addressing_Value; + o.expr = expr; + if (in_type) { + check_assignment(ctx, &o, in_type, str_lit("parameter value")); + } } else { if (in_type) { check_expr_with_type_hint(ctx, &o, expr, in_type); @@ -1858,6 +1889,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para case ParameterValue_Nil: break; case ParameterValue_Location: + case ParameterValue_Expression: case ParameterValue_Value: gbString str = type_to_string(type); error(params[i], "A default value for a parameter must not be a polymorphic constant type, got %s", str); diff --git a/src/entity.cpp b/src/entity.cpp index db6ffdd52..0c4a20df4 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -104,6 +104,7 @@ enum ParameterValueKind { ParameterValue_Constant, ParameterValue_Nil, ParameterValue_Location, + ParameterValue_Expression, ParameterValue_Value, }; diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp index 29d2ccfe6..68f95cb03 100644 --- a/src/llvm_backend.hpp +++ b/src/llvm_backend.hpp @@ -528,7 +528,7 @@ gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValu gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos); gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String const &procedure, TokenPos const &pos); -gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos); +gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast *call_expression); gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type); gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type); diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp index e850d3364..d84599eb0 100644 --- a/src/llvm_backend_proc.cpp +++ b/src/llvm_backend_proc.cpp @@ -699,7 +699,9 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) { } if (e->Variable.param_value.kind != ParameterValue_Invalid) { - lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos); + GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Location); + GB_ASSERT(e->Variable.param_value.kind != ParameterValue_Expression); + lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, nullptr, nullptr); lb_addr_store(p, res, c); } @@ -3420,7 +3422,7 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu } -gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { +gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TypeProc *procedure_type, Ast* call_expression) { switch (param_value.kind) { case ParameterValue_Constant: if (is_type_constant_type(parameter_type)) { @@ -3446,8 +3448,60 @@ gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, if (p->entity != nullptr) { proc_name = p->entity->token.string; } + + ast_node(ce, CallExpr, call_expression); + TokenPos pos = ast_token(ce->proc).pos; + return lb_emit_source_code_location_as_global(p, proc_name, pos); } + case ParameterValue_Expression: + { + Ast *orig = param_value.original_ast_expr; + if (orig->kind == Ast_BasicDirective) { + gbString expr = expr_to_string(call_expression, temporary_allocator()); + return lb_const_string(p->module, make_string_c(expr)); + } + + isize param_idx = -1; + String param_str = {0}; + { + Ast *call = unparen_expr(orig); + GB_ASSERT(call->kind == Ast_CallExpr); + ast_node(ce, CallExpr, call); + GB_ASSERT(ce->proc->kind == Ast_BasicDirective); + GB_ASSERT(ce->args.count == 1); + Ast *target = ce->args[0]; + GB_ASSERT(target->kind == Ast_Ident); + String target_str = target->Ident.token.string; + + param_idx = lookup_procedure_parameter(procedure_type, target_str); + param_str = target_str; + } + GB_ASSERT(param_idx >= 0); + + + Ast *target_expr = nullptr; + ast_node(ce, CallExpr, call_expression); + + if (ce->split_args->positional.count > param_idx) { + target_expr = ce->split_args->positional[param_idx]; + } + + for_array(i, ce->split_args->named) { + Ast *arg = ce->split_args->named[i]; + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + if (name == param_str) { + target_expr = fv->value; + break; + } + } + + gbString expr = expr_to_string(target_expr, temporary_allocator()); + return lb_const_string(p->module, make_string_c(expr)); + } + case ParameterValue_Value: return lb_build_expr(p, param_value.ast_value); } @@ -3739,8 +3793,6 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { } } - TokenPos pos = ast_token(ce->proc).pos; - if (pt->params != nullptr) { isize min_count = pt->params->Tuple.variables.count; @@ -3764,7 +3816,7 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) { args[arg_index] = lb_const_nil(p->module, e->type); break; case Entity_Variable: - args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pos); + args[arg_index] = lb_handle_param_value(p, e->type, e->Variable.param_value, pt, expr); break; case Entity_Constant: -- cgit v1.2.3 From d03d9e49a6290b29a3259f99c4cdf574988b5765 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Sun, 15 Sep 2024 00:03:20 +0200 Subject: fix #4243 --- src/llvm_backend_debug.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/llvm_backend_debug.cpp b/src/llvm_backend_debug.cpp index bb6a1ba4f..5cc79dcc8 100644 --- a/src/llvm_backend_debug.cpp +++ b/src/llvm_backend_debug.cpp @@ -571,7 +571,7 @@ gb_internal LLVMMetadataRef lb_debug_bitfield(lbModule *m, Type *type, String na GB_ASSERT(f->kind == Entity_Variable); String name = f->token.string; elements[i] = LLVMDIBuilderCreateBitFieldMemberType(m->debug_builder, scope, cast(char const *)name.text, name.len, file, line, - bit_size, offset_in_bits, offset_in_bits, + bit_size, offset_in_bits, 0, LLVMDIFlagZero, lb_debug_type(m, f->type) ); -- cgit v1.2.3 From abf6ea7732b855dcb0ddb549a6454f99c40b7328 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2024 10:24:19 +0100 Subject: Fix minor bug with addressability --- src/check_stmt.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index c8717ba98..74a9e8825 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1641,6 +1641,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) Ast *expr = unparen_expr(rs->expr); + Operand rhs_operand = {}; + bool is_range = false; bool is_possibly_addressable = true; isize max_val_count = 2; @@ -1698,7 +1700,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } } } - bool is_ptr = is_type_pointer(type_deref(operand.type)); + bool is_ptr = is_type_pointer(operand.type); Type *t = base_type(type_deref(operand.type)); switch (t->kind) { @@ -1750,16 +1752,19 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) break; case Type_DynamicArray: + is_possibly_addressable = true; array_add(&vals, t->DynamicArray.elem); array_add(&vals, t_int); break; case Type_Slice: + is_possibly_addressable = true; array_add(&vals, t->Slice.elem); array_add(&vals, t_int); break; case Type_Map: + is_possibly_addressable = true; is_map = true; array_add(&vals, t->Map.key); array_add(&vals, t->Map.value); @@ -1781,6 +1786,8 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) case Type_Tuple: { + is_possibly_addressable = false; + isize count = t->Tuple.variables.count; if (count < 1) { ERROR_BLOCK(); @@ -1810,8 +1817,6 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) array_add(&vals, e->type); } - is_possibly_addressable = false; - bool do_break = false; for (isize i = rs->vals.count-1; i >= 0; i--) { if (rs->vals[i] != nullptr && count < i+2) { @@ -1831,6 +1836,11 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) case Type_Struct: if (t->Struct.soa_kind != StructSoa_None) { + if (t->Struct.soa_kind == StructSoa_Fixed) { + is_possibly_addressable = operand.mode == Addressing_Variable || is_ptr; + } else { + is_possibly_addressable = true; + } is_soa = true; array_add(&vals, t->Struct.soa_elem); array_add(&vals, t_int); @@ -1907,7 +1917,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) if (is_possibly_addressable && i == addressable_index) { entity->flags &= ~EntityFlag_Value; } else { - char const *idx_name = is_map ? "key" : is_bit_set ? "element" : "index"; + char const *idx_name = is_map ? "key" : (is_bit_set || i == 0) ? "element" : "index"; error(token, "The %s variable '%.*s' cannot be made addressable", idx_name, LIT(str)); } } -- cgit v1.2.3 From 19c1ed154cc9e36433fe23e1e34810f9c53ec01d Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2024 11:01:26 +0100 Subject: Add `-vet-packages:` --- src/build_settings.cpp | 3 +-- src/checker.cpp | 16 ++++------------ src/main.cpp | 30 +++++++++++++++++++++++++++++- src/parser.cpp | 31 ++++++++++++++++++++----------- 4 files changed, 54 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 1aca5d424..341cbe3e1 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -383,6 +383,7 @@ struct BuildContext { u64 vet_flags; u32 sanitizer_flags; + StringSet vet_packages; bool has_resource; String link_flags; @@ -1462,8 +1463,6 @@ gb_internal void init_build_context(TargetMetrics *cross_target, Subtarget subta bc->thread_count = gb_max(bc->affinity.thread_count, 1); } - string_set_init(&bc->custom_attributes); - bc->ODIN_VENDOR = str_lit("odin"); bc->ODIN_VERSION = ODIN_VERSION; bc->ODIN_ROOT = odin_root_dir(); diff --git a/src/checker.cpp b/src/checker.cpp index 64c66c8a6..deb83bf97 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -533,18 +533,13 @@ gb_internal u64 check_vet_flags(CheckerContext *c) { c->curr_proc_decl->proc_lit) { file = c->curr_proc_decl->proc_lit->file(); } - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; + + return ast_file_vet_flags(file); } gb_internal u64 check_vet_flags(Ast *node) { AstFile *file = node->file(); - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; + return ast_file_vet_flags(file); } enum VettedEntityKind { @@ -6497,10 +6492,7 @@ gb_internal void check_parsed_files(Checker *c) { TIME_SECTION("check scope usage"); for (auto const &entry : c->info.files) { AstFile *f = entry.value; - u64 vet_flags = build_context.vet_flags; - if (f->vet_flags_set) { - vet_flags = f->vet_flags; - } + u64 vet_flags = ast_file_vet_flags(f); check_scope_usage(c, f->scope, vet_flags); } diff --git a/src/main.cpp b/src/main.cpp index 06c200442..9b1dcf0fa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -346,6 +346,7 @@ enum BuildFlagKind { BuildFlag_VetSemicolon, BuildFlag_VetCast, BuildFlag_VetTabs, + BuildFlag_VetPackages, BuildFlag_CustomAttribute, BuildFlag_IgnoreUnknownAttributes, @@ -555,6 +556,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_VetSemicolon, str_lit("vet-semicolon"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetCast, str_lit("vet-cast"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetTabs, str_lit("vet-tabs"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetPackages, str_lit("vet-packages"), BuildFlagParam_String, Command__does_check); add_flag(&build_flags, BuildFlag_CustomAttribute, str_lit("custom-attribute"), BuildFlagParam_String, Command__does_check, true); add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check); @@ -1221,6 +1223,29 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetPackages: + { + GB_ASSERT(value.kind == ExactValue_String); + String val = value.value_string; + String_Iterator it = {val, 0}; + for (;;) { + String pkg = string_split_iterator(&it, ','); + if (pkg.len == 0) { + break; + } + + pkg = string_trim_whitespace(pkg); + if (!string_is_valid_identifier(pkg)) { + gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(pkg)); + bad_flags = true; + continue; + } + + string_set_add(&build_context.vet_packages, pkg); + } + } + break; + case BuildFlag_CustomAttribute: { GB_ASSERT(value.kind == ExactValue_String); @@ -1234,7 +1259,7 @@ gb_internal bool parse_build_flags(Array args) { attr = string_trim_whitespace(attr); if (!string_is_valid_identifier(attr)) { - gb_printf_err("-custom-attribute '%.*s' must be a valid identifier\n", LIT(attr)); + gb_printf_err("-%.*s '%.*s' must be a valid identifier\n", LIT(name), LIT(attr)); bad_flags = true; continue; } @@ -3150,6 +3175,9 @@ int main(int arg_count, char const **arg_ptr) { build_context.command = command; + string_set_init(&build_context.custom_attributes); + string_set_init(&build_context.vet_packages); + if (!parse_build_flags(args)) { return 1; } diff --git a/src/parser.cpp b/src/parser.cpp index 88147d465..56bea8131 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,10 +1,28 @@ #include "parser_pos.cpp" +gb_internal bool in_vet_packages(AstFile *file) { + if (file == nullptr) { + return true; + } + if (file->pkg == nullptr) { + return true; + } + if (build_context.vet_packages.entries.count == 0) { + return true; + } + return string_set_exists(&build_context.vet_packages, file->pkg->name); +} + gb_internal u64 ast_file_vet_flags(AstFile *f) { if (f != nullptr && f->vet_flags_set) { return f->vet_flags; } - return build_context.vet_flags; + + bool found = in_vet_packages(f); + if (found) { + return build_context.vet_flags; + } + return 0; } gb_internal bool ast_file_vet_style(AstFile *f) { @@ -5372,18 +5390,9 @@ gb_internal Ast *parse_stmt(AstFile *f) { } - -gb_internal u64 check_vet_flags(AstFile *file) { - if (file && file->vet_flags_set) { - return file->vet_flags; - } - return build_context.vet_flags; -} - - gb_internal void parse_enforce_tabs(AstFile *f) { // Checks to see if tabs have been used for indentation - if ((check_vet_flags(f) & VetFlag_Tabs) == 0) { + if ((ast_file_vet_flags(f) & VetFlag_Tabs) == 0) { return; } -- cgit v1.2.3 From 09588836e73d2def550cf5b1f6dab4d9de237e37 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 17 Sep 2024 11:33:42 +0100 Subject: Add `-vet-unused-procedures` --- src/build_settings.cpp | 3 +++ src/checker.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++------- src/main.cpp | 21 ++++++++++++++++++- 3 files changed, 71 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 341cbe3e1..7aff8e650 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -285,6 +285,7 @@ enum VetFlags : u64 { VetFlag_Deprecated = 1u<<7, VetFlag_Cast = 1u<<8, VetFlag_Tabs = 1u<<9, + VetFlag_UnusedProcedures = 1u<<10, VetFlag_Unused = VetFlag_UnusedVariables|VetFlag_UnusedImports, @@ -316,6 +317,8 @@ u64 get_vet_flag_from_name(String const &name) { return VetFlag_Cast; } else if (name == "tabs") { return VetFlag_Tabs; + } else if (name == "unused-procedures") { + return VetFlag_UnusedProcedures; } return VetFlag_NONE; } diff --git a/src/checker.cpp b/src/checker.cpp index deb83bf97..af1e0e675 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -676,20 +676,45 @@ gb_internal bool check_vet_unused(Checker *c, Entity *e, VettedEntity *ve) { return false; } -gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { - bool vet_unused = (vet_flags & VetFlag_Unused) != 0; - bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0; - +gb_internal void check_scope_usage_internal(Checker *c, Scope *scope, u64 vet_flags, bool per_entity) { + u64 original_vet_flags = vet_flags; Array vetted_entities = {}; array_init(&vetted_entities, heap_allocator()); + defer (array_free(&vetted_entities)); rw_mutex_shared_lock(&scope->mutex); for (auto const &entry : scope->elements) { Entity *e = entry.value; if (e == nullptr) continue; + + vet_flags = original_vet_flags; + if (per_entity) { + vet_flags = ast_file_vet_flags(e->file); + } + + bool vet_unused = (vet_flags & VetFlag_Unused) != 0; + bool vet_shadowing = (vet_flags & (VetFlag_Shadowing|VetFlag_Using)) != 0; + bool vet_unused_procedures = (vet_flags & VetFlag_UnusedProcedures) != 0; + VettedEntity ve_unused = {}; VettedEntity ve_shadowed = {}; - bool is_unused = vet_unused && check_vet_unused(c, e, &ve_unused); + bool is_unused = false; + if (vet_unused && check_vet_unused(c, e, &ve_unused)) { + is_unused = true; + } else if (vet_unused_procedures && + e->kind == Entity_Procedure) { + if (e->flags&EntityFlag_Used) { + is_unused = false; + } else if (e->flags & EntityFlag_Require) { + is_unused = false; + } else if (e->pkg && e->pkg->kind == Package_Init && e->token.string == "main") { + is_unused = false; + } else { + is_unused = true; + ve_unused.kind = VettedEntity_Unused; + ve_unused.entity = e; + } + } bool is_shadowed = vet_shadowing && check_vet_shadowing(c, e, &ve_shadowed); if (is_unused && is_shadowed) { VettedEntity ve_both = ve_shadowed; @@ -712,13 +737,18 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { } rw_mutex_shared_unlock(&scope->mutex); - gb_sort(vetted_entities.data, vetted_entities.count, gb_size_of(VettedEntity), vetted_entity_variable_pos_cmp); + array_sort(vetted_entities, vetted_entity_variable_pos_cmp); for (auto const &ve : vetted_entities) { Entity *e = ve.entity; Entity *other = ve.other; String name = e->token.string; + vet_flags = original_vet_flags; + if (per_entity) { + vet_flags = ast_file_vet_flags(e->file); + } + if (ve.kind == VettedEntity_Shadowed_And_Unused) { error(e->token, "'%.*s' declared but not used, possibly shadows declaration at line %d", LIT(name), other->token.pos.line); } else if (vet_flags) { @@ -727,6 +757,9 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { if (e->kind == Entity_Variable && (vet_flags & VetFlag_UnusedVariables) != 0) { error(e->token, "'%.*s' declared but not used", LIT(name)); } + if (e->kind == Entity_Procedure && (vet_flags & VetFlag_UnusedProcedures) != 0) { + error(e->token, "'%.*s' declared but not used", LIT(name)); + } if ((e->kind == Entity_ImportName || e->kind == Entity_LibraryName) && (vet_flags & VetFlag_UnusedImports) != 0) { error(e->token, "'%.*s' declared but not used", LIT(name)); } @@ -744,7 +777,11 @@ gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { } } - array_free(&vetted_entities); +} + + +gb_internal void check_scope_usage(Checker *c, Scope *scope, u64 vet_flags) { + check_scope_usage_internal(c, scope, vet_flags, false); for (Scope *child = scope->head_child; child != nullptr; child = child->next) { if (child->flags & (ScopeFlag_Proc|ScopeFlag_Type|ScopeFlag_File)) { @@ -6495,6 +6532,10 @@ gb_internal void check_parsed_files(Checker *c) { u64 vet_flags = ast_file_vet_flags(f); check_scope_usage(c, f->scope, vet_flags); } + for (auto const &entry : c->info.packages) { + AstPackage *pkg = entry.value; + check_scope_usage_internal(c, pkg->scope, 0, true); + } TIME_SECTION("add basic type information"); // Add "Basic" type information diff --git a/src/main.cpp b/src/main.cpp index 9b1dcf0fa..a969e32a9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -340,6 +340,7 @@ enum BuildFlagKind { BuildFlag_VetUnused, BuildFlag_VetUnusedImports, BuildFlag_VetUnusedVariables, + BuildFlag_VetUnusedProcedures, BuildFlag_VetUsingStmt, BuildFlag_VetUsingParam, BuildFlag_VetStyle, @@ -548,6 +549,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnused, str_lit("vet-unused"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedVariables, str_lit("vet-unused-variables"), BuildFlagParam_None, Command__does_check); + add_flag(&build_flags, BuildFlag_VetUnusedProcedures, str_lit("vet-unused-procedures"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUnusedImports, str_lit("vet-unused-imports"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetShadowing, str_lit("vet-shadowing"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_VetUsingStmt, str_lit("vet-using-stmt"), BuildFlagParam_None, Command__does_check); @@ -1222,6 +1224,13 @@ gb_internal bool parse_build_flags(Array args) { case BuildFlag_VetSemicolon: build_context.vet_flags |= VetFlag_Semicolon; break; case BuildFlag_VetCast: build_context.vet_flags |= VetFlag_Cast; break; case BuildFlag_VetTabs: build_context.vet_flags |= VetFlag_Tabs; break; + case BuildFlag_VetUnusedProcedures: + build_context.vet_flags |= VetFlag_UnusedProcedures; + if (!set_flags[BuildFlag_VetPackages]) { + gb_printf_err("-%.*s must be used with -vet-packages\n", LIT(name)); + bad_flags = true; + } + break; case BuildFlag_VetPackages: { @@ -2389,7 +2398,7 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(0, ""); print_usage_line(1, "-vet-unused"); - print_usage_line(2, "Checks for unused declarations."); + print_usage_line(2, "Checks for unused declarations (variables and imports)."); print_usage_line(0, ""); print_usage_line(1, "-vet-unused-variables"); @@ -2431,6 +2440,16 @@ gb_internal void print_show_help(String const arg0, String const &command) { print_usage_line(1, "-vet-tabs"); print_usage_line(2, "Errs when the use of tabs has not been used for indentation."); print_usage_line(0, ""); + + print_usage_line(1, "-vet-packages:"); + print_usage_line(2, "Sets which packages by name will be vetted."); + print_usage_line(2, "Files with specific +vet tags will not be ignored if they are not in the packages set."); + print_usage_line(0, ""); + + print_usage_line(1, "-vet-unused-procedures"); + print_usage_line(2, "Checks for unused procedures."); + print_usage_line(2, "Must be used with -vet-packages or specified on a per file with +vet tags."); + print_usage_line(0, ""); } if (check) { -- cgit v1.2.3 From 6ef779cd5c8260b2e6979e676d28489fd53dd599 Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Tue, 17 Sep 2024 17:46:30 +0200 Subject: add new macos releases to 'odin report' and sys/info --- core/sys/info/platform_darwin.odin | 4 ++++ src/bug_report.cpp | 2 ++ 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/core/sys/info/platform_darwin.odin b/core/sys/info/platform_darwin.odin index 3fd857bfe..493f038f0 100644 --- a/core/sys/info/platform_darwin.odin +++ b/core/sys/info/platform_darwin.odin @@ -530,6 +530,10 @@ macos_release_map: map[string]Darwin_To_Release = { "23F79" = {{23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}}, "23G80" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}}, "23G93" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}}, + "23H124" = {{23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}}, + + // MacOS Sequoia + "24A335" = {{24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}}, } @(private) diff --git a/src/bug_report.cpp b/src/bug_report.cpp index 5f768f57f..fa7e156ce 100644 --- a/src/bug_report.cpp +++ b/src/bug_report.cpp @@ -919,6 +919,8 @@ gb_internal void report_os_info() { {"23F79", {23, 5, 0}, "macOS", {"Sonoma", {14, 5, 0}}}, {"23G80", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 0}}}, {"23G93", {23, 6, 0}, "macOS", {"Sonoma", {14, 6, 1}}}, + {"23H124", {23, 6, 0}, "macOS", {"Sonoma", {14, 7, 0}}}, + {"24A335", {24, 0, 0}, "macOS", {"Sequoia", {15, 0, 0}}}, }; -- cgit v1.2.3 From 29fedc1808c347774971666ecc90b44e1900dc90 Mon Sep 17 00:00:00 2001 From: Karl Zylinski Date: Tue, 17 Sep 2024 19:39:48 +0200 Subject: Changed some recently added //+ usages to #+ and also fixed some //+ usages in some code generators. --- core/testing/runner_windows.odin | 2 +- src/parser.cpp | 2 +- tests/core/sys/windows/win32gen/win32gen.cpp | 2 +- tests/documentation/documentation_tester.odin | 2 +- vendor/box2d/box2d_wasm.odin | 2 +- vendor/cgltf/cgltf_wasm.odin | 2 +- vendor/stb/image/stb_image_wasm.odin | 2 +- vendor/stb/rect_pack/stb_rect_pack_wasm.odin | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/core/testing/runner_windows.odin b/core/testing/runner_windows.odin index fa233ff84..401804c71 100644 --- a/core/testing/runner_windows.odin +++ b/core/testing/runner_windows.odin @@ -1,4 +1,4 @@ -//+private +#+private package testing import win32 "core:sys/windows" diff --git a/src/parser.cpp b/src/parser.cpp index 242671af0..520a23c5a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4967,7 +4967,7 @@ gb_internal Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) { } if (f->in_when_statement) { - syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '//+build' tags"); + syntax_error(import_name, "Cannot use 'import' within a 'when' statement. Prefer using the file suffixes (e.g. foo_windows.odin) or '#+build' tags"); } if (kind != ImportDecl_Standard) { diff --git a/tests/core/sys/windows/win32gen/win32gen.cpp b/tests/core/sys/windows/win32gen/win32gen.cpp index 731173aa6..57a094cd5 100644 --- a/tests/core/sys/windows/win32gen/win32gen.cpp +++ b/tests/core/sys/windows/win32gen/win32gen.cpp @@ -902,7 +902,7 @@ static void verify_error_helpers(ofstream& out) { } static void test_core_sys_windows(ofstream& out) { - out << "//+build windows" << endl + out << "#+build windows" << endl << "package " << __func__ << " // generated by " << path(__FILE__).filename().replace_extension("").string() << endl << endl diff --git a/tests/documentation/documentation_tester.odin b/tests/documentation/documentation_tester.odin index ce1849e1c..7b125d4e4 100644 --- a/tests/documentation/documentation_tester.odin +++ b/tests/documentation/documentation_tester.odin @@ -264,7 +264,7 @@ write_test_suite :: proc(example_tests: []Example_Test) { test_runner := strings.builder_make() strings.write_string(&test_runner, -`//+private +`#+private package documentation_verification import "core:os" diff --git a/vendor/box2d/box2d_wasm.odin b/vendor/box2d/box2d_wasm.odin index eab369a0d..0fcaf753f 100644 --- a/vendor/box2d/box2d_wasm.odin +++ b/vendor/box2d/box2d_wasm.odin @@ -1,4 +1,4 @@ -//+build wasm32, wasm64p32 +#+build wasm32, wasm64p32 package vendor_box2d @(require) import _ "vendor:libc" diff --git a/vendor/cgltf/cgltf_wasm.odin b/vendor/cgltf/cgltf_wasm.odin index f2da86a2c..fb612b2ac 100644 --- a/vendor/cgltf/cgltf_wasm.odin +++ b/vendor/cgltf/cgltf_wasm.odin @@ -1,4 +1,4 @@ -//+build wasm32, wasm64p32 +#+build wasm32, wasm64p32 package cgltf @(require) import _ "vendor:libc" diff --git a/vendor/stb/image/stb_image_wasm.odin b/vendor/stb/image/stb_image_wasm.odin index 77bb44f02..f43012383 100644 --- a/vendor/stb/image/stb_image_wasm.odin +++ b/vendor/stb/image/stb_image_wasm.odin @@ -1,4 +1,4 @@ -//+build wasm32, wasm64p32 +#+build wasm32, wasm64p32 package stb_image @(require) import _ "vendor:libc" diff --git a/vendor/stb/rect_pack/stb_rect_pack_wasm.odin b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin index fb75552ec..c4e2e5160 100644 --- a/vendor/stb/rect_pack/stb_rect_pack_wasm.odin +++ b/vendor/stb/rect_pack/stb_rect_pack_wasm.odin @@ -1,4 +1,4 @@ -//+build wasm32, wasm64p32 +#+build wasm32, wasm64p32 package stb_rect_pack @(require) import _ "vendor:libc" -- cgit v1.2.3 From 9456c366848226d300ea5064c225084e7f9d55ad Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:18:48 -0400 Subject: Specify integer-like only for some `atomic_*` intrinsics Fixes #4256 --- src/check_builtin.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 909eb668e..8c051cca2 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -4969,16 +4969,14 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As check_assignment(c, &x, elem, builtin_name); Type *t = type_deref(operand->type); - switch (id) { - case BuiltinProc_atomic_add: - case BuiltinProc_atomic_sub: - if (!is_type_numeric(t)) { + if (id != BuiltinProc_atomic_exchange) { + if (!is_type_integer_like(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } else if (is_type_different_to_arch_endianness(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } } @@ -5014,19 +5012,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } Type *t = type_deref(operand->type); - switch (id) { - case BuiltinProc_atomic_add_explicit: - case BuiltinProc_atomic_sub_explicit: - if (!is_type_numeric(t)) { + if (id != BuiltinProc_atomic_exchange_explicit) { + if (!is_type_integer_like(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } else if (is_type_different_to_arch_endianness(t)) { gbString str = type_to_string(t); - error(operand->expr, "Expected a numeric type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); + error(operand->expr, "Expected an integer type of the same platform endianness for '%.*s', got %s", LIT(builtin_name), str); gb_string_free(str); } - break; } operand->type = elem; -- cgit v1.2.3 From acbf5c8d9775f66de69206b89390f2f966b53d73 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Thu, 19 Sep 2024 05:55:30 -0400 Subject: Forbid labelled or-branch expressions within `defer` --- src/check_expr.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6776094bf..fc1aa62e6 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -9131,6 +9131,10 @@ gb_internal ExprKind check_or_branch_expr(CheckerContext *c, Operand *o, Ast *no } if (label != nullptr) { + if (c->in_defer) { + error(label, "A labelled '%.*s' cannot be used within a 'defer'", LIT(name)); + return Expr_Expr; + } if (label->kind != Ast_Ident) { error(label, "A branch statement's label name must be an identifier"); return Expr_Expr; -- cgit v1.2.3 From b116e8ff55c9250d29f63d7b91cb749bf0766c4f Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 20 Sep 2024 01:29:39 +0100 Subject: Fix 128-bit integer support for wasm targets --- base/runtime/procs_wasm.odin | 60 ++++++++++++++++++++++++++++++-------------- src/llvm_abi.cpp | 9 ++++--- vendor/wasm/js/events.odin | 6 ++++- 3 files changed, 51 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/base/runtime/procs_wasm.odin b/base/runtime/procs_wasm.odin index 8da1564c6..7e03656ca 100644 --- a/base/runtime/procs_wasm.odin +++ b/base/runtime/procs_wasm.odin @@ -14,33 +14,57 @@ ti_uint :: struct #raw_union { } @(link_name="__ashlti3", linkage="strong") -__ashlti3 :: proc "contextless" (la, ha: u64, b_: u32) -> i128 { - bits_in_dword :: size_of(u32)*8 - b := u32(b_) +__ashlti3 :: proc "contextless" (a: i128, b: u32) -> i128 { + bits :: 64 - input, result: ti_int - input.lo, input.hi = la, ha - if b & bits_in_dword != 0 { + input: ti_int = --- + result: ti_int = --- + input.all = a + if b & bits != 0 { result.lo = 0 - result.hi = input.lo << (b-bits_in_dword) + result.hi = input.lo << (b-bits) } else { if b == 0 { - return input.all + return a } result.lo = input.lo<>(bits_in_dword-b)) + result.hi = (input.hi<>(bits-b)) } return result.all } +__ashlti3_unsigned :: proc "contextless" (a: u128, b: u32) -> u128 { + return cast(u128)__ashlti3(cast(i128)a, b) +} + +@(link_name="__mulddi3", linkage="strong") +__mulddi3 :: proc "contextless" (a, b: u64) -> i128 { + r: ti_int + bits :: 32 + + mask :: ~u64(0) >> bits + r.lo = (a & mask) * (b & mask) + t := r.lo >> bits + r.lo &= mask + t += (a >> bits) * (b & mask) + r.lo += (t & mask) << bits + r.hi = t >> bits + t = r.lo >> bits + r.lo &= mask + t += (b >> bits) * (a & mask) + r.lo += (t & mask) << bits + r.hi += t >> bits + r.hi += (a >> bits) * (b >> bits) + return r.all +} @(link_name="__multi3", linkage="strong") -__multi3 :: proc "contextless" (la, ha, lb, hb: u64) -> i128 { +__multi3 :: proc "contextless" (a, b: i128) -> i128 { x, y, r: ti_int - x.lo, x.hi = la, ha - y.lo, y.hi = lb, hb - r.all = i128(x.lo * y.lo) // TODO this is incorrect + x.all = a + y.all = b + r.all = __mulddi3(x.lo, y.lo) r.hi += x.hi*y.lo + x.lo*y.hi return r.all } @@ -54,18 +78,16 @@ udivti3 :: proc "c" (la, ha, lb, hb: u64) -> u128 { } @(link_name="__lshrti3", linkage="strong") -__lshrti3 :: proc "c" (la, ha: u64, b: u32) -> i128 { - bits :: size_of(u32)*8 +__lshrti3 :: proc "c" (a: i128, b: u32) -> i128 { + bits :: 64 input, result: ti_int - input.lo = la - input.hi = ha - + input.all = a if b & bits != 0 { result.hi = 0 result.lo = input.hi >> (b - bits) } else if b == 0 { - return input.all + return a } else { result.hi = input.hi >> b result.lo = (input.hi << (bits - b)) | (input.lo >> b) diff --git a/src/llvm_abi.cpp b/src/llvm_abi.cpp index aa5c4dc60..42086b09d 100644 --- a/src/llvm_abi.cpp +++ b/src/llvm_abi.cpp @@ -1257,11 +1257,12 @@ namespace lbAbiWasm { } gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) { - if (!is_return && type == LLVMIntTypeInContext(c, 128)) { - LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2); + if (type == LLVMIntTypeInContext(c, 128)) { + // LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2); + LLVMTypeRef cast_type = nullptr; return lb_arg_type_direct(type, cast_type, nullptr, nullptr); } - + if (!is_return && lb_sizeof(type) > 8) { return lb_arg_type_indirect(type, nullptr); } @@ -1282,7 +1283,7 @@ namespace lbAbiWasm { case LLVMPointerTypeKind: return true; case LLVMIntegerTypeKind: - return lb_sizeof(type) <= 8; + return lb_sizeof(type) <= 16; } return false; } diff --git a/vendor/wasm/js/events.odin b/vendor/wasm/js/events.odin index 442dc50b3..258776fff 100644 --- a/vendor/wasm/js/events.odin +++ b/vendor/wasm/js/events.odin @@ -30,6 +30,8 @@ Event_Kind :: enum u32 { Wheel, Focus, + Focus_In, + Focus_Out, Submit, Blur, Change, @@ -110,6 +112,8 @@ event_kind_string := [Event_Kind]string{ .Wheel = "wheel", .Focus = "focus", + .Focus_In = "focusin", + .Focus_Out = "focusout", .Submit = "submit", .Blur = "blur", .Change = "change", @@ -332,7 +336,7 @@ remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr return _remove_event_listener(id, name, user_data, callback) } - +import "core:fmt" @(export, link_name="odin_dom_do_event_callback") -- cgit v1.2.3