about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-05-23 21:40:50 +0000
committerbors <bors@rust-lang.org>2023-05-23 21:40:50 +0000
commita0fd17d3f0f97f03834e971137b8be75d0a57641 (patch)
treeeada6a95bd3f4558bd125b9e8eca8b9acb4d2cab
parent97598e9e8ffb2e5e211ae5ce9cf1fc96f643710a (diff)
parent97467e4aa39d20273014195bb7362d6bace047ea (diff)
downloadrust-a0fd17d3f0f97f03834e971137b8be75d0a57641.tar.gz
rust-a0fd17d3f0f97f03834e971137b8be75d0a57641.zip
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`]
-rw-r--r--CHANGELOG.md1
-rw-r--r--clippy_lints/src/casts/mod.rs33
-rw-r--r--clippy_lints/src/casts/ptr_cast_constness.rs44
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--tests/ui/ptr_cast_constness.fixed55
-rw-r--r--tests/ui/ptr_cast_constness.rs55
-rw-r--r--tests/ui/ptr_cast_constness.stderr34
8 files changed, 223 insertions, 2 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3dfc4f7b6a4..a2648d9faa6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4950,6 +4950,7 @@ Released 2018-09-13
 [`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
 [`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
 [`ptr_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
+[`ptr_cast_constness`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_cast_constness
 [`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
 [`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
 [`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index cfeb75eed3b..d62639caca1 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast;
 mod fn_to_numeric_cast_any;
 mod fn_to_numeric_cast_with_truncation;
 mod ptr_as_ptr;
+mod ptr_cast_constness;
 mod unnecessary_cast;
 mod utils;
 
@@ -399,7 +400,7 @@ declare_clippy_lint! {
     /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
     ///
     /// ### Why is this bad?
-    /// Though `as` casts between raw pointers is not terrible, `pointer::cast` is safer because
+    /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
     /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
     ///
     /// ### Example
@@ -424,6 +425,34 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
+    /// `*mut T` and `*mut T` to `*const T`.
+    ///
+    /// ### Why is this bad?
+    /// Though `as` casts between raw pointers are not terrible, `pointer::cast_mut` and
+    /// `pointer::cast_const` are safer because they cannot accidentally cast the pointer to another
+    /// type.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr = ptr as *mut u32;
+    /// let ptr = mut_ptr as *const u32;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let ptr: *const u32 = &42_u32;
+    /// let mut_ptr = ptr.cast_mut();
+    /// let ptr = mut_ptr.cast_const();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub PTR_CAST_CONSTNESS,
+    pedantic,
+    "casting using `as` from and to raw pointers to change constness when specialized methods apply"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for casts from an enum type to an integral type which will definitely truncate the
     /// value.
     ///
@@ -689,6 +718,7 @@ impl_lint_pass!(Casts => [
     FN_TO_NUMERIC_CAST_WITH_TRUNCATION,
     CHAR_LIT_AS_U8,
     PTR_AS_PTR,
+    PTR_CAST_CONSTNESS,
     CAST_ENUM_TRUNCATION,
     CAST_ENUM_CONSTRUCTOR,
     CAST_ABS_TO_UNSIGNED,
@@ -722,6 +752,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
                 return;
             }
             cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
+            ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
             as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
             fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to);
             fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to);
diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs
new file mode 100644
index 00000000000..ab015f8822e
--- /dev/null
+++ b/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -0,0 +1,44 @@
+use clippy_utils::msrvs::POINTER_CAST_CONSTNESS;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::{diagnostics::span_lint_and_sugg, msrvs::Msrv};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, Mutability};
+use rustc_lint::LateContext;
+use rustc_middle::ty::{self, Ty, TypeAndMut};
+
+use super::PTR_CAST_CONSTNESS;
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &Expr<'_>,
+    cast_expr: &Expr<'_>,
+    cast_from: Ty<'_>,
+    cast_to: Ty<'_>,
+    msrv: &Msrv,
+) {
+    if_chain! {
+        if msrv.meets(POINTER_CAST_CONSTNESS);
+        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
+        if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind();
+        if matches!((from_mutbl, to_mutbl),
+            (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not));
+        then {
+            let sugg = Sugg::hir(cx, cast_expr, "_");
+            let constness = match *to_mutbl {
+                Mutability::Not => "const",
+                Mutability::Mut => "mut",
+            };
+
+            span_lint_and_sugg(
+                cx,
+                PTR_CAST_CONSTNESS,
+                expr.span,
+                "`as` casting between raw pointers while changing its constness",
+                &format!("try `pointer::cast_{constness}`, a safer alternative"),
+                format!("{}.cast_{constness}()", sugg.maybe_par()),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index c225e376d14..4ade25e1257 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -90,6 +90,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
     crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
     crate::casts::PTR_AS_PTR_INFO,
+    crate::casts::PTR_CAST_CONSTNESS_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index e05de2dc99c..6f102308f0b 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -20,7 +20,7 @@ macro_rules! msrv_aliases {
 // names may refer to stabilized feature flags or library items
 msrv_aliases! {
     1,68,0 { PATH_MAIN_SEPARATOR_STR }
-    1,65,0 { LET_ELSE }
+    1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
     1,55,0 { SEEK_REWIND }
diff --git a/tests/ui/ptr_cast_constness.fixed b/tests/ui/ptr_cast_constness.fixed
new file mode 100644
index 00000000000..24de573d083
--- /dev/null
+++ b/tests/ui/ptr_cast_constness.fixed
@@ -0,0 +1,55 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::ptr_cast_constness)]
+
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
+
+#[inline_macros]
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = (*ptr_ptr).cast_mut();
+    }
+
+    let _ = ptr.cast_mut();
+    let _ = mut_ptr.cast_const();
+
+    // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Make sure the lint is triggered inside a macro
+    let _ = inline!($ptr as *const i32);
+
+    // Do not lint inside macros from external crates
+    let _ = external!($ptr as *const i32);
+}
+
+#[clippy::msrv = "1.64"]
+fn _msrv_1_64() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
+
+#[clippy::msrv = "1.65"]
+fn _msrv_1_65() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr.cast_mut();
+    let _ = mut_ptr.cast_const();
+}
diff --git a/tests/ui/ptr_cast_constness.rs b/tests/ui/ptr_cast_constness.rs
new file mode 100644
index 00000000000..63d973a9fca
--- /dev/null
+++ b/tests/ui/ptr_cast_constness.rs
@@ -0,0 +1,55 @@
+//@run-rustfix
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::ptr_cast_constness)]
+
+extern crate proc_macros;
+use proc_macros::{external, inline_macros};
+
+#[inline_macros]
+fn main() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *const i32;
+    let _ = mut_ptr as *mut i32;
+
+    // Make sure the lint can handle the difference in their operator precedences.
+    unsafe {
+        let ptr_ptr: *const *const u32 = &ptr;
+        let _ = *ptr_ptr as *mut i32;
+    }
+
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+
+    // Lint this, since pointer::cast_mut and pointer::cast_const have ?Sized
+    let ptr_of_array: *const [u32; 4] = &[1, 2, 3, 4];
+    let _ = ptr_of_array as *const [u32];
+    let _ = ptr_of_array as *const dyn std::fmt::Debug;
+
+    // Make sure the lint is triggered inside a macro
+    let _ = inline!($ptr as *const i32);
+
+    // Do not lint inside macros from external crates
+    let _ = external!($ptr as *const i32);
+}
+
+#[clippy::msrv = "1.64"]
+fn _msrv_1_64() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    // `pointer::cast_const` and `pointer::cast_mut` were stabilized in 1.65. Do not lint this
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
+
+#[clippy::msrv = "1.65"]
+fn _msrv_1_65() {
+    let ptr: *const u32 = &42_u32;
+    let mut_ptr: *mut u32 = &mut 42_u32;
+
+    let _ = ptr as *mut i32;
+    let _ = mut_ptr as *const i32;
+}
diff --git a/tests/ui/ptr_cast_constness.stderr b/tests/ui/ptr_cast_constness.stderr
new file mode 100644
index 00000000000..43816c87c19
--- /dev/null
+++ b/tests/ui/ptr_cast_constness.stderr
@@ -0,0 +1,34 @@
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:20:17
+   |
+LL |         let _ = *ptr_ptr as *mut i32;
+   |                 ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()`
+   |
+   = note: `-D clippy::ptr-cast-constness` implied by `-D warnings`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:23:13
+   |
+LL |     let _ = ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:24:13
+   |
+LL |     let _ = mut_ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:53:13
+   |
+LL |     let _ = ptr as *mut i32;
+   |             ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
+
+error: `as` casting between raw pointers while changing its constness
+  --> $DIR/ptr_cast_constness.rs:54:13
+   |
+LL |     let _ = mut_ptr as *const i32;
+   |             ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
+
+error: aborting due to 5 previous errors
+