Skip to content

Commit a0fd17d

Browse files
committed
Auto merge of #10779 - Centri3:ptr_cast_constness, r=llogiq
Add new lint `ptr_cast_constness` This adds a new lint which functions as the opposite side of the coin to `ptr_as_ptr`. Rather than linting only as casts that don't change constness, this lints only constness; suggesting to use `pointer::cast_const` or `pointer::cast_mut` instead. changelog: new lint [`ptr_cast_constness`]
2 parents 97598e9 + 97467e4 commit a0fd17d

File tree

8 files changed

+223
-2
lines changed

8 files changed

+223
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4950,6 +4950,7 @@ Released 2018-09-13
49504950
[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
49514951
[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
49524952
[`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
4953+
[`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness
49534954
[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
49544955
[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
49554956
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names

clippy_lints/src/casts/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast;
1818
mod fn_to_numeric_cast_any;
1919
mod fn_to_numeric_cast_with_truncation;
2020
mod ptr_as_ptr;
21+
mod ptr_cast_constness;
2122
mod unnecessary_cast;
2223
mod utils;
2324

@@ -399,7 +400,7 @@ declare_clippy_lint! {
399400
/// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
400401
///
401402
/// ### Why is this bad?
402-
/// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
403+
/// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
403404
/// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
404405
///
405406
/// ### Example
@@ -422,6 +423,34 @@ declare_clippy_lint! {
422423
"casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
423424
}
424425

426+
declare_clippy_lint! {
427+
/// ### What it does
428+
/// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
429+
/// `*mut T` and `*mut T` to `*const T`.
430+
///
431+
/// ### Why is this bad?
432+
/// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and
433+
/// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another
434+
/// type.
435+
///
436+
/// ### Example
437+
/// ```rust
438+
/// let ptr: *const u32 = &42_u32;
439+
/// let mut_ptr = ptr as *mut u32;
440+
/// let ptr = mut_ptr as *const u32;
441+
/// ```
442+
/// Use instead:
443+
/// ```rust
444+
/// let ptr: *const u32 = &42_u32;
445+
/// let mut_ptr = ptr.cast_mut();
446+
/// let ptr = mut_ptr.cast_const();
447+
/// ```
448+
#[clippy::version = "1.71.0"]
449+
pub PTR_CAST_CONSTNESS,
450+
pedantic,
451+
"casting using `as` from and to raw pointers to change constness when specialized methods apply"
452+
}
453+
425454
declare_clippy_lint! {
426455
/// ### What it does
427456
/// Checks for casts from an enum type to an integral type which will definitely truncate the
@@ -689,6 +718,7 @@ impl_lint_pass!(Casts => [
689718
FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
690719
CHAR_LIT_AS_U8,
691720
PTR_AS_PTR,
721+
PTR_CAST_CONSTNESS,
692722
CAST_ENUM_TRUNCATION,
693723
CAST_ENUM_CONSTRUCTOR,
694724
CAST_ABS_TO_UNSIGNED,
@@ -722,6 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
722752
return;
723753
}
724754
cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
755+
ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
725756
as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
726757
fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
727758
fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use clippy_utils::msrvs::POINTER_CAST_CONSTNESS;
2+
use clippy_utils::sugg::Sugg;
3+
use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv};
4+
use if_chain::if_chain;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, Mutability};
7+
use rustc_lint::LateContext;
8+
use rustc_middle::ty::{self, Ty, TypeAndMut};
9+
10+
use super::PTR_CAST_CONSTNESS;
11+
12+
pub(super) fn check(
13+
cx: &LateContext<'_>,
14+
expr: &Expr<'_>,
15+
cast_expr: &Expr<'_>,
16+
cast_from: Ty<'_>,
17+
cast_to: Ty<'_>,
18+
msrv: &Msrv,
19+
) {
20+
if_chain! {
21+
if msrv.meets(POINTER_CAST_CONSTNESS);
22+
if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
23+
if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind();
24+
if matches!((from_mutbl, to_mutbl),
25+
(Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not));
26+
then {
27+
let sugg = Sugg::hir(cx, cast_expr, "_");
28+
let constness = match *to_mutbl {
29+
Mutability::Not => "const",
30+
Mutability::Mut => "mut",
31+
};
32+
33+
span_lint_and_sugg(
34+
cx,
35+
PTR_CAST_CONSTNESS,
36+
expr.span,
37+
"`as` casting between raw pointers while changing its constness",
38+
&format!("try `pointer::cast_{constness}`, a safer alternative"),
39+
format!("{}.cast_{constness}()", sugg.maybe_par()),
40+
Applicability::MachineApplicable,
41+
);
42+
}
43+
}
44+
}

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
9090
crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
9191
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
9292
crate::casts::PTR_AS_PTR_INFO,
93+
crate::casts::PTR_CAST_CONSTNESS_INFO,
9394
crate::casts::UNNECESSARY_CAST_INFO,
9495
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
9596
crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,

clippy_utils/src/msrvs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ macro_rules! msrv_aliases {
2020
// names may refer to stabilized feature flags or library items
2121
msrv_aliases! {
2222
1,68,0 { PATH_MAIN_SEPARATOR_STR }
23-
1,65,0 { LET_ELSE }
23+
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
2424
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
2525
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
2626
1,55,0 { SEEK_REWIND }

tests/ui/ptr_cast_constness.fixed

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@run-rustfix
2+
//@aux-build:proc_macros.rs
3+
4+
#![warn(clippy::ptr_cast_constness)]
5+
6+
extern crate proc_macros;
7+
use proc_macros::{external, inline_macros};
8+
9+
#[inline_macros]
10+
fn main() {
11+
let ptr: *const u32 = &42_u32;
12+
let mut_ptr: *mut u32 = &mut 42_u32;
13+
14+
let _ = ptr as *const i32;
15+
let _ = mut_ptr as *mut i32;
16+
17+
// Make sure the lint can handle the difference in their operator precedences.
18+
unsafe {
19+
let ptr_ptr: *const *const u32 = &ptr;
20+
let _ = (*ptr_ptr).cast_mut();
21+
}
22+
23+
let _ = ptr.cast_mut();
24+
let _ = mut_ptr.cast_const();
25+
26+
// Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
27+
let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
28+
let _ = ptr_of_array as *const [u32];
29+
let _ = ptr_of_array as *const dyn std::fmt::Debug;
30+
31+
// Make sure the lint is triggered inside a macro
32+
let _ = inline!($ptr as *const i32);
33+
34+
// Do not lint inside macros from external crates
35+
let _ = external!($ptr as *const i32);
36+
}
37+
38+
#[clippy::msrv = "1.64"]
39+
fn _msrv_1_64() {
40+
let ptr: *const u32 = &42_u32;
41+
let mut_ptr: *mut u32 = &mut 42_u32;
42+
43+
// `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
44+
let _ = ptr as *mut i32;
45+
let _ = mut_ptr as *const i32;
46+
}
47+
48+
#[clippy::msrv = "1.65"]
49+
fn _msrv_1_65() {
50+
let ptr: *const u32 = &42_u32;
51+
let mut_ptr: *mut u32 = &mut 42_u32;
52+
53+
let _ = ptr.cast_mut();
54+
let _ = mut_ptr.cast_const();
55+
}

tests/ui/ptr_cast_constness.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//@run-rustfix
2+
//@aux-build:proc_macros.rs
3+
4+
#![warn(clippy::ptr_cast_constness)]
5+
6+
extern crate proc_macros;
7+
use proc_macros::{external, inline_macros};
8+
9+
#[inline_macros]
10+
fn main() {
11+
let ptr: *const u32 = &42_u32;
12+
let mut_ptr: *mut u32 = &mut 42_u32;
13+
14+
let _ = ptr as *const i32;
15+
let _ = mut_ptr as *mut i32;
16+
17+
// Make sure the lint can handle the difference in their operator precedences.
18+
unsafe {
19+
let ptr_ptr: *const *const u32 = &ptr;
20+
let _ = *ptr_ptr as *mut i32;
21+
}
22+
23+
let _ = ptr as *mut i32;
24+
let _ = mut_ptr as *const i32;
25+
26+
// Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
27+
let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
28+
let _ = ptr_of_array as *const [u32];
29+
let _ = ptr_of_array as *const dyn std::fmt::Debug;
30+
31+
// Make sure the lint is triggered inside a macro
32+
let _ = inline!($ptr as *const i32);
33+
34+
// Do not lint inside macros from external crates
35+
let _ = external!($ptr as *const i32);
36+
}
37+
38+
#[clippy::msrv = "1.64"]
39+
fn _msrv_1_64() {
40+
let ptr: *const u32 = &42_u32;
41+
let mut_ptr: *mut u32 = &mut 42_u32;
42+
43+
// `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
44+
let _ = ptr as *mut i32;
45+
let _ = mut_ptr as *const i32;
46+
}
47+
48+
#[clippy::msrv = "1.65"]
49+
fn _msrv_1_65() {
50+
let ptr: *const u32 = &42_u32;
51+
let mut_ptr: *mut u32 = &mut 42_u32;
52+
53+
let _ = ptr as *mut i32;
54+
let _ = mut_ptr as *const i32;
55+
}

tests/ui/ptr_cast_constness.stderr

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
error: `as` casting between raw pointers while changing its constness
2+
--> $DIR/ptr_cast_constness.rs:20:17
3+
|
4+
LL | let _ = *ptr_ptr as *mut i32;
5+
| ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()`
6+
|
7+
= note: `-D clippy::ptr-cast-constness` implied by `-D warnings`
8+
9+
error: `as` casting between raw pointers while changing its constness
10+
--> $DIR/ptr_cast_constness.rs:23:13
11+
|
12+
LL | let _ = ptr as *mut i32;
13+
| ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
14+
15+
error: `as` casting between raw pointers while changing its constness
16+
--> $DIR/ptr_cast_constness.rs:24:13
17+
|
18+
LL | let _ = mut_ptr as *const i32;
19+
| ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
20+
21+
error: `as` casting between raw pointers while changing its constness
22+
--> $DIR/ptr_cast_constness.rs:53:13
23+
|
24+
LL | let _ = ptr as *mut i32;
25+
| ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
26+
27+
error: `as` casting between raw pointers while changing its constness
28+
--> $DIR/ptr_cast_constness.rs:54:13
29+
|
30+
LL | let _ = mut_ptr as *const i32;
31+
| ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
32+
33+
error: aborting due to 5 previous errors
34+

0 commit comments

Comments
 (0)