Skip to content

Commit 033da3c

Browse files
committed
add new lint as_underscore_ptr to check for as *{const,mut} _
1 parent 58fb801 commit 033da3c

38 files changed

+262
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4392,6 +4392,7 @@ Released 2018-09-13
43924392
[`as_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_conversions
43934393
[`as_ptr_cast_mut`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_ptr_cast_mut
43944394
[`as_underscore`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore
4395+
[`as_underscore_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#as_underscore_ptr
43954396
[`assertions_on_constants`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_constants
43964397
[`assertions_on_result_states`]: https://rust-lang.github.io/rust-clippy/master/index.html#assertions_on_result_states
43974398
[`assign_op_pattern`]: https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use clippy_utils::diagnostics::span_lint_and_then;
2+
use rustc_errors::Applicability;
3+
use rustc_hir::{Expr, MutTy, Ty, TyKind};
4+
use rustc_lint::LateContext;
5+
use rustc_middle::ty;
6+
7+
use super::AS_UNDERSCORE_PTR;
8+
9+
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, mut ty: &Ty<'_>) {
10+
if let TyKind::Ptr(MutTy { mutbl, .. }) = ty.kind {
11+
// get this before stripping the pointers, so the suggestion suggests replacing the whole type
12+
let ty_span = ty.span;
13+
14+
// strip all pointers from the type
15+
while let TyKind::Ptr(MutTy { ty: new_ty, .. }) = ty.kind {
16+
ty = new_ty;
17+
}
18+
19+
if matches!(ty.kind, TyKind::Infer) {
20+
let mutbl_str = match mutbl {
21+
rustc_ast::Mutability::Not => "const",
22+
rustc_ast::Mutability::Mut => "mut",
23+
};
24+
span_lint_and_then(
25+
cx,
26+
AS_UNDERSCORE_PTR,
27+
expr.span,
28+
format!("using `as *{mutbl_str} _` conversion").as_str(),
29+
|diag| {
30+
let ty_resolved = cx.typeck_results().expr_ty(expr);
31+
if let ty::Error(_) = ty_resolved.kind() {
32+
diag.help("consider giving the type explicitly");
33+
} else {
34+
diag.span_suggestion(
35+
ty_span,
36+
"consider giving the type explicitly",
37+
ty_resolved,
38+
Applicability::MachineApplicable,
39+
);
40+
}
41+
},
42+
);
43+
}
44+
} else {
45+
// not a pointer
46+
}
47+
}

clippy_lints/src/casts/mod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
mod as_ptr_cast_mut;
22
mod as_underscore;
3+
mod as_underscore_ptr;
34
mod borrow_as_ptr;
45
mod cast_abs_to_unsigned;
56
mod cast_enum_constructor;
@@ -555,6 +556,47 @@ declare_clippy_lint! {
555556
"detects `as _` conversion"
556557
}
557558

559+
declare_clippy_lint! {
560+
/// ### What it does
561+
/// Checks for the usage of `as *const _` or `as *mut _` where the pointed to type is inferred.
562+
///
563+
/// ### Why is this bad?
564+
/// When converting to a pointer, it can be dangerous to not specify the type. Type inference can
565+
/// be affected by many things, types may not always be obvious, and when working with pointers, while
566+
/// the pointed to type doesn't technically matter until an access, you should always know what types
567+
/// you intend to work with. When using multiple chained `as` casts, it can be especially dangerous,
568+
/// because `*const T as *const U` **always compiles** (for Sized types T and U).
569+
///
570+
/// ### Example
571+
/// ```rust
572+
/// struct UwU;
573+
/// impl UwU {
574+
/// // intent: turn a `&UwU` into a `*const u8` that points to the same data
575+
/// fn as_ptr(&self) -> *const u8 {
576+
/// // ⚠️ `&self` is a `&&UwU`, so this turns a double pointer into a single pointer
577+
/// // ⚠️ This pointer is a dangling pointer to a local
578+
/// &self as *const _ as *const u8
579+
/// }
580+
/// }
581+
/// ```
582+
/// Use instead:
583+
/// ```rust
584+
/// struct UwU;
585+
/// impl UwU {
586+
/// // intent: turn a `&UwU` into a `*const u8` that points to the same data
587+
/// fn as_ptr(&self) -> *const u8 {
588+
/// // ⚠️ This pointer is still a dangling pointer to a local
589+
/// // ⚠️ But now the error is explicit in the type
590+
/// &self as *const &UwU as *const u8
591+
/// }
592+
/// }
593+
/// ```
594+
#[clippy::version = "1.70.0"]
595+
pub AS_UNDERSCORE_PTR,
596+
pedantic,
597+
"detects `as *{const,mut} _ conversions"
598+
}
599+
558600
declare_clippy_lint! {
559601
/// ### What it does
560602
/// Checks for the usage of `&expr as *const T` or
@@ -693,6 +735,7 @@ impl_lint_pass!(Casts => [
693735
CAST_ENUM_CONSTRUCTOR,
694736
CAST_ABS_TO_UNSIGNED,
695737
AS_UNDERSCORE,
738+
AS_UNDERSCORE_PTR,
696739
BORROW_AS_PTR,
697740
CAST_SLICE_FROM_RAW_PARTS,
698741
AS_PTR_CAST_MUT,
@@ -741,6 +784,7 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
741784
}
742785

743786
as_underscore::check(cx, expr, cast_to_hir);
787+
as_underscore_ptr::check(cx, expr, cast_to_hir);
744788

745789
if self.msrv.meets(msrvs::BORROW_AS_PTR) {
746790
borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);

clippy_lints/src/declared_lints.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
6969
crate::cargo::WILDCARD_DEPENDENCIES_INFO,
7070
crate::casts::AS_PTR_CAST_MUT_INFO,
7171
crate::casts::AS_UNDERSCORE_INFO,
72+
crate::casts::AS_UNDERSCORE_PTR_INFO,
7273
crate::casts::BORROW_AS_PTR_INFO,
7374
crate::casts::CAST_ABS_TO_UNSIGNED_INFO,
7475
crate::casts::CAST_ENUM_CONSTRUCTOR_INFO,

clippy_lints/src/only_used_in_recursion.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_hir::hir_id::HirIdMap;
88
use rustc_hir::{Body, Expr, ExprKind, HirId, ImplItem, ImplItemKind, Node, PatKind, TraitItem, TraitItemKind};
99
use rustc_lint::{LateContext, LateLintPass};
1010
use rustc_middle::ty::subst::{EarlyBinder, GenericArgKind, SubstsRef};
11-
use rustc_middle::ty::{self, ConstKind};
11+
use rustc_middle::ty::{self, ConstKind, List};
1212
use rustc_session::{declare_tool_lint, impl_lint_pass};
1313
use rustc_span::symbol::{kw, Ident};
1414
use rustc_span::Span;
@@ -249,7 +249,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
249249
{
250250
(
251251
trait_item_id,
252-
FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const _ as usize),
252+
FnKind::ImplTraitFn(cx.tcx.erase_regions(trait_ref.substs) as *const List<_> as usize),
253253
usize::from(sig.decl.implicit_self.has_implicit_self()),
254254
)
255255
} else {
@@ -390,6 +390,6 @@ fn has_matching_substs(kind: FnKind, substs: SubstsRef<'_>) -> bool {
390390
GenericArgKind::Const(c) => matches!(c.kind(), ConstKind::Param(c) if c.index as usize == idx),
391391
}),
392392
#[allow(trivial_casts)]
393-
FnKind::ImplTraitFn(expected_substs) => substs as *const _ as usize == expected_substs,
393+
FnKind::ImplTraitFn(expected_substs) => substs as *const List<_> as usize == expected_substs,
394394
}
395395
}

tests/ui/as_ptr_cast_mut.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ impl<T> Covariant<T> {
1919
fn main() {
2020
let mut string = String::new();
2121
let _ = string.as_ptr() as *mut u8;
22+
#[allow(clippy::as_underscore_ptr)] // trying to test inference with a different lint
2223
let _: *mut i8 = string.as_ptr() as *mut _;
2324
let _ = string.as_ptr() as *const i8;
2425
let _ = string.as_mut_ptr();
@@ -32,6 +33,7 @@ fn main() {
3233
let _ = wrap.as_ptr() as *mut u8;
3334

3435
let mut local = 4;
36+
#[allow(clippy::as_underscore_ptr)] // trying to test inference with a different lint
3537
let ref_with_write_perm = Covariant(std::ptr::addr_of_mut!(local) as *const _);
3638
let _ = ref_with_write_perm.as_ptr() as *mut u8;
3739
}

tests/ui/as_ptr_cast_mut.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | let _ = string.as_ptr() as *mut u8;
77
= note: `-D clippy::as-ptr-cast-mut` implied by `-D warnings`
88

99
error: casting the result of `as_ptr` to *mut i8
10-
--> $DIR/as_ptr_cast_mut.rs:22:22
10+
--> $DIR/as_ptr_cast_mut.rs:23:22
1111
|
1212
LL | let _: *mut i8 = string.as_ptr() as *mut _;
1313
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `string.as_mut_ptr()`

tests/ui/as_underscore.fixed

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@
44

55
fn foo(_n: usize) {}
66

7+
fn use_ptr(_: *const *const ()) {}
8+
79
fn main() {
810
let n: u16 = 256;
911
foo(n as usize);
1012

1113
let n = 0_u128;
1214
let _n: u8 = n as u8;
15+
16+
let x = 1 as *const ();
17+
use_ptr(x as *const _);
18+
let x2 = x as *const _;
19+
use_ptr(x2);
20+
21+
let _x3: *mut i32 = x as *mut _;
22+
23+
let _x4: *const () = x as *const ();
1324
}

tests/ui/as_underscore.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,21 @@
44

55
fn foo(_n: usize) {}
66

7+
fn use_ptr(_: *const *const ()) {}
8+
79
fn main() {
810
let n: u16 = 256;
911
foo(n as _);
1012

1113
let n = 0_u128;
1214
let _n: u8 = n as _;
15+
16+
let x = 1 as *const ();
17+
use_ptr(x as *const _);
18+
let x2 = x as *const _;
19+
use_ptr(x2);
20+
21+
let _x3: *mut i32 = x as *mut _;
22+
23+
let _x4: *const () = x as _;
1324
}

tests/ui/as_underscore.stderr

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: using `as _` conversion
2-
--> $DIR/as_underscore.rs:9:9
2+
--> $DIR/as_underscore.rs:11:9
33
|
44
LL | foo(n as _);
55
| ^^^^^-
@@ -9,12 +9,20 @@ LL | foo(n as _);
99
= note: `-D clippy::as-underscore` implied by `-D warnings`
1010

1111
error: using `as _` conversion
12-
--> $DIR/as_underscore.rs:12:18
12+
--> $DIR/as_underscore.rs:14:18
1313
|
1414
LL | let _n: u8 = n as _;
1515
| ^^^^^-
1616
| |
1717
| help: consider giving the type explicitly: `u8`
1818

19-
error: aborting due to 2 previous errors
19+
error: using `as _` conversion
20+
--> $DIR/as_underscore.rs:23:26
21+
|
22+
LL | let _x4: *const () = x as _;
23+
| ^^^^^-
24+
| |
25+
| help: consider giving the type explicitly: `*const ()`
26+
27+
error: aborting due to 3 previous errors
2028

tests/ui/as_underscore_ptr.fixed

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
#![deny(clippy::as_underscore_ptr)]
5+
6+
struct UwU;
7+
8+
impl UwU {
9+
fn as_ptr(&self) -> *const u8 {
10+
&self as *const &UwU as *const u8
11+
}
12+
}
13+
14+
fn use_ptr(_: *const ()) {}
15+
16+
fn main() {
17+
let _: *const u8 = 1 as *const u8;
18+
use_ptr(1 as *const ());
19+
}

tests/ui/as_underscore_ptr.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// run-rustfix
2+
3+
#![allow(unused)]
4+
#![deny(clippy::as_underscore_ptr)]
5+
6+
struct UwU;
7+
8+
impl UwU {
9+
fn as_ptr(&self) -> *const u8 {
10+
&self as *const _ as *const u8
11+
}
12+
}
13+
14+
fn use_ptr(_: *const ()) {}
15+
16+
fn main() {
17+
let _: *const u8 = 1 as *const _;
18+
use_ptr(1 as *const _);
19+
}

tests/ui/as_underscore_ptr.stderr

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
error: using `as *const _` conversion
2+
--> $DIR/as_underscore_ptr.rs:10:9
3+
|
4+
LL | &self as *const _ as *const u8
5+
| ^^^^^^^^^--------
6+
| |
7+
| help: consider giving the type explicitly: `*const &UwU`
8+
|
9+
note: the lint level is defined here
10+
--> $DIR/as_underscore_ptr.rs:4:9
11+
|
12+
LL | #![deny(clippy::as_underscore_ptr)]
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
14+
15+
error: using `as *const _` conversion
16+
--> $DIR/as_underscore_ptr.rs:17:24
17+
|
18+
LL | let _: *const u8 = 1 as *const _;
19+
| ^^^^^--------
20+
| |
21+
| help: consider giving the type explicitly: `*const u8`
22+
23+
error: using `as *const _` conversion
24+
--> $DIR/as_underscore_ptr.rs:18:13
25+
|
26+
LL | use_ptr(1 as *const _);
27+
| ^^^^^--------
28+
| |
29+
| help: consider giving the type explicitly: `*const ()`
30+
31+
error: aborting due to 3 previous errors
32+

tests/ui/author/issue_3849.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#![allow(clippy::transmute_ptr_to_ref)]
44
#![allow(clippy::transmuting_null)]
55

6-
pub const ZPTR: *const usize = 0 as *const _;
6+
pub const ZPTR: *const usize = 0 as *const usize;
77

88
fn main() {
99
unsafe {

tests/ui/borrow_deref_ref.fixed

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ mod should_not_lint2 {
5151
mod false_negative {
5252
fn foo() {
5353
let x = &12;
54-
let addr_x = &x as *const _ as usize;
55-
let addr_y = &x as *const _ as usize; // assert ok
54+
let addr_x = &x as *const &i32 as usize;
55+
let addr_y = &x as *const &i32 as usize; // assert ok
5656
// let addr_y = &x as *const _ as usize; // assert fail
5757
assert_ne!(addr_x, addr_y);
5858
}

tests/ui/borrow_deref_ref.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ mod should_not_lint2 {
5151
mod false_negative {
5252
fn foo() {
5353
let x = &12;
54-
let addr_x = &x as *const _ as usize;
55-
let addr_y = &&*x as *const _ as usize; // assert ok
54+
let addr_x = &x as *const &i32 as usize;
55+
let addr_y = &&*x as *const &i32 as usize; // assert ok
5656
// let addr_y = &x as *const _ as usize; // assert fail
5757
assert_ne!(addr_x, addr_y);
5858
}

tests/ui/borrow_deref_ref.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ LL | let b = &mut &*bar(&12);
1515
error: deref on an immutable reference
1616
--> $DIR/borrow_deref_ref.rs:55:23
1717
|
18-
LL | let addr_y = &&*x as *const _ as usize; // assert ok
18+
LL | let addr_y = &&*x as *const &i32 as usize; // assert ok
1919
| ^^^ help: if you would like to reborrow, try removing `&*`: `x`
2020

2121
error: aborting due to 3 previous errors

tests/ui/cast_ref_to_mut.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![warn(clippy::cast_ref_to_mut)]
22
#![allow(clippy::no_effect, clippy::borrow_as_ptr)]
3+
#![allow(clippy::as_underscore_ptr)] // trying to test inference with a different lint
34

45
extern "C" {
56
// N.B., mutability can be easily incorrect in FFI calls -- as

0 commit comments

Comments
 (0)