Skip to content

Commit 02111a4

Browse files
committed
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 <[email protected]>
1 parent 264bc97 commit 02111a4

File tree

5 files changed

+134
-10
lines changed

5 files changed

+134
-10
lines changed

clippy_lints/src/casts/cast_slice_from_raw_parts.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::get_parent_expr;
23
use clippy_utils::msrvs::{self, Msrv};
34
use clippy_utils::source::snippet_with_context;
45
use rustc_errors::Applicability;
56
use rustc_hir::def_id::DefId;
67
use rustc_hir::{Expr, ExprKind};
78
use rustc_lint::LateContext;
9+
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
810
use rustc_middle::ty::{self, Ty};
911
use rustc_span::sym;
1012

@@ -53,3 +55,40 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
5355
);
5456
}
5557
}
58+
59+
/// Checks for implicit cast from slice reference to raw slice pointer.
60+
pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) {
61+
if let ExprKind::Call(fun, [ptr_arg, len_arg]) = expr.peel_blocks().kind
62+
&& let ExprKind::Path(ref qpath) = fun.kind
63+
&& let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
64+
&& let Some(rpk) = raw_parts_kind(cx, fun_def_id)
65+
&& !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..)))
66+
&& let [deref, borrow] = cx.typeck_results().expr_adjustments(expr)
67+
&& matches!(deref.kind, Adjust::Deref(..))
68+
&& let Adjustment {
69+
kind: Adjust::Borrow(AutoBorrow::RawPtr(..)),
70+
target,
71+
} = borrow
72+
&& let ty::RawPtr(pointee_ty, _) = target.kind()
73+
&& pointee_ty.is_slice()
74+
&& !expr.span.from_expansion()
75+
{
76+
let func = match rpk {
77+
RawPartsKind::Immutable => "from_raw_parts",
78+
RawPartsKind::Mutable => "from_raw_parts_mut",
79+
};
80+
let mut applicability = Applicability::MachineApplicable;
81+
let ctxt = expr.span.ctxt();
82+
let ptr = snippet_with_context(cx, ptr_arg.span, ctxt, "ptr", &mut applicability).0;
83+
let len = snippet_with_context(cx, len_arg.span, ctxt, "len", &mut applicability).0;
84+
span_lint_and_sugg(
85+
cx,
86+
CAST_SLICE_FROM_RAW_PARTS,
87+
expr.span,
88+
format!("implicitly casting the result of `{func}` to `{target}`"),
89+
"replace_with",
90+
format!("core::ptr::slice_{func}({ptr}, {len})"),
91+
applicability,
92+
);
93+
}
94+
}

clippy_lints/src/casts/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
910910
if self.msrv.meets(cx, msrvs::RAW_REF_OP) {
911911
borrow_as_ptr::check_implicit_cast(cx, expr);
912912
}
913+
if self.msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) {
914+
cast_slice_from_raw_parts::check_implicit_cast(cx, expr);
915+
}
913916
cast_ptr_alignment::check(cx, expr);
914917
char_lit_as_u8::check(cx, expr);
915918
ptr_as_ptr::check(cx, expr, self.msrv);

tests/ui/cast_raw_slice_pointer_cast.fixed

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(clippy::cast_slice_from_raw_parts)]
22

3-
#[allow(unused_imports, unused_unsafe)]
3+
const fn require_raw_slice_ptr<T>(_: *const [T]) {}
4+
45
fn main() {
56
let mut vec = vec![0u8; 1];
67
let ptr: *const u8 = vec.as_ptr();
@@ -27,4 +28,26 @@ fn main() {
2728
let _: *const [u8] = core::ptr::slice_from_raw_parts(ptr, 1);
2829
//~^ cast_slice_from_raw_parts
2930
}
31+
32+
// implicit cast
33+
{
34+
let _: *const [u8] = unsafe { core::ptr::slice_from_raw_parts(ptr, 1) };
35+
//~^ cast_slice_from_raw_parts
36+
let _: *mut [u8] = unsafe { core::ptr::slice_from_raw_parts_mut(mptr, 1) };
37+
//~^ cast_slice_from_raw_parts
38+
require_raw_slice_ptr(unsafe { core::ptr::slice_from_raw_parts(ptr, 1) });
39+
//~^ cast_slice_from_raw_parts
40+
}
41+
42+
// implicit cast in const context
43+
const {
44+
const PTR: *const u8 = std::ptr::null();
45+
const MPTR: *mut u8 = std::ptr::null_mut();
46+
let _: *const [u8] = unsafe { std::ptr::slice_from_raw_parts(PTR, 1) };
47+
//~^ cast_slice_from_raw_parts
48+
let _: *mut [u8] = unsafe { std::ptr::slice_from_raw_parts_mut(MPTR, 1) };
49+
//~^ cast_slice_from_raw_parts
50+
require_raw_slice_ptr(unsafe { std::ptr::slice_from_raw_parts(PTR, 1) });
51+
//~^ cast_slice_from_raw_parts
52+
};
3053
}

tests/ui/cast_raw_slice_pointer_cast.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![warn(clippy::cast_slice_from_raw_parts)]
22

3-
#[allow(unused_imports, unused_unsafe)]
3+
const fn require_raw_slice_ptr<T>(_: *const [T]) {}
4+
45
fn main() {
56
let mut vec = vec![0u8; 1];
67
let ptr: *const u8 = vec.as_ptr();
@@ -27,4 +28,26 @@ fn main() {
2728
let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
2829
//~^ cast_slice_from_raw_parts
2930
}
31+
32+
// implicit cast
33+
{
34+
let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) };
35+
//~^ cast_slice_from_raw_parts
36+
let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) };
37+
//~^ cast_slice_from_raw_parts
38+
require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) });
39+
//~^ cast_slice_from_raw_parts
40+
}
41+
42+
// implicit cast in const context
43+
const {
44+
const PTR: *const u8 = std::ptr::null();
45+
const MPTR: *mut u8 = std::ptr::null_mut();
46+
let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) };
47+
//~^ cast_slice_from_raw_parts
48+
let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) };
49+
//~^ cast_slice_from_raw_parts
50+
require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) });
51+
//~^ cast_slice_from_raw_parts
52+
};
3053
}
Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: casting the result of `from_raw_parts` to *const [u8]
2-
--> tests/ui/cast_raw_slice_pointer_cast.rs:8:35
2+
--> tests/ui/cast_raw_slice_pointer_cast.rs:9:35
33
|
44
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) as *const [u8] };
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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
88
= help: to override `-D warnings` add `#[allow(clippy::cast_slice_from_raw_parts)]`
99

1010
error: casting the result of `from_raw_parts_mut` to *mut [u8]
11-
--> tests/ui/cast_raw_slice_pointer_cast.rs:10:35
11+
--> tests/ui/cast_raw_slice_pointer_cast.rs:11:35
1212
|
1313
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) as *mut [u8] };
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
1515

1616
error: casting the result of `from_raw_parts` to *const [u8]
17-
--> tests/ui/cast_raw_slice_pointer_cast.rs:12:26
17+
--> tests/ui/cast_raw_slice_pointer_cast.rs:13:26
1818
|
1919
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) } as *const [u8];
2020
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
2121

2222
error: casting the result of `from_raw_parts` to *const [u8]
23-
--> tests/ui/cast_raw_slice_pointer_cast.rs:16:30
23+
--> tests/ui/cast_raw_slice_pointer_cast.rs:17:30
2424
|
2525
LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
2626
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
2727

2828
error: casting the result of `from_raw_parts` to *const [u8]
29-
--> tests/ui/cast_raw_slice_pointer_cast.rs:19:30
29+
--> tests/ui/cast_raw_slice_pointer_cast.rs:20:30
3030
|
3131
LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
3232
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
3333

3434
error: casting the result of `from_raw_parts` to *const [u8]
35-
--> tests/ui/cast_raw_slice_pointer_cast.rs:24:30
35+
--> tests/ui/cast_raw_slice_pointer_cast.rs:25:30
3636
|
3737
LL | let _: *const [u8] = unsafe { slice::from_raw_parts(ptr, 1) } as *const [u8];
3838
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
3939

4040
error: casting the result of `from_raw_parts` to *const [u8]
41-
--> tests/ui/cast_raw_slice_pointer_cast.rs:27:30
41+
--> tests/ui/cast_raw_slice_pointer_cast.rs:28:30
4242
|
4343
LL | let _: *const [u8] = unsafe { one::from_raw_parts(ptr, 1) } as *const [u8];
4444
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `core::ptr::slice_from_raw_parts(ptr, 1)`
4545

46-
error: aborting due to 7 previous errors
46+
error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
47+
--> tests/ui/cast_raw_slice_pointer_cast.rs:34:39
48+
|
49+
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(ptr, 1) };
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)`
51+
52+
error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
53+
--> tests/ui/cast_raw_slice_pointer_cast.rs:36:37
54+
|
55+
LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(mptr, 1) };
56+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts_mut(mptr, 1)`
57+
58+
error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
59+
--> tests/ui/cast_raw_slice_pointer_cast.rs:38:40
60+
|
61+
LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(ptr, 1) });
62+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `core::ptr::slice_from_raw_parts(ptr, 1)`
63+
64+
error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
65+
--> tests/ui/cast_raw_slice_pointer_cast.rs:46:39
66+
|
67+
LL | let _: *const [u8] = unsafe { std::slice::from_raw_parts(PTR, 1) };
68+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)`
69+
70+
error: implicitly casting the result of `from_raw_parts_mut` to `*mut [u8]`
71+
--> tests/ui/cast_raw_slice_pointer_cast.rs:48:37
72+
|
73+
LL | let _: *mut [u8] = unsafe { std::slice::from_raw_parts_mut(MPTR, 1) };
74+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts_mut(MPTR, 1)`
75+
76+
error: implicitly casting the result of `from_raw_parts` to `*const [u8]`
77+
--> tests/ui/cast_raw_slice_pointer_cast.rs:50:40
78+
|
79+
LL | require_raw_slice_ptr(unsafe { std::slice::from_raw_parts(PTR, 1) });
80+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace_with: `std::ptr::slice_from_raw_parts(PTR, 1)`
81+
82+
error: aborting due to 13 previous errors
4783

0 commit comments

Comments
 (0)