From 605a7c4091f0c960c977293a270cf8eceea7ac81 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 23 Jun 2025 23:47:19 +0200 Subject: [PATCH] Improve error message on pointer diff #2239. --- releasenotes.md | 3 ++- src/compiler/sema_casts.c | 13 +++++++++++++ test/test_suite/cast/ptrdiff.c3 | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 test/test_suite/cast/ptrdiff.c3 diff --git a/releasenotes.md b/releasenotes.md index f011644cc..a2914a20c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -25,7 +25,8 @@ - Support distrinct types as the base type of bitstructs. #2218 - Add hash::sha512 module to stdlib. #2227 - Compile time type assignment (eg `$Foo = int`) is no longer an expression. -- Add `@allow_deprecated` attribute to functions to selectively allow deprecated declarations #2223 +- Add `@allow_deprecated` attribute to functions to selectively allow deprecated declarations #2223. +- Improve error message on pointer diff #2239. ### Fixes - `-2147483648`, MIN literals work correctly. diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 4ed297b84..d948cbd5e 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1275,6 +1275,14 @@ static bool rule_int_to_float(CastContext *cc, bool is_explicit, bool is_silent) return true; } +INLINE bool expr_is_pointer_diff(Expr *expr) +{ + if (expr->type != type_isz) return false; + if (expr->expr_kind != EXPR_BINARY) return false; + if (expr->binary_expr.operator != BINARYOP_SUB) return false; + return type_is_pointer(exprptr(expr->binary_expr.left)->type) && type_is_pointer(exprptr(expr->binary_expr.right)->type); +} + static bool rule_widen_narrow(CastContext *cc, bool is_explicit, bool is_silent) { if (is_explicit) return true; @@ -1327,6 +1335,11 @@ static bool rule_widen_narrow(CastContext *cc, bool is_explicit, bool is_silent) expr_const_to_error_string(&expr->const_expr), type_quoted_error_string(cc->to_type)); } + if (expr_is_pointer_diff(expr)) + { + RETURN_CAST_ERROR(expr, "A pointer diff has the type %s which cannot implicitly be converted to %s. You can use an explicit cast if you know the conversion is safe.", + type_quoted_error_string(expr->type), type_quoted_error_string(cc->to_type)); + } RETURN_CAST_ERROR(expr, "%s cannot implicitly be converted to %s, but you may use a cast.", type_quoted_error_string(expr->type), type_quoted_error_string(cc->to_type)); } diff --git a/test/test_suite/cast/ptrdiff.c3 b/test/test_suite/cast/ptrdiff.c3 new file mode 100644 index 000000000..3818107ea --- /dev/null +++ b/test/test_suite/cast/ptrdiff.c3 @@ -0,0 +1,8 @@ +import std; +fn int main() +{ + void* a; + void* b; + int z = a - b; // #error: A pointer diff has the type + return 0; +} \ No newline at end of file