Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new lint: ref_as_ptr #12087

Merged
merged 1 commit into from
Feb 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5522,6 +5522,7 @@ Released 2018-09-13
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations
[`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.

[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)

Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
Expand Down
2 changes: 1 addition & 1 deletion book/src/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
A collection of lints to catch common mistakes and improve your
[Rust](https://github.com/rust-lang/rust) code.

[There are over 650 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
[There are over 700 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)

Lints are divided into categories, each with a default [lint
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
Expand Down
1 change: 1 addition & 0 deletions clippy_config/src/msrvs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ macro_rules! msrv_aliases {

// names may refer to stabilized feature flags or library items
msrv_aliases! {
1,76,0 { PTR_FROM_REF }
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
1,68,0 { PATH_MAIN_SEPARATOR_STR }
Expand Down
30 changes: 29 additions & 1 deletion clippy_lints/src/casts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod fn_to_numeric_cast_any;
mod fn_to_numeric_cast_with_truncation;
mod ptr_as_ptr;
mod ptr_cast_constness;
mod ref_as_ptr;
mod unnecessary_cast;
mod utils;
mod zero_ptr;
Expand Down Expand Up @@ -689,6 +690,30 @@ declare_clippy_lint! {
"using `0 as *{const, mut} T`"
}

declare_clippy_lint! {
/// ### What it does
/// Checks for casts of references to pointer using `as`
/// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead.
///
/// ### Why is this bad?
/// Using `as` casts may result in silently changing mutability or type.
///
/// ### Example
/// ```no_run
/// let a_ref = &1;
/// let a_ptr = a_ref as *const _;
/// ```
/// Use instead:
/// ```no_run
/// let a_ref = &1;
/// let a_ptr = std::ptr::from_ref(a_ref);
/// ```
#[clippy::version = "1.77.0"]
pub REF_AS_PTR,
pedantic,
"using `as` to cast a reference to pointer"
}

pub struct Casts {
msrv: Msrv,
}
Expand Down Expand Up @@ -724,6 +749,7 @@ impl_lint_pass!(Casts => [
AS_PTR_CAST_MUT,
CAST_NAN_TO_INT,
ZERO_PTR,
REF_AS_PTR,
]);

impl<'tcx> LateLintPass<'tcx> for Casts {
Expand Down Expand Up @@ -771,7 +797,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {

as_underscore::check(cx, expr, cast_to_hir);

if self.msrv.meets(msrvs::BORROW_AS_PTR) {
if self.msrv.meets(msrvs::PTR_FROM_REF) {
ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
} else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
}
}
Expand Down
55 changes: 55 additions & 0 deletions clippy_lints/src/casts/ref_as_ptr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_no_std_crate;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, Mutability, Ty, TyKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, TypeAndMut};

use super::REF_AS_PTR;

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_hir_ty: &Ty<'_>) {
let (cast_from, cast_to) = (
cx.typeck_results().expr_ty(cast_expr),
cx.typeck_results().expr_ty(expr),
);

if matches!(cast_from.kind(), ty::Ref(..))
&& let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind()
{
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
let fn_name = match to_mutbl {
Mutability::Not => "from_ref",
Mutability::Mut => "from_mut",
};

let mut app = Applicability::MachineApplicable;
let turbofish = match &cast_to_hir_ty.kind {
TyKind::Infer => String::new(),
TyKind::Ptr(mut_ty) => {
if matches!(mut_ty.ty.kind, TyKind::Infer) {
String::new()
} else {
format!(
"::<{}>",
snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
)
}
},
_ => return,
};

let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);

span_lint_and_sugg(
cx,
REF_AS_PTR,
expr.span,
"reference as raw pointer",
"try",
format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
app,
);
}
}
1 change: 1 addition & 0 deletions clippy_lints/src/declared_lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
crate::casts::PTR_AS_PTR_INFO,
crate::casts::PTR_CAST_CONSTNESS_INFO,
crate::casts::REF_AS_PTR_INFO,
crate::casts::UNNECESSARY_CAST_INFO,
crate::casts::ZERO_PTR_INFO,
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
Expand Down
5 changes: 2 additions & 3 deletions clippy_lints/src/only_used_in_recursion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
{
(
trait_item_id,
FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize),
usize::from(sig.decl.implicit_self.has_implicit_self()),
)
} else {
Expand Down Expand Up @@ -390,7 +390,6 @@ fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
}),
#[allow(trivial_casts)]
FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
FnKind::ImplTraitFn(expected_args) => std::ptr::from_ref(args) as usize == expected_args,
}
}
1 change: 1 addition & 0 deletions tests/ui/borrow_as_ptr.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fn a() -> i32 {
0
}

#[clippy::msrv = "1.75"]
fn main() {
let val = 1;
let _p = std::ptr::addr_of!(val);
Expand Down
1 change: 1 addition & 0 deletions tests/ui/borrow_as_ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ fn a() -> i32 {
0
}

#[clippy::msrv = "1.75"]
fn main() {
let val = 1;
let _p = &val as *const i32;
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/borrow_as_ptr.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: borrow as raw pointer
--> $DIR/borrow_as_ptr.rs:10:14
--> $DIR/borrow_as_ptr.rs:11:14
|
LL | let _p = &val as *const i32;
| ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)`
Expand All @@ -8,7 +8,7 @@ LL | let _p = &val as *const i32;
= help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`

error: borrow as raw pointer
--> $DIR/borrow_as_ptr.rs:17:18
--> $DIR/borrow_as_ptr.rs:18:18
|
LL | let _p_mut = &mut val_mut as *mut i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`
Expand Down
1 change: 1 addition & 0 deletions tests/ui/borrow_as_ptr_no_std.fixed
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(lang_items, start, libc)]
#![no_std]

#[clippy::msrv = "1.75"]
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
let val = 1;
Expand Down
1 change: 1 addition & 0 deletions tests/ui/borrow_as_ptr_no_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(lang_items, start, libc)]
#![no_std]

#[clippy::msrv = "1.75"]
#[start]
fn main(_argc: isize, _argv: *const *const u8) -> isize {
let val = 1;
Expand Down
4 changes: 2 additions & 2 deletions tests/ui/borrow_as_ptr_no_std.stderr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
error: borrow as raw pointer
--> $DIR/borrow_as_ptr_no_std.rs:8:14
--> $DIR/borrow_as_ptr_no_std.rs:9:14
|
LL | let _p = &val as *const i32;
| ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
Expand All @@ -8,7 +8,7 @@ LL | let _p = &val as *const i32;
= help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`

error: borrow as raw pointer
--> $DIR/borrow_as_ptr_no_std.rs:11:18
--> $DIR/borrow_as_ptr_no_std.rs:12:18
|
LL | let _p_mut = &mut val_mut as *mut i32;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`
Expand Down
110 changes: 110 additions & 0 deletions tests/ui/ref_as_ptr.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#![warn(clippy::ref_as_ptr)]
#![allow(clippy::unnecessary_mut_passed)]

fn main() {
let _ = std::ptr::from_ref(&1u8);
let _ = std::ptr::from_ref::<u32>(&2u32);
let _ = std::ptr::from_ref::<f64>(&3.0f64);

let _ = std::ptr::from_ref(&4) as *const f32;
let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;

let _ = std::ptr::from_ref(&mut 6u8);
let _ = std::ptr::from_ref::<u32>(&mut 7u32);
let _ = std::ptr::from_ref::<f64>(&mut 8.0f64);

let _ = std::ptr::from_ref(&mut 9) as *const f32;
let _ = std::ptr::from_ref::<f32>(&mut 10.0f32) as *const u32;

let _ = std::ptr::from_mut(&mut 11u8);
let _ = std::ptr::from_mut::<u32>(&mut 12u32);
let _ = std::ptr::from_mut::<f64>(&mut 13.0f64);

let _ = std::ptr::from_mut(&mut 14) as *const f32;
let _ = std::ptr::from_mut::<f32>(&mut 15.0f32) as *const u32;

let _ = std::ptr::from_ref(&1u8);
let _ = std::ptr::from_ref::<u32>(&2u32);
let _ = std::ptr::from_ref::<f64>(&3.0f64);

let _ = std::ptr::from_ref(&4) as *const f32;
let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;

let val = 1;
let _ = std::ptr::from_ref(&val);
let _ = std::ptr::from_ref::<i32>(&val);

let _ = std::ptr::from_ref(&val) as *const f32;
let _ = std::ptr::from_ref::<i32>(&val) as *const f64;

let mut val: u8 = 2;
let _ = std::ptr::from_mut::<u8>(&mut val);
let _ = std::ptr::from_mut(&mut val);

let _ = std::ptr::from_ref::<u8>(&mut val);
let _ = std::ptr::from_ref(&mut val);

let _ = std::ptr::from_ref::<u8>(&mut val) as *const f64;
let _: *const Option<u8> = std::ptr::from_ref(&mut val) as *const _;

let _ = std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i));
let _ = std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i));
let _ = std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i));
}

#[clippy::msrv = "1.75"]
fn _msrv_1_75() {
let val = &42_i32;
let mut_val = &mut 42_i32;

// `std::ptr::from_{ref, mut}` was stabilized in 1.76. Do not lint this
let _ = val as *const i32;
let _ = mut_val as *mut i32;
}

#[clippy::msrv = "1.76"]
fn _msrv_1_76() {
let val = &42_i32;
let mut_val = &mut 42_i32;

let _ = std::ptr::from_ref::<i32>(val);
let _ = std::ptr::from_mut::<i32>(mut_val);
}

fn foo(val: &[u8]) {
let _ = std::ptr::from_ref(val);
let _ = std::ptr::from_ref::<[u8]>(val);
}

fn bar(val: &mut str) {
let _ = std::ptr::from_mut(val);
let _ = std::ptr::from_mut::<str>(val);
}

struct X<'a>(&'a i32);

impl<'a> X<'a> {
fn foo(&self) -> *const i64 {
std::ptr::from_ref(self.0) as *const _
}

fn bar(&mut self) -> *const i64 {
std::ptr::from_ref(self.0) as *const _
}
}

struct Y<'a>(&'a mut i32);

impl<'a> Y<'a> {
fn foo(&self) -> *const i64 {
std::ptr::from_ref(self.0) as *const _
}

fn bar(&mut self) -> *const i64 {
std::ptr::from_ref(self.0) as *const _
}

fn baz(&mut self) -> *const i64 {
std::ptr::from_mut(self.0) as *mut _
}
}
Loading
Loading