Skip to content

Commit a3baebc

Browse files
marcin-serwinblyxyas
authored andcommitted
Add ref_as_ptr lint
Author: Marcin Serwin <[email protected]>
1 parent bc962c2 commit a3baebc

17 files changed

+588
-10
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5522,6 +5522,7 @@ Released 2018-09-13
55225522
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
55235523
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
55245524
[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations
5525+
[`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
55255526
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
55265527
[`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref
55275528
[`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

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

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

1010
Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
1111
You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.

book/src/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
A collection of lints to catch common mistakes and improve your
77
[Rust](https://github.com/rust-lang/rust) code.
88

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

1111
Lints are divided into categories, each with a default [lint
1212
level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how

clippy_config/src/msrvs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ macro_rules! msrv_aliases {
1616

1717
// names may refer to stabilized feature flags or library items
1818
msrv_aliases! {
19+
1,76,0 { PTR_FROM_REF }
1920
1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
2021
1,70,0 { OPTION_RESULT_IS_VARIANT_AND, BINARY_HEAP_RETAIN }
2122
1,68,0 { PATH_MAIN_SEPARATOR_STR }

clippy_lints/src/casts/mod.rs

+29-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ mod fn_to_numeric_cast_any;
1818
mod fn_to_numeric_cast_with_truncation;
1919
mod ptr_as_ptr;
2020
mod ptr_cast_constness;
21+
mod ref_as_ptr;
2122
mod unnecessary_cast;
2223
mod utils;
2324
mod zero_ptr;
@@ -689,6 +690,30 @@ declare_clippy_lint! {
689690
"using `0 as *{const, mut} T`"
690691
}
691692

693+
declare_clippy_lint! {
694+
/// ### What it does
695+
/// Checks for casts of references to pointer using `as`
696+
/// and suggests `std::ptr::from_ref` and `std::ptr::from_mut` instead.
697+
///
698+
/// ### Why is this bad?
699+
/// Using `as` casts may result in silently changing mutability or type.
700+
///
701+
/// ### Example
702+
/// ```no_run
703+
/// let a_ref = &1;
704+
/// let a_ptr = a_ref as *const _;
705+
/// ```
706+
/// Use instead:
707+
/// ```no_run
708+
/// let a_ref = &1;
709+
/// let a_ptr = std::ptr::from_ref(a_ref);
710+
/// ```
711+
#[clippy::version = "1.77.0"]
712+
pub REF_AS_PTR,
713+
pedantic,
714+
"using `as` to cast a reference to pointer"
715+
}
716+
692717
pub struct Casts {
693718
msrv: Msrv,
694719
}
@@ -724,6 +749,7 @@ impl_lint_pass!(Casts => [
724749
AS_PTR_CAST_MUT,
725750
CAST_NAN_TO_INT,
726751
ZERO_PTR,
752+
REF_AS_PTR,
727753
]);
728754

729755
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -771,7 +797,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
771797

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

774-
if self.msrv.meets(msrvs::BORROW_AS_PTR) {
800+
if self.msrv.meets(msrvs::PTR_FROM_REF) {
801+
ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
802+
} else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
775803
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
776804
}
777805
}

clippy_lints/src/casts/ref_as_ptr.rs

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::is_no_std_crate;
3+
use clippy_utils::source::snippet_with_applicability;
4+
use clippy_utils::sugg::Sugg;
5+
use rustc_errors::Applicability;
6+
use rustc_hir::{Expr, Mutability, Ty, TyKind};
7+
use rustc_lint::LateContext;
8+
use rustc_middle::ty::{self, TypeAndMut};
9+
10+
use super::REF_AS_PTR;
11+
12+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to_hir_ty: &Ty<'_>) {
13+
let (cast_from, cast_to) = (
14+
cx.typeck_results().expr_ty(cast_expr),
15+
cx.typeck_results().expr_ty(expr),
16+
);
17+
18+
if matches!(cast_from.kind(), ty::Ref(..))
19+
&& let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind()
20+
{
21+
let core_or_std = if is_no_std_crate(cx) { "core" } else { "std" };
22+
let fn_name = match to_mutbl {
23+
Mutability::Not => "from_ref",
24+
Mutability::Mut => "from_mut",
25+
};
26+
27+
let mut app = Applicability::MachineApplicable;
28+
let turbofish = match &cast_to_hir_ty.kind {
29+
TyKind::Infer => String::new(),
30+
TyKind::Ptr(mut_ty) => {
31+
if matches!(mut_ty.ty.kind, TyKind::Infer) {
32+
String::new()
33+
} else {
34+
format!(
35+
"::<{}>",
36+
snippet_with_applicability(cx, mut_ty.ty.span, "/* type */", &mut app)
37+
)
38+
}
39+
},
40+
_ => return,
41+
};
42+
43+
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut app);
44+
45+
span_lint_and_sugg(
46+
cx,
47+
REF_AS_PTR,
48+
expr.span,
49+
"reference as raw pointer",
50+
"try",
51+
format!("{core_or_std}::ptr::{fn_name}{turbofish}({cast_expr_sugg})"),
52+
app,
53+
);
54+
}
55+
}

clippy_lints/src/declared_lints.rs

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
9696
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
9797
crate::casts::PTR_AS_PTR_INFO,
9898
crate::casts::PTR_CAST_CONSTNESS_INFO,
99+
crate::casts::REF_AS_PTR_INFO,
99100
crate::casts::UNNECESSARY_CAST_INFO,
100101
crate::casts::ZERO_PTR_INFO,
101102
crate::checked_conversions::CHECKED_CONVERSIONS_INFO,

clippy_lints/src/only_used_in_recursion.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
252252
{
253253
(
254254
trait_item_id,
255-
FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.args) as *const _ as usize),
255+
FnKind::ImplTraitFn(std::ptr::from_ref(cx.tcx.erase_regions(trait_ref.args)) as usize),
256256
usize::from(sig.decl.implicit_self.has_implicit_self()),
257257
)
258258
} else {
@@ -390,7 +390,6 @@ fn has_matching_args(kind: FnKind, args: GenericArgsRef<'_>) -> bool {
390390
GenericArgKind::Type(ty) => matches!(*ty.kind(), ty::Param(ty) if ty.index as usize == idx),
391391
GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
392392
}),
393-
#[allow(trivial_casts)]
394-
FnKind::ImplTraitFn(expected_args) => args as *const _ as usize == expected_args,
393+
FnKind::ImplTraitFn(expected_args) => std::ptr::from_ref(args) as usize == expected_args,
395394
}
396395
}

tests/ui/borrow_as_ptr.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ fn a() -> i32 {
55
0
66
}
77

8+
#[clippy::msrv = "1.75"]
89
fn main() {
910
let val = 1;
1011
let _p = std::ptr::addr_of!(val);

tests/ui/borrow_as_ptr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ fn a() -> i32 {
55
0
66
}
77

8+
#[clippy::msrv = "1.75"]
89
fn main() {
910
let val = 1;
1011
let _p = &val as *const i32;

tests/ui/borrow_as_ptr.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: borrow as raw pointer
2-
--> $DIR/borrow_as_ptr.rs:10:14
2+
--> $DIR/borrow_as_ptr.rs:11:14
33
|
44
LL | let _p = &val as *const i32;
55
| ^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL | let _p = &val as *const i32;
88
= help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
99

1010
error: borrow as raw pointer
11-
--> $DIR/borrow_as_ptr.rs:17:18
11+
--> $DIR/borrow_as_ptr.rs:18:18
1212
|
1313
LL | let _p_mut = &mut val_mut as *mut i32;
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::addr_of_mut!(val_mut)`

tests/ui/borrow_as_ptr_no_std.fixed

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(lang_items, start, libc)]
33
#![no_std]
44

5+
#[clippy::msrv = "1.75"]
56
#[start]
67
fn main(_argc: isize, _argv: *const *const u8) -> isize {
78
let val = 1;

tests/ui/borrow_as_ptr_no_std.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#![feature(lang_items, start, libc)]
33
#![no_std]
44

5+
#[clippy::msrv = "1.75"]
56
#[start]
67
fn main(_argc: isize, _argv: *const *const u8) -> isize {
78
let val = 1;

tests/ui/borrow_as_ptr_no_std.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: borrow as raw pointer
2-
--> $DIR/borrow_as_ptr_no_std.rs:8:14
2+
--> $DIR/borrow_as_ptr_no_std.rs:9:14
33
|
44
LL | let _p = &val as *const i32;
55
| ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)`
@@ -8,7 +8,7 @@ LL | let _p = &val as *const i32;
88
= help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]`
99

1010
error: borrow as raw pointer
11-
--> $DIR/borrow_as_ptr_no_std.rs:11:18
11+
--> $DIR/borrow_as_ptr_no_std.rs:12:18
1212
|
1313
LL | let _p_mut = &mut val_mut as *mut i32;
1414
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)`

tests/ui/ref_as_ptr.fixed

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
#![warn(clippy::ref_as_ptr)]
2+
#![allow(clippy::unnecessary_mut_passed)]
3+
4+
fn main() {
5+
let _ = std::ptr::from_ref(&1u8);
6+
let _ = std::ptr::from_ref::<u32>(&2u32);
7+
let _ = std::ptr::from_ref::<f64>(&3.0f64);
8+
9+
let _ = std::ptr::from_ref(&4) as *const f32;
10+
let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;
11+
12+
let _ = std::ptr::from_ref(&mut 6u8);
13+
let _ = std::ptr::from_ref::<u32>(&mut 7u32);
14+
let _ = std::ptr::from_ref::<f64>(&mut 8.0f64);
15+
16+
let _ = std::ptr::from_ref(&mut 9) as *const f32;
17+
let _ = std::ptr::from_ref::<f32>(&mut 10.0f32) as *const u32;
18+
19+
let _ = std::ptr::from_mut(&mut 11u8);
20+
let _ = std::ptr::from_mut::<u32>(&mut 12u32);
21+
let _ = std::ptr::from_mut::<f64>(&mut 13.0f64);
22+
23+
let _ = std::ptr::from_mut(&mut 14) as *const f32;
24+
let _ = std::ptr::from_mut::<f32>(&mut 15.0f32) as *const u32;
25+
26+
let _ = std::ptr::from_ref(&1u8);
27+
let _ = std::ptr::from_ref::<u32>(&2u32);
28+
let _ = std::ptr::from_ref::<f64>(&3.0f64);
29+
30+
let _ = std::ptr::from_ref(&4) as *const f32;
31+
let _ = std::ptr::from_ref::<f32>(&5.0f32) as *const u32;
32+
33+
let val = 1;
34+
let _ = std::ptr::from_ref(&val);
35+
let _ = std::ptr::from_ref::<i32>(&val);
36+
37+
let _ = std::ptr::from_ref(&val) as *const f32;
38+
let _ = std::ptr::from_ref::<i32>(&val) as *const f64;
39+
40+
let mut val: u8 = 2;
41+
let _ = std::ptr::from_mut::<u8>(&mut val);
42+
let _ = std::ptr::from_mut(&mut val);
43+
44+
let _ = std::ptr::from_ref::<u8>(&mut val);
45+
let _ = std::ptr::from_ref(&mut val);
46+
47+
let _ = std::ptr::from_ref::<u8>(&mut val) as *const f64;
48+
let _: *const Option<u8> = std::ptr::from_ref(&mut val) as *const _;
49+
50+
let _ = std::ptr::from_ref::<[usize; 7]>(&std::array::from_fn(|i| i * i));
51+
let _ = std::ptr::from_ref::<[usize; 8]>(&mut std::array::from_fn(|i| i * i));
52+
let _ = std::ptr::from_mut::<[usize; 9]>(&mut std::array::from_fn(|i| i * i));
53+
}
54+
55+
#[clippy::msrv = "1.75"]
56+
fn _msrv_1_75() {
57+
let val = &42_i32;
58+
let mut_val = &mut 42_i32;
59+
60+
// `std::ptr::from_{ref, mut}` was stabilized in 1.76. Do not lint this
61+
let _ = val as *const i32;
62+
let _ = mut_val as *mut i32;
63+
}
64+
65+
#[clippy::msrv = "1.76"]
66+
fn _msrv_1_76() {
67+
let val = &42_i32;
68+
let mut_val = &mut 42_i32;
69+
70+
let _ = std::ptr::from_ref::<i32>(val);
71+
let _ = std::ptr::from_mut::<i32>(mut_val);
72+
}
73+
74+
fn foo(val: &[u8]) {
75+
let _ = std::ptr::from_ref(val);
76+
let _ = std::ptr::from_ref::<[u8]>(val);
77+
}
78+
79+
fn bar(val: &mut str) {
80+
let _ = std::ptr::from_mut(val);
81+
let _ = std::ptr::from_mut::<str>(val);
82+
}
83+
84+
struct X<'a>(&'a i32);
85+
86+
impl<'a> X<'a> {
87+
fn foo(&self) -> *const i64 {
88+
std::ptr::from_ref(self.0) as *const _
89+
}
90+
91+
fn bar(&mut self) -> *const i64 {
92+
std::ptr::from_ref(self.0) as *const _
93+
}
94+
}
95+
96+
struct Y<'a>(&'a mut i32);
97+
98+
impl<'a> Y<'a> {
99+
fn foo(&self) -> *const i64 {
100+
std::ptr::from_ref(self.0) as *const _
101+
}
102+
103+
fn bar(&mut self) -> *const i64 {
104+
std::ptr::from_ref(self.0) as *const _
105+
}
106+
107+
fn baz(&mut self) -> *const i64 {
108+
std::ptr::from_mut(self.0) as *mut _
109+
}
110+
}

0 commit comments

Comments
 (0)