Skip to content

Commit 947516f

Browse files
committed
Auto merge of #6130 - Ambroisie:lint-ptr-eq, r=Manishearth
New lint: Recommend using `ptr::eq` when possible This is based almost entirely on the code available in the previous PR #4596. I merely updated the code to make it compile. Fixes #3661. - [ ] I'm not sure about the lint name, but it was the one used in the original PR. - [X] Added passing UI tests (including committed `.stderr` file) - [X] `cargo test` passes locally - [X] Executed `cargo dev update_lints` - [X] Added lint documentation - [X] Run `cargo dev fmt` --- changelog: none
2 parents fcf22d9 + 6edde81 commit 947516f

File tree

7 files changed

+201
-0
lines changed

7 files changed

+201
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -1892,6 +1892,7 @@ Released 2018-09-13
18921892
[`print_with_newline`]: https://rust-lang.github.io/rust-clippy/master/index.html#print_with_newline
18931893
[`println_empty_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#println_empty_string
18941894
[`ptr_arg`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_arg
1895+
[`ptr_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_eq
18951896
[`ptr_offset_with_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#ptr_offset_with_cast
18961897
[`pub_enum_variant_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#pub_enum_variant_names
18971898
[`question_mark`]: https://rust-lang.github.io/rust-clippy/master/index.html#question_mark

clippy_lints/src/lib.rs

+5
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ mod path_buf_push_overwrite;
281281
mod pattern_type_mismatch;
282282
mod precedence;
283283
mod ptr;
284+
mod ptr_eq;
284285
mod ptr_offset_with_cast;
285286
mod question_mark;
286287
mod ranges;
@@ -778,6 +779,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
778779
&ptr::CMP_NULL,
779780
&ptr::MUT_FROM_REF,
780781
&ptr::PTR_ARG,
782+
&ptr_eq::PTR_EQ,
781783
&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST,
782784
&question_mark::QUESTION_MARK,
783785
&ranges::RANGE_MINUS_ONE,
@@ -916,6 +918,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
916918
let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold;
917919
store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold));
918920
store.register_late_pass(|| box ptr::Ptr);
921+
store.register_late_pass(|| box ptr_eq::PtrEq);
919922
store.register_late_pass(|| box needless_bool::NeedlessBool);
920923
store.register_late_pass(|| box needless_bool::BoolComparison);
921924
store.register_late_pass(|| box approx_const::ApproxConstant);
@@ -1457,6 +1460,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
14571460
LintId::of(&ptr::CMP_NULL),
14581461
LintId::of(&ptr::MUT_FROM_REF),
14591462
LintId::of(&ptr::PTR_ARG),
1463+
LintId::of(&ptr_eq::PTR_EQ),
14601464
LintId::of(&ptr_offset_with_cast::PTR_OFFSET_WITH_CAST),
14611465
LintId::of(&question_mark::QUESTION_MARK),
14621466
LintId::of(&ranges::RANGE_ZIP_WITH_LEN),
@@ -1611,6 +1615,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16111615
LintId::of(&panic_unimplemented::PANIC_PARAMS),
16121616
LintId::of(&ptr::CMP_NULL),
16131617
LintId::of(&ptr::PTR_ARG),
1618+
LintId::of(&ptr_eq::PTR_EQ),
16141619
LintId::of(&question_mark::QUESTION_MARK),
16151620
LintId::of(&redundant_field_names::REDUNDANT_FIELD_NAMES),
16161621
LintId::of(&redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),

clippy_lints/src/ptr_eq.rs

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
use crate::utils;
2+
use if_chain::if_chain;
3+
use rustc_errors::Applicability;
4+
use rustc_hir::{BinOpKind, Expr, ExprKind};
5+
use rustc_lint::{LateContext, LateLintPass};
6+
use rustc_session::{declare_lint_pass, declare_tool_lint};
7+
8+
declare_clippy_lint! {
9+
/// **What it does:** Use `std::ptr::eq` when applicable
10+
///
11+
/// **Why is this bad?** `ptr::eq` can be used to compare `&T` references
12+
/// (which coerce to `*const T` implicitly) by their address rather than
13+
/// comparing the values they point to.
14+
///
15+
/// **Known problems:** None.
16+
///
17+
/// **Example:**
18+
///
19+
/// ```rust
20+
/// let a = &[1, 2, 3];
21+
/// let b = &[1, 2, 3];
22+
///
23+
/// assert!(a as *const _ as usize == b as *const _ as usize);
24+
/// ```
25+
/// Use instead:
26+
/// ```rust
27+
/// let a = &[1, 2, 3];
28+
/// let b = &[1, 2, 3];
29+
///
30+
/// assert!(std::ptr::eq(a, b));
31+
/// ```
32+
pub PTR_EQ,
33+
style,
34+
"use `std::ptr::eq` when comparing raw pointers"
35+
}
36+
37+
declare_lint_pass!(PtrEq => [PTR_EQ]);
38+
39+
static LINT_MSG: &str = "use `std::ptr::eq` when comparing raw pointers";
40+
41+
impl LateLintPass<'_> for PtrEq {
42+
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
43+
if utils::in_macro(expr.span) {
44+
return;
45+
}
46+
47+
if let ExprKind::Binary(ref op, ref left, ref right) = expr.kind {
48+
if BinOpKind::Eq == op.node {
49+
let (left, right) = match (expr_as_cast_to_usize(cx, left), expr_as_cast_to_usize(cx, right)) {
50+
(Some(lhs), Some(rhs)) => (lhs, rhs),
51+
_ => (&**left, &**right),
52+
};
53+
54+
if_chain! {
55+
if let Some(left_var) = expr_as_cast_to_raw_pointer(cx, left);
56+
if let Some(right_var) = expr_as_cast_to_raw_pointer(cx, right);
57+
if let Some(left_snip) = utils::snippet_opt(cx, left_var.span);
58+
if let Some(right_snip) = utils::snippet_opt(cx, right_var.span);
59+
then {
60+
utils::span_lint_and_sugg(
61+
cx,
62+
PTR_EQ,
63+
expr.span,
64+
LINT_MSG,
65+
"try",
66+
format!("std::ptr::eq({}, {})", left_snip, right_snip),
67+
Applicability::MachineApplicable,
68+
);
69+
}
70+
}
71+
}
72+
}
73+
}
74+
}
75+
76+
// If the given expression is a cast to an usize, return the lhs of the cast
77+
// E.g., `foo as *const _ as usize` returns `foo as *const _`.
78+
fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
79+
if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize {
80+
if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
81+
return Some(expr);
82+
}
83+
}
84+
None
85+
}
86+
87+
// If the given expression is a cast to a `*const` pointer, return the lhs of the cast
88+
// E.g., `foo as *const _` returns `foo`.
89+
fn expr_as_cast_to_raw_pointer<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
90+
if cx.typeck_results().expr_ty(cast_expr).is_unsafe_ptr() {
91+
if let ExprKind::Cast(ref expr, _) = cast_expr.kind {
92+
return Some(expr);
93+
}
94+
}
95+
None
96+
}

src/lintlist/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,13 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
18441844
deprecation: None,
18451845
module: "ptr",
18461846
},
1847+
Lint {
1848+
name: "ptr_eq",
1849+
group: "style",
1850+
desc: "use `std::ptr::eq` when comparing raw pointers",
1851+
deprecation: None,
1852+
module: "ptr_eq",
1853+
},
18471854
Lint {
18481855
name: "ptr_offset_with_cast",
18491856
group: "complexity",

tests/ui/ptr_eq.fixed

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// run-rustfix
2+
#![warn(clippy::ptr_eq)]
3+
4+
macro_rules! mac {
5+
($a:expr, $b:expr) => {
6+
$a as *const _ as usize == $b as *const _ as usize
7+
};
8+
}
9+
10+
macro_rules! another_mac {
11+
($a:expr, $b:expr) => {
12+
$a as *const _ == $b as *const _
13+
};
14+
}
15+
16+
fn main() {
17+
let a = &[1, 2, 3];
18+
let b = &[1, 2, 3];
19+
20+
let _ = std::ptr::eq(a, b);
21+
let _ = std::ptr::eq(a, b);
22+
let _ = a.as_ptr() == b as *const _;
23+
let _ = a.as_ptr() == b.as_ptr();
24+
25+
// Do not lint
26+
27+
let _ = mac!(a, b);
28+
let _ = another_mac!(a, b);
29+
30+
let a = &mut [1, 2, 3];
31+
let b = &mut [1, 2, 3];
32+
33+
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
34+
let _ = a.as_mut_ptr() == b.as_mut_ptr();
35+
36+
let _ = a == b;
37+
let _ = core::ptr::eq(a, b);
38+
}

tests/ui/ptr_eq.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// run-rustfix
2+
#![warn(clippy::ptr_eq)]
3+
4+
macro_rules! mac {
5+
($a:expr, $b:expr) => {
6+
$a as *const _ as usize == $b as *const _ as usize
7+
};
8+
}
9+
10+
macro_rules! another_mac {
11+
($a:expr, $b:expr) => {
12+
$a as *const _ == $b as *const _
13+
};
14+
}
15+
16+
fn main() {
17+
let a = &[1, 2, 3];
18+
let b = &[1, 2, 3];
19+
20+
let _ = a as *const _ as usize == b as *const _ as usize;
21+
let _ = a as *const _ == b as *const _;
22+
let _ = a.as_ptr() == b as *const _;
23+
let _ = a.as_ptr() == b.as_ptr();
24+
25+
// Do not lint
26+
27+
let _ = mac!(a, b);
28+
let _ = another_mac!(a, b);
29+
30+
let a = &mut [1, 2, 3];
31+
let b = &mut [1, 2, 3];
32+
33+
let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
34+
let _ = a.as_mut_ptr() == b.as_mut_ptr();
35+
36+
let _ = a == b;
37+
let _ = core::ptr::eq(a, b);
38+
}

tests/ui/ptr_eq.stderr

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
error: use `std::ptr::eq` when comparing raw pointers
2+
--> $DIR/ptr_eq.rs:20:13
3+
|
4+
LL | let _ = a as *const _ as usize == b as *const _ as usize;
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
6+
|
7+
= note: `-D clippy::ptr-eq` implied by `-D warnings`
8+
9+
error: use `std::ptr::eq` when comparing raw pointers
10+
--> $DIR/ptr_eq.rs:21:13
11+
|
12+
LL | let _ = a as *const _ == b as *const _;
13+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
14+
15+
error: aborting due to 2 previous errors
16+

0 commit comments

Comments
 (0)