Skip to content

Commit 69f554d

Browse files
committed
integer_arithmetic: check all/only overflowing ops
Make the `integer_arithmetic` lint detect all the operations that are defined as being capable of overflow in the Rust Reference. Changes: * Disallow bit shifting (`<<`, `>>`). They overflow if the RHS exceeds the bit width. * Allow unsigned division and remainder (they cannot overflow).
1 parent 7907abe commit 69f554d

File tree

4 files changed

+148
-20
lines changed

4 files changed

+148
-20
lines changed

clippy_lints/src/arithmetic.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,20 @@ use crate::consts::constant_simple;
22
use crate::utils::span_lint;
33
use rustc_hir as hir;
44
use rustc_lint::{LateContext, LateLintPass};
5+
use rustc_middle::ty;
56
use rustc_session::{declare_tool_lint, impl_lint_pass};
67
use rustc_span::source_map::Span;
78

89
declare_clippy_lint! {
9-
/// **What it does:** Checks for plain integer arithmetic.
10+
/// **What it does:** Checks for integer arithmetic operations that could overflow.
1011
///
11-
/// **Why is this bad?** This is only checked against overflow in debug builds.
12-
/// In some applications one wants explicitly checked, wrapping or saturating
12+
/// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable
13+
/// of overflowing according to the [Rust
14+
/// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow).
15+
/// No bounds analysis or sophisticated reasoning is attempted.
16+
///
17+
/// **Why is this bad?** Integer overflow will trigger a panic in debug builds or will wrap in
18+
/// release mode. In some applications one wants explicitly checked, wrapping or saturating
1319
/// arithmetic.
1420
///
1521
/// **Known problems:** None.
@@ -21,7 +27,7 @@ declare_clippy_lint! {
2127
/// ```
2228
pub INTEGER_ARITHMETIC,
2329
restriction,
24-
"any integer arithmetic statement"
30+
"any integer arithmetic expression which could overflow"
2531
}
2632

2733
declare_clippy_lint! {
@@ -71,8 +77,6 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
7177
| hir::BinOpKind::BitAnd
7278
| hir::BinOpKind::BitOr
7379
| hir::BinOpKind::BitXor
74-
| hir::BinOpKind::Shl
75-
| hir::BinOpKind::Shr
7680
| hir::BinOpKind::Eq
7781
| hir::BinOpKind::Lt
7882
| hir::BinOpKind::Le
@@ -84,6 +88,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Arithmetic {
8488

8589
let (l_ty, r_ty) = (cx.tables.expr_ty(l), cx.tables.expr_ty(r));
8690
if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() {
91+
// Allow unsigned integer division and modulo (it can't overflow)
92+
if let ty::Uint(_) = l_ty.kind {
93+
if op.node == hir::BinOpKind::Div || op.node == hir::BinOpKind::Rem {
94+
return;
95+
}
96+
}
8797
span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected");
8898
self.expr_span = Some(expr.span);
8999
} else if l_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() {

src/lintlist/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ pub static ref ALL_LINTS: Vec<Lint> = vec![
846846
Lint {
847847
name: "integer_arithmetic",
848848
group: "restriction",
849-
desc: "any integer arithmetic statement",
849+
desc: "any integer arithmetic expression which could overflow",
850850
deprecation: None,
851851
module: "arithmetic",
852852
},

tests/ui/integer_arithmetic.rs

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ fn main() {
1818
i / 2; // no error, this is part of the expression in the preceding line
1919
i - 2 + 2 - i;
2020
-i;
21+
i >> 1;
22+
i << 1;
2123

2224
// no error, overflows are checked by `overflowing_literals`
2325
-1;
@@ -26,18 +28,16 @@ fn main() {
2628
i & 1; // no wrapping
2729
i | 1;
2830
i ^ 1;
29-
i >> 1;
30-
i << 1;
3131

3232
i += 1;
3333
i -= 1;
3434
i *= 2;
3535
i /= 2;
3636
i %= 2;
37-
38-
// no errors
3937
i <<= 3;
4038
i >>= 2;
39+
40+
// no errors
4141
i |= 1;
4242
i &= 1;
4343
i ^= i;
@@ -73,8 +73,6 @@ fn main() {
7373
1 + 1
7474
};
7575
}
76-
77-
7876
}
7977

8078
// warn on references as well! (#5328)
@@ -84,6 +82,42 @@ pub fn int_arith_ref() {
8482
&3 + &1;
8583
}
8684

85+
pub fn unsigned() {
86+
let mut i = 1000u64;
87+
88+
// should error
89+
i + 2;
90+
i - 2;
91+
i * 2;
92+
i << 2;
93+
i >> i;
94+
95+
// should error
96+
i += 2;
97+
i -= 2;
98+
i *= i;
99+
i <<= 2;
100+
i >>= 2;
101+
102+
// should not error
103+
i | 3;
104+
i & 2;
105+
i ^ 4;
106+
i / 2;
107+
i % 5;
108+
109+
// should not error
110+
i |= 1;
111+
i &= 1;
112+
i ^= i;
113+
i /= i;
114+
i %= 6;
115+
116+
// should not error
117+
!i;
118+
!(!i);
119+
}
120+
87121
pub fn foo(x: &i32) -> i32 {
88122
let a = 5;
89123
a + x

tests/ui/integer_arithmetic.stderr

Lines changed: 91 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ error: integer arithmetic detected
3131
LL | -i;
3232
| ^^
3333

34+
error: integer arithmetic detected
35+
--> $DIR/integer_arithmetic.rs:21:5
36+
|
37+
LL | i >> 1;
38+
| ^^^^^^
39+
40+
error: integer arithmetic detected
41+
--> $DIR/integer_arithmetic.rs:22:5
42+
|
43+
LL | i << 1;
44+
| ^^^^^^
45+
3446
error: integer arithmetic detected
3547
--> $DIR/integer_arithmetic.rs:32:5
3648
|
@@ -62,46 +74,118 @@ LL | i %= 2;
6274
| ^^^^^^
6375

6476
error: integer arithmetic detected
65-
--> $DIR/integer_arithmetic.rs:82:5
77+
--> $DIR/integer_arithmetic.rs:37:5
78+
|
79+
LL | i <<= 3;
80+
| ^^^^^^^
81+
82+
error: integer arithmetic detected
83+
--> $DIR/integer_arithmetic.rs:38:5
84+
|
85+
LL | i >>= 2;
86+
| ^^^^^^^
87+
88+
error: integer arithmetic detected
89+
--> $DIR/integer_arithmetic.rs:80:5
6690
|
6791
LL | 3 + &1;
6892
| ^^^^^^
6993

7094
error: integer arithmetic detected
71-
--> $DIR/integer_arithmetic.rs:83:5
95+
--> $DIR/integer_arithmetic.rs:81:5
7296
|
7397
LL | &3 + 1;
7498
| ^^^^^^
7599

76100
error: integer arithmetic detected
77-
--> $DIR/integer_arithmetic.rs:84:5
101+
--> $DIR/integer_arithmetic.rs:82:5
78102
|
79103
LL | &3 + &1;
80104
| ^^^^^^^
81105

82106
error: integer arithmetic detected
83107
--> $DIR/integer_arithmetic.rs:89:5
84108
|
85-
LL | a + x
109+
LL | i + 2;
110+
| ^^^^^
111+
112+
error: integer arithmetic detected
113+
--> $DIR/integer_arithmetic.rs:90:5
114+
|
115+
LL | i - 2;
116+
| ^^^^^
117+
118+
error: integer arithmetic detected
119+
--> $DIR/integer_arithmetic.rs:91:5
120+
|
121+
LL | i * 2;
86122
| ^^^^^
87123

124+
error: integer arithmetic detected
125+
--> $DIR/integer_arithmetic.rs:92:5
126+
|
127+
LL | i << 2;
128+
| ^^^^^^
129+
88130
error: integer arithmetic detected
89131
--> $DIR/integer_arithmetic.rs:93:5
90132
|
133+
LL | i >> i;
134+
| ^^^^^^
135+
136+
error: integer arithmetic detected
137+
--> $DIR/integer_arithmetic.rs:96:5
138+
|
139+
LL | i += 2;
140+
| ^^^^^^
141+
142+
error: integer arithmetic detected
143+
--> $DIR/integer_arithmetic.rs:97:5
144+
|
145+
LL | i -= 2;
146+
| ^^^^^^
147+
148+
error: integer arithmetic detected
149+
--> $DIR/integer_arithmetic.rs:98:5
150+
|
151+
LL | i *= i;
152+
| ^^^^^^
153+
154+
error: integer arithmetic detected
155+
--> $DIR/integer_arithmetic.rs:99:5
156+
|
157+
LL | i <<= 2;
158+
| ^^^^^^^
159+
160+
error: integer arithmetic detected
161+
--> $DIR/integer_arithmetic.rs:100:5
162+
|
163+
LL | i >>= 2;
164+
| ^^^^^^^
165+
166+
error: integer arithmetic detected
167+
--> $DIR/integer_arithmetic.rs:123:5
168+
|
169+
LL | a + x
170+
| ^^^^^
171+
172+
error: integer arithmetic detected
173+
--> $DIR/integer_arithmetic.rs:127:5
174+
|
91175
LL | x + y
92176
| ^^^^^
93177

94178
error: integer arithmetic detected
95-
--> $DIR/integer_arithmetic.rs:97:5
179+
--> $DIR/integer_arithmetic.rs:131:5
96180
|
97181
LL | x + y
98182
| ^^^^^
99183

100184
error: integer arithmetic detected
101-
--> $DIR/integer_arithmetic.rs:101:5
185+
--> $DIR/integer_arithmetic.rs:135:5
102186
|
103187
LL | (&x + &y)
104188
| ^^^^^^^^^
105189

106-
error: aborting due to 17 previous errors
190+
error: aborting due to 31 previous errors
107191

0 commit comments

Comments
 (0)