@@ -9,15 +9,17 @@ use rustc_ast as ast;
99use rustc_data_structures:: fx:: FxHashSet ;
1010use rustc_hir as hir;
1111use rustc_lint:: { LateContext , LateLintPass } ;
12+ use rustc_middle:: ty:: Ty ;
1213use rustc_session:: impl_lint_pass;
1314use rustc_span:: source_map:: { Span , Spanned } ;
1415
1516const HARD_CODED_ALLOWED : & [ & str ] = & [
1617 "f32" ,
1718 "f64" ,
1819 "std::num::Saturating" ,
19- "std::string::String" ,
2020 "std::num::Wrapping" ,
21+ "std::string::String" ,
22+ "&str" ,
2123] ;
2224
2325#[ derive( Debug ) ]
@@ -60,15 +62,14 @@ impl ArithmeticSideEffects {
6062 }
6163
6264 /// Checks if the given `expr` has any of the inner `allowed` elements.
63- fn is_allowed_ty ( & self , cx : & LateContext < ' _ > , expr : & hir:: Expr < ' _ > ) -> bool {
64- self . allowed . contains (
65- cx. typeck_results ( )
66- . expr_ty ( expr)
67- . to_string ( )
68- . split ( '<' )
69- . next ( )
70- . unwrap_or_default ( ) ,
71- )
65+ fn is_allowed_ty ( & self , ty : Ty < ' _ > ) -> bool {
66+ self . allowed
67+ . contains ( ty. to_string ( ) . split ( '<' ) . next ( ) . unwrap_or_default ( ) )
68+ }
69+
70+ // For example, 8i32 or &i64::MAX.
71+ fn is_integral ( ty : Ty < ' _ > ) -> bool {
72+ ty. peel_refs ( ) . is_integral ( )
7273 }
7374
7475 // Common entry-point to avoid code duplication.
@@ -82,24 +83,13 @@ impl ArithmeticSideEffects {
8283 /// * Is `expr` is a literal integer reference like `&199`, returns the literal integer without
8384 /// references.
8485 /// * If `expr` is anything else, returns `None`.
85- fn literal_integer < ' expr , ' tcx > (
86- cx : & LateContext < ' tcx > ,
87- expr : & ' expr hir:: Expr < ' tcx > ,
88- ) -> Option < & ' expr hir:: Expr < ' tcx > > {
89- let expr_refs = cx. typeck_results ( ) . expr_ty ( expr) . peel_refs ( ) ;
90-
91- if !expr_refs. is_integral ( ) {
92- return None ;
93- }
94-
86+ fn literal_integer < ' expr , ' tcx > ( expr : & ' expr hir:: Expr < ' tcx > ) -> Option < & ' expr hir:: Expr < ' tcx > > {
9587 if matches ! ( expr. kind, hir:: ExprKind :: Lit ( _) ) {
9688 return Some ( expr) ;
9789 }
98-
9990 if let hir:: ExprKind :: AddrOf ( .., inn) = expr. kind && let hir:: ExprKind :: Lit ( _) = inn. kind {
10091 return Some ( inn)
10192 }
102-
10393 None
10494 }
10595
@@ -128,14 +118,21 @@ impl ArithmeticSideEffects {
128118 ) {
129119 return ;
130120 } ;
131- if self . is_allowed_ty ( cx, lhs) || self . is_allowed_ty ( cx, rhs) {
121+ let lhs_ty = cx. typeck_results ( ) . expr_ty ( lhs) ;
122+ let rhs_ty = cx. typeck_results ( ) . expr_ty ( rhs) ;
123+ let lhs_and_rhs_have_the_same_ty = lhs_ty == rhs_ty;
124+ if lhs_and_rhs_have_the_same_ty && self . is_allowed_ty ( lhs_ty) && self . is_allowed_ty ( rhs_ty) {
132125 return ;
133126 }
134- let has_valid_op = match ( Self :: literal_integer ( cx, lhs) , Self :: literal_integer ( cx, rhs) ) {
135- ( None , None ) => false ,
136- ( None , Some ( local_expr) ) => Self :: has_valid_op ( op, local_expr) ,
137- ( Some ( local_expr) , None ) => Self :: has_valid_op ( op, local_expr) ,
138- ( Some ( _) , Some ( _) ) => true ,
127+ let has_valid_op = if Self :: is_integral ( lhs_ty) && Self :: is_integral ( rhs_ty) {
128+ match ( Self :: literal_integer ( lhs) , Self :: literal_integer ( rhs) ) {
129+ ( None , None ) => false ,
130+ ( None , Some ( local_expr) ) => Self :: has_valid_op ( op, local_expr) ,
131+ ( Some ( local_expr) , None ) => Self :: has_valid_op ( op, local_expr) ,
132+ ( Some ( _) , Some ( _) ) => true ,
133+ }
134+ } else {
135+ false
139136 } ;
140137 if !has_valid_op {
141138 self . issue_lint ( cx, expr) ;
0 commit comments