Restrict the cases where ptr_eq triggers (#14526)

`ptr_eq` was recently enhanced to lint on more cases of raw pointers
comparison:

- lint on all raw pointer comparison, by proposing to use
`[core|std]::ptr::eq(lhs, rhs)` instead of `lhs == rhs`;
- removing one symetric `as usize` on each size if needed
- peeling any level of `as *[const|mut] _` if the remaining expression
can still be coerced into the original one (i.e., is a ref or raw
pointer to the same type as before)

The current change restricts the lint to the cases where at least one
level of symetric `as usize`, or any conversion to a raw pointer, could
be removed. For example, a direct comparaison of two raw pointers will
not trigger the lint anymore.

changelog: [`ptr_eq`]: do not lint when comparing two raw pointers
directly with no casts involved

Fixes rust-lang/rust-clippy#14525
This commit is contained in:
Alex Macleod 2025-04-22 16:05:34 +00:00 committed by Pietro Albini
parent 6e8f95f7ce
commit 287610b489
No known key found for this signature in database
GPG key ID: 3E06ABE80BAAF19C
7 changed files with 60 additions and 100 deletions

View file

@ -786,9 +786,9 @@ fn check_ptr_eq<'tcx>(
}
// Remove one level of usize conversion if any
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
(Some(lhs), Some(rhs)) => (lhs, rhs),
_ => (left, right),
let (left, right, usize_peeled) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
(Some(lhs), Some(rhs)) => (lhs, rhs, true),
_ => (left, right, false),
};
// This lint concerns raw pointers
@ -797,7 +797,12 @@ fn check_ptr_eq<'tcx>(
return;
}
let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
let ((left_var, left_casts_peeled), (right_var, right_casts_peeled)) =
(peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
if !(usize_peeled || left_casts_peeled || right_casts_peeled) {
return;
}
let mut app = Applicability::MachineApplicable;
let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
@ -830,8 +835,9 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
}
}
// Peel raw casts if the remaining expression can be coerced to it
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
// Peel raw casts if the remaining expression can be coerced to it, and whether casts have been
// peeled or not.
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> (&'tcx Expr<'tcx>, bool) {
if !expr.span.from_expansion()
&& let ExprKind::Cast(inner, _) = expr.kind
&& let ty::RawPtr(target_ty, _) = expr_ty.kind()
@ -839,8 +845,8 @@ fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty:
&& let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
&& target_ty == inner_target_ty
{
peel_raw_casts(cx, inner, inner_ty)
(peel_raw_casts(cx, inner, inner_ty).0, true)
} else {
expr
(expr, false)
}
}

View file

@ -23,23 +23,25 @@ fn main() {
//~^ ptr_eq
let _ = std::ptr::eq(a, b);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_ptr(), b as *const _);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_ptr(), b.as_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
let _ = std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
//~^ ptr_eq
let _ = std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
let _ = a == b;
let _ = core::ptr::eq(a, b);
@ -51,9 +53,9 @@ fn main() {
let _ = !std::ptr::eq(x, y);
//~^ ptr_eq
#[allow(clippy::eq_op)]
let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
//~^ ptr_eq
#[expect(clippy::eq_op)]
// Do not lint: casts are needed to not change type
let _issue14337 = main as *const () == main as *const ();
// Do not peel the content of macros
let _ = std::ptr::eq(mac!(cast a), mac!(cast b));

View file

@ -23,23 +23,25 @@ fn main() {
//~^ ptr_eq
let _ = a as *const _ == b as *const _;
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
//~^ ptr_eq
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
//~^ ptr_eq
let _ = a == b;
let _ = core::ptr::eq(a, b);
@ -51,9 +53,9 @@ fn main() {
let _ = x as *const u32 != y as *mut u32 as *const u32;
//~^ ptr_eq
#[allow(clippy::eq_op)]
#[expect(clippy::eq_op)]
// Do not lint: casts are needed to not change type
let _issue14337 = main as *const () == main as *const ();
//~^ ptr_eq
// Do not peel the content of macros
let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;

View file

@ -14,52 +14,22 @@ LL | let _ = a as *const _ == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:26:13
|
LL | let _ = a.as_ptr() == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:28:13
|
LL | let _ = a.as_ptr() == b.as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:39:13
|
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:41:13
|
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:48:13
--> tests/ui/ptr_eq.rs:50:13
|
LL | let _ = x as *const u32 == y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:51:13
--> tests/ui/ptr_eq.rs:53:13
|
LL | let _ = x as *const u32 != y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:55:23
|
LL | let _issue14337 = main as *const () == main as *const ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
error: use `std::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq.rs:59:13
--> tests/ui/ptr_eq.rs:61:13
|
LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
error: aborting due to 10 previous errors
error: aborting due to 5 previous errors

View file

@ -32,23 +32,25 @@ fn main() {
//~^ ptr_eq
let _ = core::ptr::eq(a, b);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_ptr(), b as *const _);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_ptr(), b.as_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
let _ = core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _);
//~^ ptr_eq
let _ = core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr());
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
let _ = a == b;
let _ = core::ptr::eq(a, b);

View file

@ -32,23 +32,25 @@ fn main() {
//~^ ptr_eq
let _ = a as *const _ == b as *const _;
//~^ ptr_eq
// Do not lint: the rhs conversion is needed
let _ = a.as_ptr() == b as *const _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_ptr() == b.as_ptr();
//~^ ptr_eq
// Do not lint
let _ = mac!(a, b);
let _ = another_mac!(a, b);
let a = &mut [1, 2, 3];
let b = &mut [1, 2, 3];
// Do not lint: the rhs conversion is needed
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
//~^ ptr_eq
// Do not lint: we have two raw pointers already
let _ = a.as_mut_ptr() == b.as_mut_ptr();
//~^ ptr_eq
let _ = a == b;
let _ = core::ptr::eq(a, b);

View file

@ -13,29 +13,5 @@ error: use `core::ptr::eq` when comparing raw pointers
LL | let _ = a as *const _ == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a, b)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:35:13
|
LL | let _ = a.as_ptr() == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b as *const _)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:37:13
|
LL | let _ = a.as_ptr() == b.as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_ptr(), b.as_ptr())`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:48:13
|
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
error: use `core::ptr::eq` when comparing raw pointers
--> tests/ui/ptr_eq_no_std.rs:50:13
|
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
error: aborting due to 6 previous errors
error: aborting due to 2 previous errors