From cec69cdd6ae3dfff3a036b5e2ea6898e705490d9 Mon Sep 17 00:00:00 2001 From: Zihan Date: Tue, 23 Sep 2025 13:10:23 -0400 Subject: [PATCH] `ptr_cast_constness`: check for implicit mut to const pointer coercion changelog: [`ptr_cast_constness`]: check for implicit mut to const pointer coercion Signed-off-by: Zihan --- clippy_lints/src/casts/mod.rs | 1 + clippy_lints/src/casts/ptr_cast_constness.rs | 25 +++++++++++++++++++- tests/ui/ptr_cast_constness.fixed | 13 ++++++++++ tests/ui/ptr_cast_constness.rs | 13 ++++++++++ tests/ui/ptr_cast_constness.stderr | 20 +++++++++++++++- 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 47cc1da0a6e9..9c6aeff86732 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -919,5 +919,6 @@ impl<'tcx> LateLintPass<'tcx> for Casts { cast_ptr_alignment::check_cast_method(cx, expr); cast_slice_different_sizes::check(cx, expr, self.msrv); ptr_cast_constness::check_null_ptr_cast_method(cx, expr); + ptr_cast_constness::check_implicit_cast_from_mut(cx, expr, self.msrv); } } diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs index c0f13f5e5782..747b3ea9a093 100644 --- a/clippy_lints/src/casts/ptr_cast_constness.rs +++ b/clippy_lints/src/casts/ptr_cast_constness.rs @@ -2,10 +2,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{std_or_core, sym}; +use clippy_utils::{get_parent_expr, std_or_core, sym}; use rustc_errors::Applicability; use rustc_hir::{self as hir, Expr, ExprKind, QPath}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, PointerCoercion}; use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use super::PTR_CAST_CONSTNESS; @@ -102,3 +103,25 @@ pub(super) fn check_null_ptr_cast_method(cx: &LateContext<'_>, expr: &Expr<'_>) ); } } + +pub(super) fn check_implicit_cast_from_mut(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) { + if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) + && let ty::RawPtr(..) = cx.typeck_results().expr_ty(expr).kind() + && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..))) + && let [coercion] = cx.typeck_results().expr_adjustments(expr) + && let Adjust::Pointer(PointerCoercion::MutToConstPointer) = coercion.kind + && !expr.span.from_expansion() + { + let mut app = Applicability::MachineApplicable; + let sugg = Sugg::hir_with_applicability(cx, expr, "_", &mut app); + span_lint_and_sugg( + cx, + PTR_CAST_CONSTNESS, + expr.span, + "implicit casting from mut pointer to const pointer", + "try `pointer::cast_const`, a safer alternative", + format!("{}.cast_const()", sugg.maybe_paren()), + app, + ); + } +} diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed index cf57de53d9f3..f99f000fc211 100644 --- a/tests/ui/ptr_cast_constness.fixed +++ b/tests/ui/ptr_cast_constness.fixed @@ -112,3 +112,16 @@ fn issue11317() { let _ptr: *mut u32 = (r as *const u32).cast_mut(); //~^ ptr_cast_constness } + +/// Checks for implicit mut pointer to const pointer coercion +fn issue13667() { + fn expect_const_ptr(_: *const T) {} + + let p = &mut 0 as *mut i32; + let _: *const i32 = p.cast_const(); + //~^ ptr_cast_constness + expect_const_ptr(p.cast_const()); + //~^ ptr_cast_constness + let _: *const u8 = (p as *mut u8).cast_const(); + //~^ ptr_cast_constness +} diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs index ea53a0fa8c50..38ef796320cc 100644 --- a/tests/ui/ptr_cast_constness.rs +++ b/tests/ui/ptr_cast_constness.rs @@ -112,3 +112,16 @@ fn issue11317() { let _ptr: *mut u32 = r as *const _ as *mut _; //~^ ptr_cast_constness } + +/// Checks for implicit mut pointer to const pointer coercion +fn issue13667() { + fn expect_const_ptr(_: *const T) {} + + let p = &mut 0 as *mut i32; + let _: *const i32 = p; + //~^ ptr_cast_constness + expect_const_ptr(p); + //~^ ptr_cast_constness + let _: *const u8 = p as *mut u8; + //~^ ptr_cast_constness +} diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr index 4adb5cc5ad7f..3b5cd899c951 100644 --- a/tests/ui/ptr_cast_constness.stderr +++ b/tests/ui/ptr_cast_constness.stderr @@ -95,5 +95,23 @@ error: `as` casting between raw pointers while changing only its constness LL | let _ptr: *mut u32 = r as *const _ as *mut _; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(r as *const u32).cast_mut()` -error: aborting due to 15 previous errors +error: implicit casting from mut pointer to const pointer + --> tests/ui/ptr_cast_constness.rs:121:25 + | +LL | let _: *const i32 = p; + | ^ help: try `pointer::cast_const`, a safer alternative: `p.cast_const()` + +error: implicit casting from mut pointer to const pointer + --> tests/ui/ptr_cast_constness.rs:123:22 + | +LL | expect_const_ptr(p); + | ^ help: try `pointer::cast_const`, a safer alternative: `p.cast_const()` + +error: implicit casting from mut pointer to const pointer + --> tests/ui/ptr_cast_constness.rs:125:24 + | +LL | let _: *const u8 = p as *mut u8; + | ^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `(p as *mut u8).cast_const()` + +error: aborting due to 18 previous errors