1
+ mod cast_precision_loss;
2
+ mod utils;
3
+
1
4
use std:: borrow:: Cow ;
2
5
3
6
use if_chain:: if_chain;
@@ -6,7 +9,7 @@ use rustc_errors::Applicability;
6
9
use rustc_hir:: { Expr , ExprKind , GenericArg , Lit , MutTy , Mutability , TyKind , UnOp } ;
7
10
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
8
11
use rustc_middle:: lint:: in_external_macro;
9
- use rustc_middle:: ty:: { self , FloatTy , InferTy , IntTy , Ty , TyCtxt , TypeAndMut , UintTy } ;
12
+ use rustc_middle:: ty:: { self , FloatTy , InferTy , Ty , TypeAndMut , UintTy } ;
10
13
use rustc_semver:: RustcVersion ;
11
14
use rustc_session:: { declare_lint_pass, declare_tool_lint, impl_lint_pass} ;
12
15
use rustc_span:: symbol:: sym;
@@ -20,6 +23,8 @@ use crate::utils::{
20
23
span_lint_and_then,
21
24
} ;
22
25
26
+ use utils:: int_ty_to_nbits;
27
+
23
28
declare_clippy_lint ! {
24
29
/// **What it does:** Checks for casts from any numerical to a float type where
25
30
/// the receiving type cannot store all values from the original type without
@@ -249,57 +254,6 @@ declare_clippy_lint! {
249
254
"casting a function pointer to a numeric type not wide enough to store the address"
250
255
}
251
256
252
- /// Returns the size in bits of an integral type.
253
- /// Will return 0 if the type is not an int or uint variant
254
- fn int_ty_to_nbits ( typ : Ty < ' _ > , tcx : TyCtxt < ' _ > ) -> u64 {
255
- match typ. kind ( ) {
256
- ty:: Int ( i) => match i {
257
- IntTy :: Isize => tcx. data_layout . pointer_size . bits ( ) ,
258
- IntTy :: I8 => 8 ,
259
- IntTy :: I16 => 16 ,
260
- IntTy :: I32 => 32 ,
261
- IntTy :: I64 => 64 ,
262
- IntTy :: I128 => 128 ,
263
- } ,
264
- ty:: Uint ( i) => match i {
265
- UintTy :: Usize => tcx. data_layout . pointer_size . bits ( ) ,
266
- UintTy :: U8 => 8 ,
267
- UintTy :: U16 => 16 ,
268
- UintTy :: U32 => 32 ,
269
- UintTy :: U64 => 64 ,
270
- UintTy :: U128 => 128 ,
271
- } ,
272
- _ => 0 ,
273
- }
274
- }
275
-
276
- fn span_precision_loss_lint ( cx : & LateContext < ' _ > , expr : & Expr < ' _ > , cast_from : Ty < ' _ > , cast_to_f64 : bool ) {
277
- let mantissa_nbits = if cast_to_f64 { 52 } else { 23 } ;
278
- let arch_dependent = is_isize_or_usize ( cast_from) && cast_to_f64;
279
- let arch_dependent_str = "on targets with 64-bit wide pointers " ;
280
- let from_nbits_str = if arch_dependent {
281
- "64" . to_owned ( )
282
- } else if is_isize_or_usize ( cast_from) {
283
- "32 or 64" . to_owned ( )
284
- } else {
285
- int_ty_to_nbits ( cast_from, cx. tcx ) . to_string ( )
286
- } ;
287
- span_lint (
288
- cx,
289
- CAST_PRECISION_LOSS ,
290
- expr. span ,
291
- & format ! (
292
- "casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
293
- but `{1}`'s mantissa is only {4} bits wide)",
294
- cast_from,
295
- if cast_to_f64 { "f64" } else { "f32" } ,
296
- if arch_dependent { arch_dependent_str } else { "" } ,
297
- from_nbits_str,
298
- mantissa_nbits
299
- ) ,
300
- ) ;
301
- }
302
-
303
257
fn should_strip_parens ( op : & Expr < ' _ > , snip : & str ) -> bool {
304
258
if let ExprKind :: Binary ( _, _, _) = op. kind {
305
259
if snip. starts_with ( '(' ) && snip. ends_with ( ')' ) {
@@ -629,6 +583,7 @@ fn lint_numeric_casts<'tcx>(
629
583
cast_from : Ty < ' tcx > ,
630
584
cast_to : Ty < ' tcx > ,
631
585
) {
586
+ cast_precision_loss:: check ( cx, expr, cast_from, cast_to) ;
632
587
match ( cast_from. is_integral ( ) , cast_to. is_integral ( ) ) {
633
588
( true , false ) => {
634
589
let from_nbits = int_ty_to_nbits ( cast_from, cx. tcx ) ;
@@ -637,9 +592,6 @@ fn lint_numeric_casts<'tcx>(
637
592
} else {
638
593
64
639
594
} ;
640
- if is_isize_or_usize ( cast_from) || from_nbits >= to_nbits {
641
- span_precision_loss_lint ( cx, expr, cast_from, to_nbits == 64 ) ;
642
- }
643
595
if from_nbits < to_nbits {
644
596
span_lossless_lint ( cx, expr, cast_expr, cast_from, cast_to) ;
645
597
}
0 commit comments