diff options
| author | Zihan <zihanli0822@gmail.com> | 2025-08-07 18:27:13 -0400 |
|---|---|---|
| committer | Zihan <zihanli0822@gmail.com> | 2025-08-23 18:53:59 -0400 |
| commit | 02111a4d30fafde6db2a26edc60217a76670a5dc (patch) | |
| tree | bbb0e4504f35d1d380b35b83161c74358e169d5d | |
| parent | 264bc97b2623f29109e0ecb91d66cdb6c7b10a43 (diff) | |
| download | rust-02111a4d30fafde6db2a26edc60217a76670a5dc.tar.gz rust-02111a4d30fafde6db2a26edc60217a76670a5dc.zip | |
`cast_slice_from_raw_parts`: check for implicit cast to raw slice pointer
changelog: [`cast_slice_from_raw_parts`]: check for implicit cast to raw slice pointer Signed-off-by: Zihan <zihanli0822@gmail.com>
| -rw-r--r-- | clippy_lints/src/casts/cast_slice_from_raw_parts.rs | 39 | ||||
| -rw-r--r-- | clippy_lints/src/casts/mod.rs | 3 | ||||
| -rw-r--r-- | tests/ui/cast_raw_slice_pointer_cast.fixed | 25 | ||||
| -rw-r--r-- | tests/ui/cast_raw_slice_pointer_cast.rs | 25 | ||||
| -rw-r--r-- | tests/ui/cast_raw_slice_pointer_cast.stderr | 52 |
5 files changed, 134 insertions, 10 deletions
diff --git a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs index 46b0c88d3fe..24bfb735564 100644 --- a/clippy_lints/src/casts/cast_slice_from_raw_parts.rs +++ b/clippy_lints/src/casts/cast_slice_from_raw_parts.rs @@ -1,10 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::get_parent_expr; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::snippet_with_context; use rustc_errors::Applicability; use rustc_hir::def_id::DefId; use rustc_hir::{Expr, ExprKind}; use rustc_lint::LateContext; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::{self, Ty}; use rustc_span::sym; @@ -53,3 +55,40 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, ); } } + +/// Checks for implicit cast from slice reference to raw slice pointer. +pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) { + if let ExprKind::Call(fun, [ptr_arg, len_arg]) = expr.peel_blocks().kind + && let ExprKind::Path(ref qpath) = fun.kind + && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id() + && let Some(rpk) = raw_parts_kind(cx, fun_def_id) + && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..))) + && let [deref, borrow] = cx.typeck_results().expr_adjustments(expr) + && matches!(deref.kind, Adjust::Deref(..)) + && let Adjustment { + kind: Adjust::Borrow(AutoBorrow::RawPtr(..)), + target, + } = borrow + && let ty::RawPtr(pointee_ty, _) = target.kind() + && pointee_ty.is_slice() + && !expr.span.from_expansion() + { + let func = match rpk { + RawPartsKind::Immutable => "from_raw_parts", + RawPartsKind::Mutable => "from_raw_parts_mut", + }; + let mut applicability = Applicability::MachineApplicable; + let ctxt = expr.span.ctxt(); + let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0; + let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0; + span_lint_and_sugg( + cx, + CAST_SLICE_FROM_RAW_PARTS, + expr.span, + format!("implicitly casting the result of `{func}` to `{target}`"), + "replace_with", + format!("core::ptr::slice_{func}({ptr}, {len})"), + applicability, + ); + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index dcc439a272c..bbdb0eabbab 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -910,6 +910,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if self.msrv.meets(cx, msrvs::RAW_REF_OP) { borrow_as_ptr::check_implicit_cast(cx, expr); } + if self.msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) { + cast_slice_from_raw_parts::check_implicit_cast(cx, expr); + } cast_ptr_alignment::check(cx, expr); char_lit_as_u8::check(cx, expr); ptr_as_ptr::check(cx, expr, self.msrv); diff --git a/tests/ui/cast_raw_slice_pointer_cast.fixed b/tests/ui/cast_raw_slice_pointer_cast.fixed index bddcb0ebf64..14e232d0d2a 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -1,6 +1,7 @@ #![warn(clippy::cast_slice_from_raw_parts)] -#[allow(unused_imports, unused_unsafe)] +const fn require_raw_slice_ptr<T>(_: *const [T]) {} + fn main() { let mut vec = vec![0u8; 1]; let ptr: *const u8 = vec.as_ptr(); @@ -27,4 +28,26 @@ fn main() { let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1); //~^ cast_slice_from_raw_parts } + + // implicit cast + { + let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = std::ptr::null(); + const MPTR: *mut u8 = std::ptr::null_mut(); + let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; } diff --git a/tests/ui/cast_raw_slice_pointer_cast.rs b/tests/ui/cast_raw_slice_pointer_cast.rs index 0a1eb276d5e..8f57b1f9619 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/tests/ui/cast_raw_slice_pointer_cast.rs @@ -1,6 +1,7 @@ #![warn(clippy::cast_slice_from_raw_parts)] -#[allow(unused_imports, unused_unsafe)] +const fn require_raw_slice_ptr<T>(_: *const [T]) {} + fn main() { let mut vec = vec![0u8; 1]; let ptr: *const u8 = vec.as_ptr(); @@ -27,4 +28,26 @@ fn main() { let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; //~^ cast_slice_from_raw_parts } + + // implicit cast + { + let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) }); + //~^ cast_slice_from_raw_parts + } + + // implicit cast in const context + const { + const PTR: *const u8 = std::ptr::null(); + const MPTR: *mut u8 = std::ptr::null_mut(); + let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) }; + //~^ cast_slice_from_raw_parts + let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) }; + //~^ cast_slice_from_raw_parts + require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) }); + //~^ cast_slice_from_raw_parts + }; } diff --git a/tests/ui/cast_raw_slice_pointer_cast.stderr b/tests/ui/cast_raw_slice_pointer_cast.stderr index 60794a988db..e70cc593bb0 100644 --- a/tests/ui/cast_raw_slice_pointer_cast.stderr +++ b/tests/ui/cast_raw_slice_pointer_cast.stderr @@ -1,5 +1,5 @@ error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:8:35 + --> tests/ui/cast_raw_slice_pointer_cast.rs:9:35 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` @@ -8,40 +8,76 @@ LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *co = help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]` error: casting the result of `from_raw_parts_mut` to *mut [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:10:35 + --> tests/ui/cast_raw_slice_pointer_cast.rs:11:35 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:12:26 + --> tests/ui/cast_raw_slice_pointer_cast.rs:13:26 | LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:16:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:17:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:19:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:20:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:24:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:25:30 | LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` error: casting the result of `from_raw_parts` to *const [u8] - --> tests/ui/cast_raw_slice_pointer_cast.rs:27:30 + --> tests/ui/cast_raw_slice_pointer_cast.rs:28:30 | LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)` -error: aborting due to 7 previous errors +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:34:39 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:36:37 + | +LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:38:40 + | +LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:46:39 + | +LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)` + +error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:48:37 + | +LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(MPTR, 1)` + +error: implicitly casting the result of `from_raw_parts` to `*const [u8]` + --> tests/ui/cast_raw_slice_pointer_cast.rs:50:40 + | +LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)` + +error: aborting due to 13 previous errors |
