From f17c86d936dad98a8f8cf26d5543d8df20e6419e Mon Sep 17 00:00:00 2001 From: kalsprite Date: Wed, 19 Aug 2026 15:39:39 -0700 Subject: [PATCH 1/2] diagnostics: let compiler check error() fmt strings + fixes --- src/check_builtin.cpp | 16 ++++++++-------- src/check_decl.cpp | 2 +- src/check_expr.cpp | 34 +++++++++++++++++----------------- src/check_stmt.cpp | 6 +++--- src/check_type.cpp | 14 +++++++------- src/checker.cpp | 10 +++++----- src/error.cpp | 23 +++++++++++++++-------- src/parser.cpp | 4 ++++ 8 files changed, 60 insertions(+), 49 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index 61bcb462b..b18f8c44d 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -727,7 +727,7 @@ gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operan Type *superclass = obj_type->Named.type_name->TypeName.objc_superclass; if (superclass == nullptr) { gbString t = type_to_string(obj_type); - error(operand->expr, "'%.*s' target object '%.*s' does not have an Objective-C superclass. One must be set via the @(objc_superclass) attribute", LIT(builtin_name), t); + error(operand->expr, "'%.*s' target object '%s' does not have an Objective-C superclass. One must be set via the @(objc_superclass) attribute", LIT(builtin_name), t); gb_string_free(t); return false; } @@ -3305,7 +3305,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As if (sel.indirect) { gbString type_str = type_to_string_shorthand(type); error(ce->args[0], - "Field '%s' is embedded via a pointer in '%s'", field_name.string(), type_str); + "Field '%.*s' is embedded via a pointer in '%s'", LIT(field_name.string()), type_str); gb_string_free(type_str); return false; } @@ -4932,11 +4932,11 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As gb_string_free(s); } else if (elements > MATRIX_ELEMENT_COUNT_MAX) { gbString s = type_to_string(x.type); - error(call, "'%.*s' expects a matrix or array with a maximum of %d elements, got %s with %lld elements", LIT(builtin_name), MATRIX_ELEMENT_COUNT_MAX, s, elements); + error(call, "'%.*s' expects a matrix or array with a maximum of %d elements, got %s with %lld elements", LIT(builtin_name), MATRIX_ELEMENT_COUNT_MAX, s, cast(long long)elements); gb_string_free(s); } else if (elements > MATRIX_ELEMENT_COUNT_MAX) { gbString s = type_to_string(x.type); - error(call, "'%.*s' expects a matrix or array with non-zero elements, got %s", LIT(builtin_name), MATRIX_ELEMENT_COUNT_MAX, s); + error(call, "'%.*s' expects a matrix or array with non-zero elements, got %s", LIT(builtin_name), s); gb_string_free(s); } else if (size > MATRIX_ELEMENT_MAX_SIZE) { gbString s = type_to_string(x.type); @@ -5353,7 +5353,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } if (!is_type_integer(offset.type)) { gbString s = type_to_string(array_ptr.type); - error(array_ptr.expr, "Expected an integer as the offset for '%.*s', got %s", s, LIT(builtin_name)); + error(array_ptr.expr, "Expected an integer as the offset for '%.*s', got %s", LIT(builtin_name), s); gb_string_free(s); return false; } @@ -5821,7 +5821,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As i64 sz = type_size_of(x.type); if (sz < 2) { gbString xts = type_to_string(x.type); - error(x.expr, "Type passed to '%.*s' must be at least 2 bytes, got %s with size of %lld", LIT(builtin_name), xts, sz); + error(x.expr, "Type passed to '%.*s' must be at least 2 bytes, got %s with size of %lld", LIT(builtin_name), xts, cast(long long)sz); gb_string_free(xts); } @@ -6653,12 +6653,12 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As } i64 n = exact_value_to_i64(z.value); if (n <= 0) { - error(z.expr, "Scale parameter in '%.*s' must be positive, got %lld", LIT(builtin_name), n); + error(z.expr, "Scale parameter in '%.*s' must be positive, got %lld", LIT(builtin_name), cast(long long)n); return false; } i64 sz = 8*type_size_of(x.type); if (n > sz) { - error(z.expr, "Scale parameter in '%.*s' is larger than the base integer bit width, got %lld, expected a maximum of %lld", LIT(builtin_name), n, sz); + error(z.expr, "Scale parameter in '%.*s' is larger than the base integer bit width, got %lld, expected a maximum of %lld", LIT(builtin_name), cast(long long)n, cast(long long)sz); return false; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 68553c25f..1751fee3b 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1158,7 +1158,7 @@ gb_internal void check_objc_methods(CheckerContext *ctx, Entity *e, AttributeCon error(e->token, "Imported Objective-C methods must use the \"c\" calling convention"); return; } else if (tn->TypeName.objc_context_provider) { - error(e->token, "Imported Objective-C class '%.*s' must not declare context providers.", tn->type->Named.name); + error(e->token, "Imported Objective-C class '%.*s' must not declare context providers.", LIT(tn->type->Named.name)); return; } else if (tn->TypeName.objc_is_implementation) { error(e->token, "Imported Objective-C methods used in a class with @(objc_implement) is not allowed."); diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 332277701..cc99a20af 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -2655,7 +2655,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, String max_size_str = big_int_to_string(temporary_allocator(), &max_size); if (size_changed) { - error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %lld' is '%.*s'\n", b, cast(long long)bit_size, LIT(max_size_str)); } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } @@ -2677,7 +2677,7 @@ gb_internal bool check_integer_exceed_suggestion(CheckerContext *c, Operand *o, } if (size_changed) { - error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %u' is '%.*s'\n", b, bit_size, LIT(max_size_str)); + error_line("\tThe maximum value that can be represented with that bit_field's field of '%s | %lld' is '%.*s'\n", b, cast(long long)bit_size, LIT(max_size_str)); } else { error_line("\tThe maximum value that can be represented by '%s' is '%.*s'\n", b, LIT(max_size_str)); } @@ -2765,7 +2765,7 @@ gb_internal void check_cast_error_suggestion(CheckerContext *c, Operand *o, Type i64 x = type_size_of(o->type); i64 y = type_size_of(type); if (x != y) { - error_line("\tNote: the type of expression and the type of the cast have a different size in bytes, %lld vs %lld\n", x, y); + error_line("\tNote: the type of expression and the type of the cast have a different size in bytes, %lld vs %lld\n", cast(long long)x, cast(long long)y); } } } else if (is_type_integer(o->type) && is_type_pointer(type)) { @@ -4111,7 +4111,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type if (srcz != dstz) { gbString expr_str = expr_to_string(o->expr); gbString type_str = type_to_string(dst_t); - error(o->expr, "Cannot transmute '%s' to '%s', %lld vs %lld bytes", expr_str, type_str, srcz, dstz); + error(o->expr, "Cannot transmute '%s' to '%s', %lld vs %lld bytes", expr_str, type_str, cast(long long)srcz, cast(long long)dstz); gb_string_free(type_str); gb_string_free(expr_str); o->mode = Addressing_Invalid; @@ -4571,7 +4571,7 @@ gb_internal void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Typ x->expr = node; return; } else { - error(x->expr, "key '%lld' out of range of bit set, %lld..%lld", key, lower, upper); + error(x->expr, "key '%lld' out of range of bit set, %lld..%lld", cast(long long)key, cast(long long)lower, cast(long long)upper); x->mode = Addressing_Invalid; } } @@ -5524,7 +5524,7 @@ gb_internal bool check_index_value(CheckerContext *c, Type *main_type, bool open String idx_str = big_int_to_string(temporary_allocator(), &i); gbString expr_str = expr_to_string(operand.expr, temporary_allocator()); char range_type = open_range ? '=' : '<'; - error(operand.expr, "Index '%s' is out of bounds range 0..%c%lld, got %.*s", expr_str, range_type, max_count, LIT(idx_str)); + error(operand.expr, "Index '%s' is out of bounds range 0..%c%lld, got %.*s", expr_str, range_type, cast(long long)max_count, LIT(idx_str)); return false; } @@ -6158,7 +6158,7 @@ gb_internal Entity *check_selector(CheckerContext *c, Operand *operand, Ast *nod } else { GB_PANIC("unknown swizzle kind"); } - error(selector->Ident.token, "Swizzle value is out of bounds, got %c, max count %lld", c, array_count); + error(selector->Ident.token, "Swizzle value is out of bounds, got %c, max count %lld", c, cast(long long)array_count); break; } } @@ -6772,10 +6772,10 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A defer (gb_string_free(proc_str)); if (param_count_excluding_defaults != pt->param_count) { char const *err_fmt = "Too many arguments for '%s', expected %td..=%td arguments, got %td"; - error(call, err_fmt, proc_str, param_count_excluding_defaults, pt->param_count, positional_operands.count); + error(call, err_fmt, proc_str, param_count_excluding_defaults, cast(isize)pt->param_count, positional_operands.count); } else { char const *err_fmt = "Too many arguments for '%s', expected %td arguments, got %td"; - error(call, err_fmt, proc_str, pt->param_count, positional_operands.count); + error(call, err_fmt, proc_str, cast(isize)pt->param_count, positional_operands.count); } } return err; @@ -11049,17 +11049,17 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * bool new_range = range_cache_add_range(&rc, lo, hi); if (!new_range) { - error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", lo, LIT(op.string), hi, LIT(context_name)); + error(elem, "Overlapping field range index %lld %.*s %lld for %.*s", cast(long long)lo, LIT(op.string), cast(long long)hi, LIT(context_name)); continue; } if (max_type_count >= 0 && (lo < 0 || lo >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", lo, max_type_count, LIT(context_name)); + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", cast(long long)lo, cast(long long)max_type_count, LIT(context_name)); continue; } if (max_type_count >= 0 && (hi < 0 || hi >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", hi, max_type_count, LIT(context_name)); + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", cast(long long)hi, cast(long long)max_type_count, LIT(context_name)); continue; } @@ -11087,13 +11087,13 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * i64 index = exact_value_to_i64(op_index.value); if (max_type_count >= 0 && (index < 0 || index >= max_type_count)) { - error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", index, max_type_count, LIT(context_name)); + error(elem, "Index %lld is out of bounds (0..<%lld) for %.*s", cast(long long)index, cast(long long)max_type_count, LIT(context_name)); continue; } bool new_index = range_cache_add_index(&rc, index); if (!new_index) { - error(elem, "Duplicate field index %lld for %.*s", index, LIT(context_name)); + error(elem, "Duplicate field index %lld for %.*s", cast(long long)index, LIT(context_name)); continue; } @@ -11128,7 +11128,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", cast(long long)index, cast(long long)max_type_count, LIT(context_name)); } Operand operand = {}; @@ -11405,7 +11405,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * } if (0 <= max_type_count && max_type_count <= index) { - error(e, "Index %lld is out of bounds (>= %lld) for %.*s", index, max_type_count, LIT(context_name)); + error(e, "Index %lld is out of bounds (>= %lld) for %.*s", cast(long long)index, cast(long long)max_type_count, LIT(context_name)); } Operand operand = {}; @@ -11657,7 +11657,7 @@ gb_internal ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast * // okay } else { 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); + error(elem, "Bit field value out of bounds, %s (%lld) not in the range %lld .. %lld", s, cast(long long)v, cast(long long)lower, cast(long long)upper); gb_string_free(s); continue; } diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 31825bb34..f92c97f02 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1147,9 +1147,9 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod if (ctx->inline_for_depth >= MAX_INLINE_FOR_DEPTH && prev_inline_for_depth < MAX_INLINE_FOR_DEPTH) { ERROR_BLOCK(); if (prev_inline_for_depth > 0) { - error(node, "Nested '#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + error(node, "Nested '#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", cast(long long)v, MAX_INLINE_FOR_DEPTH); } else { - error(node, "'#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", v, MAX_INLINE_FOR_DEPTH); + error(node, "'#unroll for' loop cannot be inlined as it exceeds the maximum '#unroll for' depth (%lld levels >= %lld maximum levels)", cast(long long)v, MAX_INLINE_FOR_DEPTH); } error_line("\tUse a normal 'for' loop instead by removing the 'inline' prefix\n"); ctx->inline_for_depth = MAX_INLINE_FOR_DEPTH; @@ -2511,7 +2511,7 @@ gb_internal void check_expr_stmt(CheckerContext *ctx, Ast *node) { { gbString lhs = expr_to_string(be->left); gbString rhs = expr_to_string(be->right); - error_line("\tSuggestion: Did you mean to do an assignment?\n", lhs, rhs); + error_line("\tSuggestion: Did you mean to do an assignment?\n"); error_line("\t '%s = %s;'\n", lhs, rhs); gb_string_free(rhs); gb_string_free(lhs); diff --git a/src/check_type.cpp b/src/check_type.cpp index 2ccefdea1..fcc1378f6 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -281,7 +281,7 @@ gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_, } i64 align = big_int_to_i64(&v); if (align < 1 || !gb_is_power_of_two(cast(isize)align)) { - error(node, "#%s must be a power of 2, got %lld", msg, align); + error(node, "#%s must be a power of 2, got %lld", msg, cast(long long)align); return false; } *align_ = align; @@ -1390,7 +1390,7 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t if (lower > 0) { actual_lower = 0; } else if (lower < 0) { - error(bs->elem, "bit_set does not allow a negative lower bound (%lld) when an underlying type is set", lower); + error(bs->elem, "bit_set does not allow a negative lower bound (%lld) when an underlying type is set", cast(long long)lower); } } @@ -1419,9 +1419,9 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t } if (!is_valid) { if (actual_lower != lower) { - error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internally the lower bound was changed to 0 as an underlying type was set)", bits, bits_required); + error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internally the lower bound was changed to 0 as an underlying type was set)", cast(long long)bits, cast(long long)bits_required); } else { - error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, bits_required); + error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", cast(long long)bits, cast(long long)bits_required); } } @@ -1481,7 +1481,7 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t lower_changed = true; } else if (lower < 0) { gbString s = type_to_string(elem); - error(bs->elem, "bit_set does not allow a negative lower bound (%lld) of the element type '%s' when an underlying type is set", lower, s); + error(bs->elem, "bit_set does not allow a negative lower bound (%lld) of the element type '%s' when an underlying type is set", cast(long long)lower, s); gb_string_free(s); } } @@ -1489,9 +1489,9 @@ gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_t if (upper - lower >= bits) { i64 bits_required = upper-lower+1; if (lower_changed) { - error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internally the lower bound was changed to 0 as an underlying type was set)", bits, bits_required); + error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required (internally the lower bound was changed to 0 as an underlying type was set)", cast(long long)bits, cast(long long)bits_required); } else { - error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", bits, bits_required); + error(bs->elem, "bit_set range is greater than %lld bits, %lld bits are required", cast(long long)bits, cast(long long)bits_required); } } diff --git a/src/checker.cpp b/src/checker.cpp index 25bbc0f56..2e161505d 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -7380,24 +7380,24 @@ gb_internal void check_objc_context_provider_procedures(Checker *c) { const char *self_param_err = "The @(objc_context_provider) procedure must take as a parameter a single pointer to the @(objc_type) value."; if (proc.param_count != 1) { - error(proc_entity->token, self_param_err); + error(proc_entity->token, "%s", self_param_err); } Type *self_param = base_type(proc.params->Tuple.variables[0]->type); if (self_param->kind != Type_Pointer) { - error(proc_entity->token, self_param_err); + error(proc_entity->token, "%s", self_param_err); } Type *self_type = base_named_type(self_param->Pointer.elem); if (!internal_check_is_assignable_to(self_type, e->type) && !(e->TypeName.objc_ivar && internal_check_is_assignable_to(self_type, e->TypeName.objc_ivar))) { - error(proc_entity->token, self_param_err); + error(proc_entity->token, "%s", self_param_err); } if (proc.calling_convention != ProcCC_CDecl && proc.calling_convention != ProcCC_Contextless) { - error(e->token, self_param_err); + error(e->token, "%s", self_param_err); } if (proc.is_polymorphic) { - error(e->token, self_param_err); + error(e->token, "%s", self_param_err); } } } diff --git a/src/error.cpp b/src/error.cpp index ee2d79c27..b28ef7b10 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -174,14 +174,21 @@ gb_internal bool json_errors(void); gb_internal bool has_ansi_terminal_colours(void); gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset); -gb_internal void warning(Token const &token, char const *fmt, ...); -gb_internal void error(Token const &token, char const *fmt, ...); -gb_internal void error(TokenPos pos, char const *fmt, ...); -gb_internal void error_line(char const *fmt, ...); -gb_internal void syntax_error(Token const &token, char const *fmt, ...); -gb_internal void syntax_error(TokenPos pos, char const *fmt, ...); -gb_internal void syntax_warning(Token const &token, char const *fmt, ...); -gb_internal void compiler_error(char const *fmt, ...); +// Let the compiler check these against their arguments. +#if defined(__GNUC__) || defined(__clang__) + #define ODIN_FMT_LIKE(fmt_idx, va_idx) __attribute__((format(printf, fmt_idx, va_idx))) +#else + #define ODIN_FMT_LIKE(fmt_idx, va_idx) +#endif + +gb_internal void warning(Token const &token, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void error(Token const &token, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void error(TokenPos pos, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void error_line(char const *fmt, ...) ODIN_FMT_LIKE(1, 2); +gb_internal void syntax_error(Token const &token, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void syntax_error(TokenPos pos, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void syntax_warning(Token const &token, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); +gb_internal void compiler_error(char const *fmt, ...) ODIN_FMT_LIKE(1, 2); gb_internal void print_all_errors(void); diff --git a/src/parser.cpp b/src/parser.cpp index 24e16102a..69f9c2690 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -564,6 +564,7 @@ gb_internal Ast *clone_ast(Ast *node, AstFile *f) { } +gb_internal void error(Ast *node, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); gb_internal void error(Ast *node, char const *fmt, ...) { Token token = {}; TokenPos end_pos = {}; @@ -617,6 +618,7 @@ gb_internal void syntax_error_with_verbose(Ast *node, char const *fmt, ...) { } +gb_internal void error_no_newline(Ast *node, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); gb_internal void error_no_newline(Ast *node, char const *fmt, ...) { Token token = {}; if (node != nullptr) { @@ -632,6 +634,7 @@ gb_internal void error_no_newline(Ast *node, char const *fmt, ...) { } } +gb_internal void warning(Ast *node, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); gb_internal void warning(Ast *node, char const *fmt, ...) { Token token = {}; TokenPos end_pos = {}; @@ -645,6 +648,7 @@ gb_internal void warning(Ast *node, char const *fmt, ...) { va_end(va); } +gb_internal void syntax_error(Ast *node, char const *fmt, ...) ODIN_FMT_LIKE(2, 3); gb_internal void syntax_error(Ast *node, char const *fmt, ...) { Token token = {}; TokenPos end_pos = {}; From f84735af42d948b029662093665ad9d4a79b17f9 Mon Sep 17 00:00:00 2001 From: kalsprite Date: Wed, 19 Aug 2026 15:50:55 -0700 Subject: [PATCH 2/2] missed site --- src/check_builtin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index b18f8c44d..20fa2f92c 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -5352,8 +5352,8 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As return false; } if (!is_type_integer(offset.type)) { - gbString s = type_to_string(array_ptr.type); - error(array_ptr.expr, "Expected an integer as the offset for '%.*s', got %s", LIT(builtin_name), s); + gbString s = type_to_string(offset.type); + error(offset.expr, "Expected an integer as the offset for '%.*s', got %s", LIT(builtin_name), s); gb_string_free(s); return false; }