From 5ed2735658c4ae1ad9aa5d790a6ebd64136bdf27 Mon Sep 17 00:00:00 2001 From: Feoramund <161657516+Feoramund@users.noreply.github.com> Date: Tue, 10 Jun 2025 06:13:14 -0400 Subject: Guard against invalid proc types in parameter list Fixes #4362 --- src/check_expr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 9308eab8e..335b82f1a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -6497,7 +6497,7 @@ gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_ Entity **lhs = nullptr; isize lhs_count = -1; - if (proc_type == nullptr) { + if (proc_type == nullptr || proc_type == t_invalid) { return nullptr; } @@ -6697,6 +6697,9 @@ gb_internal bool check_call_arguments_single(CheckerContext *c, Ast *call, Opera GB_ASSERT(proc_type != nullptr); proc_type = base_type(proc_type); + if (proc_type == t_invalid) { + return false; + } GB_ASSERT(proc_type->kind == Type_Proc); CallArgumentError err = check_call_arguments_internal(c, call, e, proc_type, positional_operands, named_operands, show_error_mode, data); -- cgit v1.2.3 From c7c5258c587b38508cd855ff2488a842503233eb Mon Sep 17 00:00:00 2001 From: Airtz <72342006+Airtz@users.noreply.github.com> Date: Fri, 20 Jun 2025 01:23:40 +0200 Subject: Update check_expr.cpp --- src/check_expr.cpp | 145 +++++++++++++++++++++++------------------------------ 1 file changed, 63 insertions(+), 82 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 335b82f1a..6ee6de146 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3086,126 +3086,107 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod GB_ASSERT(node->kind == Ast_BinaryExpr); ast_node(be, BinaryExpr, node); - ExactValue x_val = {}; - if (x->mode == Addressing_Constant) { - x_val = exact_value_to_integer(x->value); + bool y_is_untyped = is_type_untyped(y->type); + if (y_is_untyped) { + convert_to_typed(c, y, t_untyped_integer); + if (y->mode == Addressing_Invalid) { + x->mode = Addressing_Invalid; + return; + } + } else if (!is_type_unsigned(y->type)) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' must be an unsigned integer", y_str); + gb_string_free(y_str); + x->mode = Addressing_Invalid; + return; } bool x_is_untyped = is_type_untyped(x->type); - if (!(is_type_integer(x->type) || (x_is_untyped && x_val.kind == ExactValue_Integer))) { - gbString err_str = expr_to_string(x->expr); - error(node, "Shifted operand '%s' must be an integer", err_str); - gb_string_free(err_str); + if (!(x_is_untyped || is_type_integer(x->type))) { + gbString x_str = expr_to_string(x->expr); + error(x->expr, "Shifted operand '%s' must be an integer", x_str); + gb_string_free(x_str); x->mode = Addressing_Invalid; return; } - if (is_type_unsigned(y->type)) { - - } else if (is_type_untyped(y->type)) { - convert_to_typed(c, y, t_untyped_integer); - if (y->mode == Addressing_Invalid) { + if (y->mode == Addressing_Constant) { + if (big_int_is_neg(&y->value.value_integer)) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' must be positive", y_str); + gb_string_free(y_str); x->mode = Addressing_Invalid; return; } - } else { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount '%s' must be an unsigned integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } + BigInt max_shift = {}; + big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT); - if (x->mode == Addressing_Constant) { - if (y->mode == Addressing_Constant) { - ExactValue y_val = exact_value_to_integer(y->value); - if (y_val.kind != ExactValue_Integer) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount '%s' must be an unsigned integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } + if (big_int_cmp(&y->value.value_integer, &max_shift) > 0) { + gbString y_str = expr_to_string(y->expr); + error(y->expr, "Shift amount '%s' must be <= %u", y_str, MAX_BIG_INT_SHIFT); + gb_string_free(y_str); + x->mode = Addressing_Invalid; + return; + } - BigInt max_shift = {}; - big_int_from_u64(&max_shift, MAX_BIG_INT_SHIFT); + if (x->mode == Addressing_Constant) { + if (x_is_untyped) { + convert_to_typed(c, x, t_untyped_integer); + if (x->mode == Addressing_Invalid) { + return; + } - if (big_int_cmp(&y_val.value_integer, &max_shift) > 0) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount too large: '%s'", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } + x->expr = node; + x->value = exact_value_shift(be->op.kind, exact_value_to_integer(x->value), exact_value_to_integer(y->value)); - if (!is_type_integer(x->type)) { - // NOTE(bill): It could be an untyped float but still representable - // as an integer - x->type = t_untyped_integer; + return; } x->expr = node; - x->value = exact_value_shift(be->op.kind, x_val, y_val); + x->value = exact_value_shift(be->op.kind, x->value, y->value); + check_is_expressible(c, x, x->type); - if (is_type_typed(x->type)) { - check_is_expressible(c, x, x->type); - } return; } - TokenPos pos = ast_token(x->expr).pos; + if (y_is_untyped) { + convert_to_typed(c, y, t_uint); + } + + return; + } + + if (x->mode == Addressing_Constant) { if (x_is_untyped) { - if (x->expr != nullptr) { - x->expr->tav.is_lhs = true; - } - x->mode = Addressing_Value; + Type *def_type = default_type(t_untyped_integer); if (type_hint) { if (is_type_integer(type_hint)) { convert_to_typed(c, x, type_hint); + } else if (is_type_any(type_hint)) { + convert_to_typed(c, x, def_type); } else { gbString x_str = expr_to_string(x->expr); - gbString to_type = type_to_string(type_hint); - error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type); + gbString type_str = type_to_string(type_hint); + error(x->expr, "Shifted operand '%s' cannot convert to non-integer type '%s'", x_str, type_str); gb_string_free(x_str); - gb_string_free(to_type); + gb_string_free(type_str); x->mode = Addressing_Invalid; + return; } - } else if (!is_type_integer(x->type)) { - gbString x_str = expr_to_string(x->expr); - error(node, "Non-integer shifted operand '%s' is not allowed", x_str); - gb_string_free(x_str); - x->mode = Addressing_Invalid; + } else { + convert_to_typed(c, x, def_type); + } + if (x->mode == Addressing_Invalid) { + return; } - // x->value = x_val; - return; } - } - - if (y->mode == Addressing_Constant && big_int_is_neg(&y->value.value_integer)) { - gbString err_str = expr_to_string(y->expr); - error(node, "Shift amount cannot be negative: '%s'", err_str); - gb_string_free(err_str); - } - - if (!is_type_integer(x->type)) { - gbString err_str = expr_to_string(x->expr); - error(node, "Shift operand '%s' must be an integer", err_str); - gb_string_free(err_str); - x->mode = Addressing_Invalid; - return; - } - if (is_type_untyped(y->type)) { - convert_to_typed(c, y, t_uint); + x->mode = Addressing_Value; } - - x->mode = Addressing_Value; } - - gb_internal bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) { if (check_is_assignable_to(c, operand, y)) { return true; -- cgit v1.2.3 From 7c5b5618e8fb27589d6ae14b217dd0288a6621e2 Mon Sep 17 00:00:00 2001 From: Airtz <72342006+Airtz@users.noreply.github.com> Date: Fri, 20 Jun 2025 04:49:39 +0200 Subject: `check_is_expressible` instead of `convert_to_typed` when there is no `type_hint` --- src/check_expr.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 6ee6de146..7cf4ef83a 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3160,12 +3160,11 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod if (x->mode == Addressing_Constant) { if (x_is_untyped) { - Type *def_type = default_type(t_untyped_integer); if (type_hint) { if (is_type_integer(type_hint)) { convert_to_typed(c, x, type_hint); } else if (is_type_any(type_hint)) { - convert_to_typed(c, x, def_type); + convert_to_typed(c, x, default_type(t_untyped_integer)); } else { gbString x_str = expr_to_string(x->expr); gbString type_str = type_to_string(type_hint); @@ -3176,7 +3175,7 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod return; } } else { - convert_to_typed(c, x, def_type); + check_is_expressible(c, x, default_type(t_untyped_integer)); } if (x->mode == Addressing_Invalid) { return; -- cgit v1.2.3 From 7abd86c2110ac9973ea9d8445d20e24c960a6ab9 Mon Sep 17 00:00:00 2001 From: Jeroen van Rijn Date: Sat, 21 Jun 2025 00:05:15 +0200 Subject: Clarify --- for global variable. --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 335b82f1a..fcdabedde 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -11090,7 +11090,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast case_ast_node(u, Uninit, node); o->mode = Addressing_Value; o->type = t_untyped_uninit; - error(node, "Use of --- outside of variable declaration"); + error(node, "Global variables will always be zeroed if left unassigned, --- is disallowed"); case_end; -- cgit v1.2.3 From 19c0f43e192d853ca62dfd44cdfae82ac5b1da44 Mon Sep 17 00:00:00 2001 From: Airtz Date: Sun, 22 Jun 2025 16:15:22 +0200 Subject: Fix #4445 --- src/check_expr.cpp | 45 ++++++++++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 19 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fcdabedde..71079b4a1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5884,12 +5884,12 @@ typedef u32 UnpackFlags; enum UnpackFlag : u32 { UnpackFlag_None = 0, UnpackFlag_AllowOk = 1<<0, - UnpackFlag_IsVariadic = 1<<1, - UnpackFlag_AllowUndef = 1<<2, + UnpackFlag_AllowUndef = 1<<1, }; -gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs_arguments, UnpackFlags flags) { +gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize lhs_count, Array *operands, Slice const &rhs_arguments, UnpackFlags flags, + isize variadic_index = -1) { auto const &add_dependencies_from_unpacking = [](CheckerContext *c, Entity **lhs, isize lhs_count, isize tuple_index, isize tuple_count) -> isize { if (lhs == nullptr || c->decl == nullptr) { return tuple_count; @@ -5914,10 +5914,12 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize return tuple_count; }; - bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; - bool is_variadic = (flags & UnpackFlag_IsVariadic) != 0; bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; + + if (variadic_index < 0) { + variadic_index = lhs_count; + } bool optional_ok = false; isize tuple_index = 0; @@ -5934,8 +5936,7 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize Type *type_hint = nullptr; - - if (lhs != nullptr && tuple_index < lhs_count) { + if (lhs != nullptr && tuple_index < variadic_index) { // NOTE(bill): override DeclInfo for dependency Entity *e = lhs[tuple_index]; if (e != nullptr) { @@ -5946,9 +5947,9 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize type_hint = e->type->Slice.elem; } } - } else if (lhs != nullptr && tuple_index >= lhs_count && is_variadic) { + } else if (lhs != nullptr && tuple_index >= variadic_index) { // NOTE(bill): override DeclInfo for dependency - Entity *e = lhs[lhs_count-1]; + Entity *e = lhs[variadic_index]; if (e != nullptr) { type_hint = e->type; if (e->flags & EntityFlag_Ellipsis) { @@ -6493,7 +6494,7 @@ gb_internal bool is_call_expr_field_value(AstCallExpr *ce) { return ce->args[0]->kind == Ast_FieldValue; } -gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_, bool *is_variadic) { +gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_type, isize *lhs_count_) { Entity **lhs = nullptr; isize lhs_count = -1; @@ -6503,7 +6504,6 @@ gb_internal Entity **populate_proc_parameter_list(CheckerContext *c, Type *proc_ GB_ASSERT(is_type_proc(proc_type)); TypeProc *pt = &base_type(proc_type)->Proc; - *is_variadic = pt->variadic; if (!pt->is_polymorphic || pt->is_poly_specialized) { if (pt->params != nullptr) { @@ -6833,7 +6833,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, Entity **lhs = nullptr; isize lhs_count = -1; - bool is_variadic = false; + i32 variadic_index = -1; auto positional_operands = array_make(heap_allocator(), 0, 0); auto named_operands = array_make(heap_allocator(), 0, 0); @@ -6842,9 +6842,13 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (procs.count == 1) { Entity *e = procs[0]; - - lhs = populate_proc_parameter_list(c, e->type, &lhs_count, &is_variadic); - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + TypeProc *pt = &base_type(e->type)->Proc; + + lhs = populate_proc_parameter_list(c, e->type, &lhs_count); + if (pt->variadic) { + variadic_index = pt->variadic_index; + } + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); if (check_named_arguments(c, e->type, named_args, &named_operands, true)) { check_call_arguments_single(c, call, operand, @@ -6908,7 +6912,7 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } } - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); for_array(i, named_args) { Ast *arg = named_args[i]; @@ -7347,12 +7351,15 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op if (positional_args.count > 0) { isize lhs_count = -1; - bool is_variadic = false; Entity **lhs = nullptr; + i32 variadic_index = -1; if (pt != nullptr) { - lhs = populate_proc_parameter_list(c, proc_type, &lhs_count, &is_variadic); + lhs = populate_proc_parameter_list(c, proc_type, &lhs_count); + if (pt->variadic) { + variadic_index = pt->variadic_index; + } } - check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, is_variadic ? UnpackFlag_IsVariadic : UnpackFlag_None); + check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); } if (named_args.count > 0) { -- cgit v1.2.3 From 277130111e941d30d73a3566e178c7f893d03113 Mon Sep 17 00:00:00 2001 From: Airtz Date: Sun, 22 Jun 2025 16:51:44 +0200 Subject: sign check error message update --- src/check_expr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 7cf4ef83a..3c981d462 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -3113,7 +3113,7 @@ gb_internal void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *nod if (y->mode == Addressing_Constant) { if (big_int_is_neg(&y->value.value_integer)) { gbString y_str = expr_to_string(y->expr); - error(y->expr, "Shift amount '%s' must be positive", y_str); + error(y->expr, "Shift amount '%s' cannot be negative", y_str); gb_string_free(y_str); x->mode = Addressing_Invalid; return; -- cgit v1.2.3 From d65b1d5e947aa10642a478772eaf726e52ab91ec Mon Sep 17 00:00:00 2001 From: Airtz Date: Mon, 23 Jun 2025 18:10:40 +0200 Subject: Better proc groups inference --- src/check_expr.cpp | 64 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 25 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 898ac387b..3f947b6a7 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -5896,8 +5896,9 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize bool allow_ok = (flags & UnpackFlag_AllowOk) != 0; bool allow_undef = (flags & UnpackFlag_AllowUndef) != 0; - - if (variadic_index < 0) { + + bool is_variadic = variadic_index > -1; + if (!is_variadic) { variadic_index = lhs_count; } @@ -5916,25 +5917,18 @@ gb_internal bool check_unpack_arguments(CheckerContext *ctx, Entity **lhs, isize Type *type_hint = nullptr; - if (lhs != nullptr && tuple_index < variadic_index) { - // NOTE(bill): override DeclInfo for dependency - Entity *e = lhs[tuple_index]; - if (e != nullptr) { - type_hint = e->type; - if (e->flags & EntityFlag_Ellipsis) { - GB_ASSERT(is_type_slice(e->type)); - GB_ASSERT(e->type->kind == Type_Slice); - type_hint = e->type->Slice.elem; + if (lhs != nullptr) { + if (tuple_index < variadic_index) { + // NOTE(bill): override DeclInfo for dependency + Entity *e = lhs[tuple_index]; + if (e != nullptr) { + type_hint = e->type; } - } - } else if (lhs != nullptr && tuple_index >= variadic_index) { - // NOTE(bill): override DeclInfo for dependency - Entity *e = lhs[variadic_index]; - if (e != nullptr) { - type_hint = e->type; - if (e->flags & EntityFlag_Ellipsis) { + } else if (is_variadic) { + Entity *e = lhs[variadic_index]; + if (e != nullptr) { + GB_ASSERT(e->flags & EntityFlag_Ellipsis); GB_ASSERT(is_type_slice(e->type)); - GB_ASSERT(e->type->kind == Type_Slice); type_hint = e->type->Slice.elem; } } @@ -6822,11 +6816,12 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, if (procs.count == 1) { Entity *e = procs[0]; - TypeProc *pt = &base_type(e->type)->Proc; - - lhs = populate_proc_parameter_list(c, e->type, &lhs_count); - if (pt->variadic) { - variadic_index = pt->variadic_index; + Type *pt = base_type(e->type); + if (pt != nullptr && is_type_proc(pt)) { + lhs = populate_proc_parameter_list(c, pt, &lhs_count); + if (pt->Proc.variadic) { + variadic_index = pt->Proc.variadic_index; + } } check_unpack_arguments(c, lhs, lhs_count, &positional_operands, positional_args, UnpackFlag_None, variadic_index); @@ -6888,6 +6883,25 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c, } lhs[param_index] = e; } + + for (Entity *p : procs) { + Type *pt = base_type(p->type); + if (!(pt != nullptr && is_type_proc(pt))) { + continue; + } + + if (pt->Proc.is_polymorphic) { + if (variadic_index == -1) { + variadic_index = pt->Proc.variadic_index; + } else if (variadic_index != pt->Proc.variadic_index) { + variadic_index = -1; + break; + } + } else { + variadic_index = -1; + break; + } + } } } } @@ -7330,8 +7344,8 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op defer (array_free(&named_operands)); if (positional_args.count > 0) { - isize lhs_count = -1; Entity **lhs = nullptr; + isize lhs_count = -1; i32 variadic_index = -1; if (pt != nullptr) { lhs = populate_proc_parameter_list(c, proc_type, &lhs_count); -- cgit v1.2.3 From 2259db9a5396f598cb1c38d5f0ad73b02fce1403 Mon Sep 17 00:00:00 2001 From: Airtz Date: Tue, 24 Jun 2025 02:54:14 +0200 Subject: Better error messages --- src/check_expr.cpp | 14 +++++++------- src/check_stmt.cpp | 20 +++++++++++--------- 2 files changed, 18 insertions(+), 16 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 3f947b6a7..fa1b4cd92 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2424,27 +2424,27 @@ gb_internal void check_assignment_error_suggestion(CheckerContext *c, Operand *o Type *s = src->Array.elem; Type *d = dst->Slice.elem; if (are_types_identical(s, d)) { - error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a); + error_line("\tSuggestion: The array expression may be sliced with %s[:]\n", a); } } else if (is_type_dynamic_array(src) && is_type_slice(dst)) { Type *s = src->DynamicArray.elem; Type *d = dst->Slice.elem; if (are_types_identical(s, d)) { - error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a); + error_line("\tSuggestion: The dynamic array expression may be sliced with %s[:]\n", a); } }else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) { - error_line("\tSuggestion: the expression may be directly casted to type %s\n", b); + error_line("\tSuggestion: The expression may be directly casted to type %s\n", b); } else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) { - error_line("\tSuggestion: a string may be transmuted to %s\n", b); - error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n"); + error_line("\tSuggestion: A string may be transmuted to %s\n", b); + error_line("\t This is an UNSAFE operation as string data is assumed to be immutable,\n"); error_line("\t whereas slices in general are assumed to be mutable.\n"); } else if (is_type_u8_slice(src) && are_types_identical(dst, t_string) && o->mode != Addressing_Constant) { - error_line("\tSuggestion: the expression may be casted to %s\n", b); + error_line("\tSuggestion: The expression may be casted to %s\n", b); } else if (check_integer_exceed_suggestion(c, o, type, max_bit_size)) { return; } else if (is_expr_inferred_fixed_array(c->type_hint_expr) && is_type_array_like(type) && is_type_array_like(o->type)) { gbString s = expr_to_string(c->type_hint_expr); - error_line("\tSuggestion: make sure that `%s` is attached to the compound literal directly\n", s); + error_line("\tSuggestion: Make sure that `%s` is attached to the compound literal directly\n", s); gb_string_free(s); } else if (is_type_pointer(type) && o->mode == Addressing_Variable && diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index d92edf41d..620e9fb74 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -418,7 +418,7 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) { -gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) { +gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs, String context_name) { if (rhs->mode == Addressing_Invalid) { return nullptr; } @@ -430,7 +430,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O Ast *node = unparen_expr(lhs->expr); - check_no_copy_assignment(*rhs, str_lit("assignment")); + check_no_copy_assignment(*rhs, context_name); // NOTE(bill): Ignore assignments to '_' if (is_blank_ident(node)) { @@ -630,7 +630,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O ctx->bit_field_bit_size = lhs_e->Variable.bit_field_bit_size; } - check_assignment(ctx, rhs, assignment_type, str_lit("assignment")); + check_assignment(ctx, rhs, assignment_type, context_name); ctx->bit_field_bit_size = prev_bit_field_bit_size; @@ -2418,7 +2418,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { isize lhs_count = as->lhs.count; if (lhs_count == 0) { - error(as->op, "Missing lhs in assignment statement"); + error(as->op, "Missing LHS in assignment statement"); return; } @@ -2451,7 +2451,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { if (lhs_to_ignore[i]) { continue; } - check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i]); + check_assignment_variable(ctx, &lhs_operands[i], &rhs_operands[i], str_lit("assignment")); } if (lhs_count != rhs_count) { error(as->lhs[0], "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count); @@ -2461,11 +2461,11 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { // a += 1; // Single-sided Token op = as->op; if (as->lhs.count != 1 || as->rhs.count != 1) { - error(op, "Assignment operation '%.*s' requires single-valued expressions", LIT(op.string)); + error(op, "Assignment operator '%.*s' requires single-valued operands", LIT(op.string)); return; } if (!gb_is_between(op.kind, Token__AssignOpBegin+1, Token__AssignOpEnd-1)) { - error(op, "Unknown Assignment operation '%.*s'", LIT(op.string)); + error(op, "Unknown assignment operator '%.*s'", LIT(op.string)); return; } Operand lhs = {Addressing_Invalid}; @@ -2474,7 +2474,7 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { ast_node(be, BinaryExpr, binary_expr); be->op = op; be->op.kind = cast(TokenKind)(cast(i32)be->op.kind - (Token_AddEq - Token_Add)); - // NOTE(bill): Only use the first one will be used + // NOTE(bill): Only use the first one will be used be->left = as->lhs[0]; be->right = as->rhs[0]; @@ -2482,7 +2482,9 @@ gb_internal void check_assign_stmt(CheckerContext *ctx, Ast *node) { check_binary_expr(ctx, &rhs, binary_expr, nullptr, true); if (rhs.mode != Addressing_Invalid) { // NOTE(bill): Only use the first one will be used - check_assignment_variable(ctx, &lhs, &rhs); + be->op.string = substring(be->op.string, 0, 1); + rhs.expr = binary_expr; + check_assignment_variable(ctx, &lhs, &rhs, str_lit("assignment operation")); } } } -- cgit v1.2.3 From 2c308bdcfabe4aeaa51e007a683347f0546e6a1b Mon Sep 17 00:00:00 2001 From: Laytan Laats Date: Thu, 26 Jun 2025 17:05:12 +0200 Subject: fix load type panic because front-end allows a deref of a type Fixes #5357 --- src/check_expr.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index fa1b4cd92..14d54af68 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -11323,6 +11323,13 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast node->viral_state_flags |= de->expr->viral_state_flags; if (o->mode == Addressing_Invalid) { + o->mode = Addressing_Invalid; + o->expr = node; + return kind; + } else if (o->mode == Addressing_Type) { + gbString str = expr_to_string(o->expr); + error(o->expr, "Cannot dereference '%s' because it is a type", str); + o->mode = Addressing_Invalid; o->expr = node; return kind; -- cgit v1.2.3 From f72b2b153057e1d629c85af2ea7c54f7928198d5 Mon Sep 17 00:00:00 2001 From: Hayden Gray <35206453+A1029384756@users.noreply.github.com> Date: Thu, 26 Jun 2025 16:43:44 -0400 Subject: [source-code-locations] - added options to show, obfuscate, and hide source code locations (#5412) --- src/build_settings.cpp | 9 ++++++++- src/check_expr.cpp | 46 ++++++++++++++++++++++++++++++++++++++++---- src/llvm_backend_const.cpp | 20 ++++++++++++++++--- src/llvm_backend_general.cpp | 14 +++++++++++++- src/main.cpp | 30 ++++++++++++++++++++++++++--- 5 files changed, 107 insertions(+), 12 deletions(-) (limited to 'src/check_expr.cpp') diff --git a/src/build_settings.cpp b/src/build_settings.cpp index 05709902a..ebe57bf1e 100644 --- a/src/build_settings.cpp +++ b/src/build_settings.cpp @@ -385,6 +385,13 @@ enum LinkerChoice : i32 { Linker_COUNT, }; +enum SourceCodeLocationInfo : u8 { + SourceCodeLocationInfo_Normal = 0, + SourceCodeLocationInfo_Obfuscated = 1, + SourceCodeLocationInfo_Filename = 2, + SourceCodeLocationInfo_None = 3, +}; + String linker_choices[Linker_COUNT] = { str_lit("default"), str_lit("lld"), @@ -512,7 +519,7 @@ struct BuildContext { bool dynamic_map_calls; - bool obfuscate_source_code_locations; + SourceCodeLocationInfo source_code_location_info; bool min_link_libs; diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 14d54af68..aa9c8837d 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -8760,23 +8760,52 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A String name = bd->name.string; if (name == "file") { String file = get_file_path_string(bd->token.pos.file_id); - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(file); } else if (name == "directory") { String file = get_file_path_string(bd->token.pos.file_id); String path = dir_from_path(file); - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: path = obfuscate_string(path, "D"); + break; + case SourceCodeLocationInfo_Filename: + path = last_path_element(path); + break; + case SourceCodeLocationInfo_None: + path = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(path); } else if (name == "line") { i32 line = bd->token.pos.line; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: line = obfuscate_i32(line); + break; + case SourceCodeLocationInfo_Filename: + break; + case SourceCodeLocationInfo_None: + line = 0; + break; } o->type = t_untyped_integer; o->value = exact_value_i64(line); @@ -8787,8 +8816,17 @@ gb_internal ExprKind check_basic_directive_expr(CheckerContext *c, Operand *o, A o->value = exact_value_string(str_lit("")); } else { String p = c->proc_name; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: p = obfuscate_string(p, "P"); + break; + case SourceCodeLocationInfo_Filename: + break; + case SourceCodeLocationInfo_None: + p = str_lit(""); + break; } o->type = t_untyped_string; o->value = exact_value_string(p); diff --git a/src/llvm_backend_const.cpp b/src/llvm_backend_const.cpp index e897ae282..c3112934e 100644 --- a/src/llvm_backend_const.cpp +++ b/src/llvm_backend_const.cpp @@ -292,12 +292,26 @@ gb_internal lbValue lb_const_source_code_location_const(lbModule *m, String cons i32 line = pos.line; i32 column = pos.column; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); procedure = obfuscate_string(procedure, "P"); - line = obfuscate_i32(line); - column = obfuscate_i32(column); + line = obfuscate_i32(line); + column = obfuscate_i32(column); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + procedure = str_lit(""); + + line = 0; + column = 0; + break; } LLVMValueRef fields[4] = {}; diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 5d6a55973..aaa9ffd4d 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -568,10 +568,22 @@ gb_internal void lb_set_file_line_col(lbProcedure *p, Array arr, TokenP i32 line = pos.line; i32 col = pos.column; - if (build_context.obfuscate_source_code_locations) { + switch (build_context.source_code_location_info) { + case SourceCodeLocationInfo_Normal: + break; + case SourceCodeLocationInfo_Obfuscated: file = obfuscate_string(file, "F"); line = obfuscate_i32(line); col = obfuscate_i32(col); + break; + case SourceCodeLocationInfo_Filename: + file = last_path_element(file); + break; + case SourceCodeLocationInfo_None: + file = str_lit(""); + line = 0; + col = 0; + break; } arr[0] = lb_find_or_add_entity_string(p->module, file, false); diff --git a/src/main.cpp b/src/main.cpp index d7fb66f99..f988aff6a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -370,6 +370,7 @@ enum BuildFlagKind { BuildFlag_NoRTTI, BuildFlag_DynamicMapCalls, BuildFlag_ObfuscateSourceCodeLocations, + BuildFlag_SourceCodeLocations, BuildFlag_Compact, BuildFlag_GlobalDefinitions, @@ -594,6 +595,7 @@ gb_internal bool parse_build_flags(Array args) { add_flag(&build_flags, BuildFlag_DynamicMapCalls, str_lit("dynamic-map-calls"), BuildFlagParam_None, Command__does_check); add_flag(&build_flags, BuildFlag_ObfuscateSourceCodeLocations, str_lit("obfuscate-source-code-locations"), BuildFlagParam_None, Command__does_build); + add_flag(&build_flags, BuildFlag_SourceCodeLocations, str_lit("source-code-locations"), BuildFlagParam_String, Command__does_build); add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc); add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc | Command_test | Command_build); @@ -1422,7 +1424,23 @@ gb_internal bool parse_build_flags(Array args) { break; case BuildFlag_ObfuscateSourceCodeLocations: - build_context.obfuscate_source_code_locations = true; + gb_printf_err("'-obfuscate-source-code-locations' is now deprecated in favor of '-source-code-locations:obfuscated'\n"); + build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated; + break; + + case BuildFlag_SourceCodeLocations: + if (str_eq_ignore_case(value.value_string, str_lit("normal"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Normal; + } else if (str_eq_ignore_case(value.value_string, str_lit("obfuscated"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Obfuscated; + } else if (str_eq_ignore_case(value.value_string, str_lit("filename"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_Filename; + } else if (str_eq_ignore_case(value.value_string, str_lit("none"))) { + build_context.source_code_location_info = SourceCodeLocationInfo_None; + } else { + gb_printf_err("-source-code-locations: options are 'normal', 'obfuscated', 'filename', and 'none'\n"); + bad_flags = true; + } break; case BuildFlag_DefaultToNilAllocator: @@ -2669,8 +2687,14 @@ gb_internal int print_show_help(String const arg0, String command, String option } - if (print_flag("-obfuscate-source-code-locations")) { - print_usage_line(2, "Obfuscate the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value."); + if (print_flag("-source-code-locations:")) { + print_usage_line(2, "Processes the file and procedure strings, and line and column numbers, stored with a 'runtime.Source_Code_Location' value."); + print_usage_line(2, "Available options:"); + print_usage_line(3, "-source-code-locations:normal"); + print_usage_line(3, "-source-code-locations:obfuscated"); + print_usage_line(3, "-source-code-locations:filename"); + print_usage_line(3, "-source-code-locations:none"); + print_usage_line(2, "The default is -source-code-locations:normal."); } -- cgit v1.2.3