@@ -66,8 +66,7 @@ fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx
6666 // a % b => [a]
6767 let exprs = exprs_with_selected_binop_peeled ( cast_op) ;
6868 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 ) {
7170 Sign :: Negative => negative_count += 1 ,
7271 Sign :: Uncertain => uncertain_count += 1 ,
7372 Sign :: ZeroOrPositive => ( ) ,
@@ -85,7 +84,11 @@ fn should_lint<'cx>(cx: &LateContext<'cx>, cast_op: &Expr<'_>, cast_from: Ty<'cx
8584 }
8685}
8786
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 > {
8992 let ty = ty. into ( ) . unwrap_or_else ( || cx. typeck_results ( ) . expr_ty ( expr) ) ;
9093
9194 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
9699 None
97100}
98101
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 ) ]
99118enum Sign {
100119 ZeroOrPositive ,
101120 Negative ,
@@ -104,9 +123,12 @@ enum Sign {
104123
105124fn expr_sign < ' cx > ( cx : & LateContext < ' cx > , expr : & Expr < ' _ > , ty : impl Into < Option < Ty < ' cx > > > ) -> Sign {
106125 // 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) {
108127 return if val >= 0 { Sign :: ZeroOrPositive } else { Sign :: Negative } ;
109128 }
129+ if let Some ( _val) = get_const_unsigned_int_eval ( cx, expr, None ) {
130+ return Sign :: ZeroOrPositive ;
131+ }
110132
111133 // Calling on methods that always return non-negative values.
112134 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
144166/// Otherwise, returns [`Sign::Uncertain`].
145167fn pow_call_result_sign ( cx : & LateContext < ' _ > , base : & Expr < ' _ > , exponent : & Expr < ' _ > ) -> Sign {
146168 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 ) ;
148172 let exponent_is_even = exponent_val. map ( |val| val % 2 == 0 ) ;
149173
150174 match ( base_sign, exponent_is_even) {
151175 // Non-negative bases always return non-negative results, ignoring overflow.
152- // This is because Rust's integer pow() functions take an unsigned exponent.
153176 ( Sign :: ZeroOrPositive , _) => Sign :: ZeroOrPositive ,
154177
155178 // Any base raised to an even exponent is non-negative.
0 commit comments