@@ -6,9 +6,10 @@ use clippy_utils::sugg::Sugg;
6
6
use clippy_utils:: ty:: { get_discriminant_value, is_isize_or_usize} ;
7
7
use rustc_errors:: { Applicability , Diag , SuggestionStyle } ;
8
8
use rustc_hir:: def:: { DefKind , Res } ;
9
- use rustc_hir:: { BinOpKind , Expr , ExprKind } ;
9
+ use rustc_hir:: { BinOpKind , Expr , ExprKind , QPath } ;
10
10
use rustc_lint:: LateContext ;
11
- use rustc_middle:: ty:: { self , FloatTy , Ty } ;
11
+ use rustc_middle:: ty:: { self , FloatTy , Ty , TyCtxt } ;
12
+ use rustc_span:: symbol:: sym;
12
13
use rustc_span:: Span ;
13
14
use rustc_target:: abi:: IntegerType ;
14
15
@@ -40,8 +41,8 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
40
41
get_constant_bits ( cx, right) . map_or ( 0 , |b| b. saturating_sub ( 1 ) )
41
42
} )
42
43
} ,
43
- BinOpKind :: Rem => get_constant_bits ( cx, right)
44
- . unwrap_or ( u64:: MAX )
44
+ BinOpKind :: Rem => constant_int ( cx, right)
45
+ . map_or ( u64:: MAX , |c| c . next_power_of_two ( ) . trailing_zeros ( ) . into ( ) )
45
46
. min ( apply_reductions ( cx, nbits, left, signed) ) ,
46
47
BinOpKind :: BitAnd => get_constant_bits ( cx, right)
47
48
. unwrap_or ( u64:: MAX )
@@ -79,6 +80,35 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
79
80
nbits
80
81
}
81
82
} ,
83
+ ExprKind :: Path ( QPath :: Resolved (
84
+ None ,
85
+ rustc_hir:: Path {
86
+ res : Res :: Def ( DefKind :: Const | DefKind :: AssocConst , def_id) ,
87
+ ..
88
+ } ,
89
+ ) )
90
+ // NOTE(@Jarcho): A constant from another crate might not have the same value
91
+ // for all versions of the crate. This isn't a problem for constants in the
92
+ // current crate since a crate can't compile against multiple versions of itself.
93
+ if def_id. is_local ( ) => {
94
+ // `constant()` already checks if a const item is based on `cfg!`.
95
+ get_constant_bits ( cx, expr) . unwrap_or ( nbits)
96
+ } ,
97
+ // mem::size_of::<T>();
98
+ ExprKind :: Call ( func, [ ] ) => {
99
+ if let ExprKind :: Path ( ref func_qpath) = func. kind
100
+ && let Some ( def_id) = cx. qpath_res ( func_qpath, func. hir_id ) . opt_def_id ( )
101
+ && cx. tcx . is_diagnostic_item ( sym:: mem_size_of, def_id)
102
+ && let Some ( ty) = cx. typeck_results ( ) . node_args ( func. hir_id ) . types ( ) . next ( )
103
+ && is_valid_sizeof ( cx. tcx , ty)
104
+ && let Ok ( layout) = cx. tcx . layout_of ( cx. param_env . and ( ty) )
105
+ {
106
+ let size: u64 = layout. layout . size ( ) . bytes ( ) ;
107
+ ( 64 - size. leading_zeros ( ) ) . into ( )
108
+ } else {
109
+ nbits
110
+ }
111
+ } ,
82
112
_ => nbits,
83
113
}
84
114
}
@@ -104,7 +134,7 @@ pub(super) fn check(
104
134
let ( should_lint, suffix) = match ( is_isize_or_usize ( cast_from) , is_isize_or_usize ( cast_to) ) {
105
135
( true , true ) | ( false , false ) => ( to_nbits < from_nbits, "" ) ,
106
136
( true , false ) => (
107
- to_nbits <= 32 ,
137
+ to_nbits < from_nbits && to_nbits < = 32 ,
108
138
if to_nbits == 32 {
109
139
" on targets with 64-bit wide pointers"
110
140
} else {
@@ -199,3 +229,23 @@ fn offer_suggestion(
199
229
SuggestionStyle :: ShowAlways ,
200
230
) ;
201
231
}
232
+
233
+ // FIXME(@tesuji): May extend this to a validator functions to include:
234
+ // * some ABI-guaranteed STD types,
235
+ // * some non-local crate types suggested in [PR-12962][1].
236
+ // [1]: https://github.com/rust-lang/rust-clippy/pull/12962#discussion_r1661500351
237
+ fn is_valid_sizeof < ' tcx > ( tcx : TyCtxt < ' tcx > , ty : Ty < ' tcx > ) -> bool {
238
+ if ty. is_primitive_ty ( ) || ty. is_any_ptr ( ) || ty. is_box ( ) || ty. is_slice ( ) {
239
+ return true ;
240
+ }
241
+ if let ty:: Adt ( def, args) = ty. kind ( )
242
+ && def. did ( ) . is_local ( )
243
+ {
244
+ def. all_fields ( ) . all ( |field| {
245
+ let ty = field. ty ( tcx, args) ;
246
+ is_valid_sizeof ( tcx, ty)
247
+ } )
248
+ } else {
249
+ false
250
+ }
251
+ }
0 commit comments