diff --git a/CHANGELOG.md b/CHANGELOG.md index dafa3f3a1393..e2e02332e473 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4506,6 +4506,7 @@ Released 2018-09-13 [`arithmetic_side_effects`]: https://rust-lang.github.io/rust-clippy/master/index.html#arithmetic_side_effects [`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions [`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut +[`as_ptr_cast_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_underscore [`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore [`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants [`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states diff --git a/clippy_lints/src/casts/as_ptr_cast_underscore.rs b/clippy_lints/src/casts/as_ptr_cast_underscore.rs new file mode 100644 index 000000000000..d173bfaa6e54 --- /dev/null +++ b/clippy_lints/src/casts/as_ptr_cast_underscore.rs @@ -0,0 +1,33 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use if_chain::if_chain; +use rustc_hir::ExprKind; +use rustc_hir::{Expr, Mutability}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, TypeAndMut}; + +use super::AS_PTR_CAST_UNDERSCORE; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + if_chain! { + if let ExprKind::Cast(cast_expr, ..) = expr.kind; + let (cast_from, cast_to) = (cx.typeck_results().expr_ty(cast_expr), cx.typeck_results().expr_ty(expr)); + if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind(); + // check both mutability and type are the same + if cast_from.kind() == cast_to.kind(); + then { + let constness = match *from_mutbl { + Mutability::Not => "const", + Mutability::Mut => "mut", + }; + + span_lint_and_help( + cx, + AS_PTR_CAST_UNDERSCORE, + expr.span, + &format!("casting a raw pointer using `as *{constness} _` without changing type or constness"), + None, + "this is an extrenuous operation", + ); + } + } +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index cfeb75eed3bb..c80cc9b5df24 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,4 +1,5 @@ mod as_ptr_cast_mut; +mod as_ptr_cast_underscore; mod as_underscore; mod borrow_as_ptr; mod cast_abs_to_unsigned; @@ -422,6 +423,30 @@ declare_clippy_lint! { "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `as` casts between raw pointers that change neither its constness or type. + /// + /// ### Why is this bad? + /// It's an unnecessary operation. If the type and constness is the same, the cast can be entirely + /// emitted. + /// + /// ### Example + /// ```rust + /// let x = [10; 4]; + /// let px = x.as_ptr() as *const _; + /// ``` + /// Use instead: + /// ```rust + /// let x = [10; 4]; + /// let px = x.as_ptr(); + /// ``` + #[clippy::version = "1.71.0"] + pub AS_PTR_CAST_UNDERSCORE, + nursery, + "casting raw pointers that change neither its constness or type" +} + declare_clippy_lint! { /// ### What it does /// Checks for casts from an enum type to an integral type which will definitely truncate the @@ -696,6 +721,7 @@ impl_lint_pass!(Casts => [ BORROW_AS_PTR, CAST_SLICE_FROM_RAW_PARTS, AS_PTR_CAST_MUT, + AS_PTR_CAST_UNDERSCORE, CAST_NAN_TO_INT, ]); @@ -703,6 +729,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if !in_external_macro(cx.sess(), expr.span) { ptr_as_ptr::check(cx, expr, &self.msrv); + as_ptr_cast_underscore::check(cx, expr); } if expr.span.from_expansion() { diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs index a3a6f1746bcc..73d490c6b0f1 100644 --- a/clippy_lints/src/declared_lints.rs +++ b/clippy_lints/src/declared_lints.rs @@ -69,6 +69,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::cargo::REDUNDANT_FEATURE_NAMES_INFO, crate::cargo::WILDCARD_DEPENDENCIES_INFO, crate::casts::AS_PTR_CAST_MUT_INFO, + crate::casts::AS_PTR_CAST_UNDERSCORE_INFO, crate::casts::AS_UNDERSCORE_INFO, crate::casts::BORROW_AS_PTR_INFO, crate::casts::CAST_ABS_TO_UNSIGNED_INFO, diff --git a/tests/ui/as_ptr_cast_underscore.rs b/tests/ui/as_ptr_cast_underscore.rs new file mode 100644 index 000000000000..264d3014bea6 --- /dev/null +++ b/tests/ui/as_ptr_cast_underscore.rs @@ -0,0 +1,39 @@ +#![warn(clippy::as_ptr_cast_underscore)] +#![allow(dead_code)] +#![allow(unused)] + +static X: u32 = 0u32; + +fn takes_raw(a: *mut u32) -> *mut u32 { + a +} + +fn return_raw() -> *mut u32 { + // UB but i don't care + X as *mut u32 +} + +fn main() { + let e = return_raw() as *mut _; + let e = return_raw() as *const _; + let mut z = vec![11; 100]; + let z = z.as_mut_ptr() as *mut _; + // since this changes its type, this will not be linted + takes_raw(z); + + // this doesn't, however, so lint this + let mut z = [1u32; 2]; + let z = z.as_mut_ptr() as *mut _; + let z = takes_raw(z as *mut _) as *mut _; + + let mut x = [3; 11]; + // do not lint if it changes type + let z: *const u32 = x.as_ptr() as *const _; + // lint this + let w = x.as_ptr() as *const _; + let x = x.as_mut_ptr() as *mut _; + + // this is not a raw pointer. do not lint this. + let y = 1i32; + let y = y as i64; +} diff --git a/tests/ui/as_ptr_cast_underscore.stderr b/tests/ui/as_ptr_cast_underscore.stderr new file mode 100644 index 000000000000..9ca50e478d5d --- /dev/null +++ b/tests/ui/as_ptr_cast_underscore.stderr @@ -0,0 +1,51 @@ +error: casting a raw pointer using `as *mut _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:17:13 + | +LL | let e = return_raw() as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this is an extrenuous operation + = note: `-D clippy::as-ptr-cast-underscore` implied by `-D warnings` + +error: casting a raw pointer using `as *mut _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:26:13 + | +LL | let z = z.as_mut_ptr() as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this is an extrenuous operation + +error: casting a raw pointer using `as *mut _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:27:13 + | +LL | let z = takes_raw(z as *mut _) as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this is an extrenuous operation + +error: casting a raw pointer using `as *mut _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:27:23 + | +LL | let z = takes_raw(z as *mut _) as *mut _; + | ^^^^^^^^^^^ + | + = help: this is an extrenuous operation + +error: casting a raw pointer using `as *const _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:33:13 + | +LL | let w = x.as_ptr() as *const _; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this is an extrenuous operation + +error: casting a raw pointer using `as *mut _` without changing type or constness + --> $DIR/as_ptr_cast_underscore.rs:34:13 + | +LL | let x = x.as_mut_ptr() as *mut _; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this is an extrenuous operation + +error: aborting due to 6 previous errors +