Skip to content

Commit 21216e3

Browse files
authored
Rewrite bit mask lints (#15587)
The helper functions/types could be pulled into `clippy_utils`. I'm going to go through and sort that crate out in a separate PR first rather than add to it now. changelog: [`ineffective_bit_masks`]: Lint xor expressions
2 parents 304793d + 708a38c commit 21216e3

8 files changed

Lines changed: 1617 additions & 381 deletions

File tree

clippy_lints/src/operators/bit_mask.rs

Lines changed: 243 additions & 144 deletions
Large diffs are not rendered by default.

clippy_utils/src/consts.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
979979
}
980980
}
981981

982+
#[expect(clippy::too_many_lines)]
982983
fn binop(&self, op: BinOpKind, left: &Expr<'_>, right: &Expr<'_>) -> Option<Constant> {
983984
let l = self.expr(left)?;
984985
let r = self.expr(right);
@@ -1027,15 +1028,20 @@ impl<'tcx> ConstEvalCtxt<'tcx> {
10271028
},
10281029
ty::Uint(ity) => {
10291030
let bits = ity.bits();
1031+
let mask = !0u128 >> (128 - bits);
10301032

10311033
match op {
10321034
BinOpKind::Add => l.checked_add(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
10331035
BinOpKind::Sub => l.checked_sub(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
10341036
BinOpKind::Mul => l.checked_mul(r).and_then(|n| ity.ensure_fits(n)).map(Constant::Int),
10351037
BinOpKind::Div => l.checked_div(r).map(Constant::Int),
10361038
BinOpKind::Rem => l.checked_rem(r).map(Constant::Int),
1037-
BinOpKind::Shr if r < bits => l.checked_shr(r.try_into().ok()?).map(Constant::Int),
1038-
BinOpKind::Shl if r < bits => l.checked_shl(r.try_into().ok()?).map(Constant::Int),
1039+
BinOpKind::Shr if r < bits => {
1040+
l.checked_shr(r.try_into().ok()?).map(|x| Constant::Int(x & mask))
1041+
},
1042+
BinOpKind::Shl if r < bits => {
1043+
l.checked_shl(r.try_into().ok()?).map(|x| Constant::Int(x & mask))
1044+
},
10391045
BinOpKind::BitXor => Some(Constant::Int(l ^ r)),
10401046
BinOpKind::BitOr => Some(Constant::Int(l | r)),
10411047
BinOpKind::BitAnd => Some(Constant::Int(l & r)),

tests/ui/bad_bit_masks.rs

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
//@aux-build:proc_macros.rs
2+
3+
#![warn(clippy::bad_bit_mask)]
4+
#![expect(clippy::erasing_op, clippy::identity_op)]
5+
6+
use core::hint::black_box;
7+
use core::ops::BitAnd;
8+
use proc_macros::{external, with_span};
9+
10+
fn main() {
11+
let x = black_box(5u32);
12+
13+
let _ = x & 0b0000 == 0b0000; //~ bad_bit_mask
14+
let _ = x & 0b0000 == 0b0001; //~ bad_bit_mask
15+
let _ = x & 0b0001 == 0b0000;
16+
let _ = x & 0b0001 == 0b0001;
17+
let _ = x & 0b0010 == 0b0001; //~ bad_bit_mask
18+
let _ = x & 0b0001 == 0b0010; //~ bad_bit_mask
19+
let _ = x & 0b0011 == 0b0001;
20+
let _ = x & 0b0011 == 0b0010;
21+
let _ = x & 0b0011 == 0b0011;
22+
let _ = x & 0b0011 == 0b0100; //~ bad_bit_mask
23+
let _ = x & 0b0100 == 0b0100;
24+
let _ = x & 0b0110 == 0b0111; //~ bad_bit_mask
25+
let _ = x & 0b0011 == 0b0101; //~ bad_bit_mask
26+
let _ = x & 0b1111 == 0b1110;
27+
let _ = x & 0b1111 == 0b1010;
28+
29+
let _ = x | 0b0000 == 0b0000;
30+
let _ = x | 0b0000 == 0b0001;
31+
let _ = x | 0b0001 == 0b0000; //~ bad_bit_mask
32+
let _ = x | 0b0001 == 0b0001;
33+
let _ = x | 0b0010 == 0b0001; //~ bad_bit_mask
34+
let _ = x | 0b0001 == 0b0010; //~ bad_bit_mask
35+
let _ = x | 0b0011 == 0b0001; //~ bad_bit_mask
36+
let _ = x | 0b0011 == 0b0010; //~ bad_bit_mask
37+
let _ = x | 0b0011 == 0b0011;
38+
let _ = x | 0b0011 == 0b0100; //~ bad_bit_mask
39+
let _ = x | 0b0100 == 0b0100;
40+
let _ = x | 0b0110 == 0b0111;
41+
let _ = x | 0b0011 == 0b0101; //~ bad_bit_mask
42+
let _ = x | 0b1111 == 0b1110; //~ bad_bit_mask
43+
let _ = x | 0b1111 == 0b1010; //~ bad_bit_mask
44+
45+
let _ = x & 0b0000 != 0b0000; //~ bad_bit_mask
46+
let _ = x & 0b0000 != 0b0001; //~ bad_bit_mask
47+
let _ = x & 0b0001 != 0b0000;
48+
let _ = x & 0b0001 != 0b0001;
49+
let _ = x & 0b0010 != 0b0001; //~ bad_bit_mask
50+
let _ = x & 0b0001 != 0b0010; //~ bad_bit_mask
51+
let _ = x & 0b0011 != 0b0001;
52+
let _ = x & 0b0011 != 0b0010;
53+
let _ = x & 0b0011 != 0b0011;
54+
let _ = x & 0b0011 != 0b0100; //~ bad_bit_mask
55+
let _ = x & 0b0100 != 0b0100;
56+
let _ = x & 0b0110 != 0b0111; //~ bad_bit_mask
57+
let _ = x & 0b0011 != 0b0101; //~ bad_bit_mask
58+
let _ = x & 0b1111 != 0b1110;
59+
let _ = x & 0b1111 != 0b1010;
60+
61+
let _ = x | 0b0000 != 0b0000;
62+
let _ = x | 0b0000 != 0b0001;
63+
let _ = x | 0b0001 != 0b0000; //~ bad_bit_mask
64+
let _ = x | 0b0001 != 0b0001;
65+
let _ = x | 0b0010 != 0b0001; //~ bad_bit_mask
66+
let _ = x | 0b0001 != 0b0010; //~ bad_bit_mask
67+
let _ = x | 0b0011 != 0b0001; //~ bad_bit_mask
68+
let _ = x | 0b0011 != 0b0010; //~ bad_bit_mask
69+
let _ = x | 0b0011 != 0b0011;
70+
let _ = x | 0b0011 != 0b0100; //~ bad_bit_mask
71+
let _ = x | 0b0100 != 0b0100;
72+
let _ = x | 0b0110 != 0b0111;
73+
let _ = x | 0b0011 != 0b0101; //~ bad_bit_mask
74+
let _ = x | 0b1111 != 0b1110; //~ bad_bit_mask
75+
let _ = x | 0b1111 != 0b1010; //~ bad_bit_mask
76+
77+
let _ = 0b0010 & x == 0b0001; //~ bad_bit_mask
78+
let _ = 0b0001 == x & 0b0010; //~ bad_bit_mask
79+
let _ = 0b0001 == 0b0010 & x; //~ bad_bit_mask
80+
81+
let _ = x & (0b0100 | 0b0010) == (0b0111 ^ 0b1000); //~ bad_bit_mask
82+
83+
external! {
84+
let x = black_box(5u32);
85+
let _ = x & 0b0010 == 0b0001;
86+
}
87+
with_span! {
88+
sp
89+
let x = black_box(5u32);
90+
let _ = x & 0b0010 == 0b0001;
91+
}
92+
93+
{
94+
const C: i32 = 0b0011;
95+
96+
let x = black_box(5i32);
97+
let _ = x & C == 0b0011;
98+
let _ = x & C == 0b0100; //~ bad_bit_mask
99+
let _ = x & 0b0001 == C; //~ bad_bit_mask
100+
}
101+
102+
{
103+
// Bits shifted out.
104+
let _ = black_box(1u8) & 0xf0 == 0x11 << 4;
105+
let _ = black_box(1i8) & 0x70 == 0x11 << 4;
106+
let _ = black_box(1u16) & 0xf000 == 0x11 << 12;
107+
let _ = black_box(1i16) & 0x7000 == 0x11 << 12;
108+
}
109+
110+
{
111+
struct S(u32);
112+
impl BitAnd<u32> for S {
113+
type Output = Self;
114+
fn bitand(self, _: u32) -> Self {
115+
self
116+
}
117+
}
118+
impl PartialEq<u32> for S {
119+
fn eq(&self, _: &u32) -> bool {
120+
true
121+
}
122+
}
123+
let _ = black_box(S(0)) & 0x1 != 0;
124+
}
125+
}

0 commit comments

Comments
 (0)