@@ -66,8 +66,7 @@ fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx
66
66
// a % b => [a]
67
67
let exprs = exprs_with_selected_binop_peeled ( cast_op) ;
68
68
for expr in exprs {
69
- let ty = cx. typeck_results ( ) . expr_ty ( expr) ;
70
- match expr_sign ( cx, expr, ty) {
69
+ match expr_sign ( cx, expr, None ) {
71
70
Sign :: Negative => negative_count += 1 ,
72
71
Sign :: Uncertain => uncertain_count += 1 ,
73
72
Sign :: ZeroOrPositive => ( ) ,
@@ -85,7 +84,11 @@ fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx
85
84
}
86
85
}
87
86
88
- fn get_const_int_eval < ' cx > ( cx : & LateContext < ' cx > , expr : & Expr < ' _ > , ty : impl Into < Option < Ty < ' cx > > > ) -> Option < i128 > {
87
+ fn get_const_signed_int_eval < ' cx > (
88
+ cx : & LateContext < ' cx > ,
89
+ expr : & Expr < ' _ > ,
90
+ ty : impl Into < Option < Ty < ' cx > > > ,
91
+ ) -> Option < i128 > {
89
92
let ty = ty. into ( ) . unwrap_or_else ( || cx. typeck_results ( ) . expr_ty ( expr) ) ;
90
93
91
94
if let Constant :: Int ( n) = constant ( cx, cx. typeck_results ( ) , expr) ?
@@ -96,6 +99,22 @@ fn get_const_int_eval<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into
96
99
None
97
100
}
98
101
102
+ fn get_const_unsigned_int_eval < ' cx > (
103
+ cx : & LateContext < ' cx > ,
104
+ expr : & Expr < ' _ > ,
105
+ ty : impl Into < Option < Ty < ' cx > > > ,
106
+ ) -> Option < u128 > {
107
+ let ty = ty. into ( ) . unwrap_or_else ( || cx. typeck_results ( ) . expr_ty ( expr) ) ;
108
+
109
+ if let Constant :: Int ( n) = constant ( cx, cx. typeck_results ( ) , expr) ?
110
+ && let ty:: Uint ( _ity) = * ty. kind ( )
111
+ {
112
+ return Some ( n) ;
113
+ }
114
+ None
115
+ }
116
+
117
+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
99
118
enum Sign {
100
119
ZeroOrPositive ,
101
120
Negative ,
@@ -104,9 +123,12 @@ enum Sign {
104
123
105
124
fn expr_sign < ' cx > ( cx : & LateContext < ' cx > , expr : & Expr < ' _ > , ty : impl Into < Option < Ty < ' cx > > > ) -> Sign {
106
125
// Try evaluate this expr first to see if it's positive
107
- if let Some ( val) = get_const_int_eval ( cx, expr, ty) {
126
+ if let Some ( val) = get_const_signed_int_eval ( cx, expr, ty) {
108
127
return if val >= 0 { Sign :: ZeroOrPositive } else { Sign :: Negative } ;
109
128
}
129
+ if let Some ( _val) = get_const_unsigned_int_eval ( cx, expr, None ) {
130
+ return Sign :: ZeroOrPositive ;
131
+ }
110
132
111
133
// Calling on methods that always return non-negative values.
112
134
if let ExprKind :: MethodCall ( path, caller, args, ..) = expr. kind {
@@ -144,12 +166,13 @@ fn expr_sign<'cx>(cx: &LateContext<'cx>, expr: &Expr<'_>, ty: impl Into<Option<T
144
166
/// Otherwise, returns [`Sign::Uncertain`].
145
167
fn pow_call_result_sign ( cx : & LateContext < ' _ > , base : & Expr < ' _ > , exponent : & Expr < ' _ > ) -> Sign {
146
168
let base_sign = expr_sign ( cx, base, None ) ;
147
- let exponent_val = get_const_int_eval ( cx, exponent, None ) ;
169
+
170
+ // Rust's integer pow() functions take an unsigned exponent.
171
+ let exponent_val = get_const_unsigned_int_eval ( cx, exponent, None ) ;
148
172
let exponent_is_even = exponent_val. map ( |val| val % 2 == 0 ) ;
149
173
150
174
match ( base_sign, exponent_is_even) {
151
175
// Non-negative bases always return non-negative results, ignoring overflow.
152
- // This is because Rust's integer pow() functions take an unsigned exponent.
153
176
( Sign :: ZeroOrPositive , _) => Sign :: ZeroOrPositive ,
154
177
155
178
// Any base raised to an even exponent is non-negative.
0 commit comments