about summary refs log tree commit diff
path: root/clippy_lints/src/casts
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2023-06-02 11:41:57 +0200
committerPhilipp Krones <hello@philkrones.com>2023-06-02 11:41:57 +0200
commite6dc0efc0076690c0dcae05541fec771795ca84c (patch)
tree18b4bc307f398c6599d89f70859315a678554b76 /clippy_lints/src/casts
parentec2c6155aacbb92e2dba046e1560d9f28a61f077 (diff)
downloadrust-e6dc0efc0076690c0dcae05541fec771795ca84c.tar.gz
rust-e6dc0efc0076690c0dcae05541fec771795ca84c.zip
Merge commit '30448e8cf98d4754350db0c959644564f317bc0f' into clippyup
Diffstat (limited to 'clippy_lints/src/casts')
-rw-r--r--clippy_lints/src/casts/mod.rs33
-rw-r--r--clippy_lints/src/casts/ptr_cast_constness.rs44
2 files changed, 76 insertions, 1 deletions
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 0c175372aab..b90dab07a27 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -17,6 +17,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;
 
@@ -363,7 +364,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
@@ -388,6 +389,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.
     ///
@@ -652,6 +681,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,
@@ -685,6 +715,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,
+            );
+        }
+    }
+}