Skip to content

Commit fc4254b

Browse files
committed
cast_lossless: lint when converting char as well
1 parent e9aed87 commit fc4254b

File tree

4 files changed

+98
-24
lines changed

4 files changed

+98
-24
lines changed

clippy_lints/src/casts/cast_lossless.rs

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ use clippy_utils::is_in_const_context;
33
use clippy_utils::msrvs::{self, Msrv};
44
use clippy_utils::source::SpanRangeExt;
55
use clippy_utils::sugg::Sugg;
6-
use clippy_utils::ty::is_isize_or_usize;
76
use rustc_errors::Applicability;
87
use rustc_hir::{Expr, QPath, TyKind};
98
use rustc_lint::LateContext;
10-
use rustc_middle::ty::{self, FloatTy, Ty};
9+
use rustc_middle::ty::{self, FloatTy, IntTy, Ty, UintTy};
1110
use rustc_span::hygiene;
1211

1312
use super::{CAST_LOSSLESS, utils};
@@ -76,29 +75,21 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M
7675
return false;
7776
}
7877

79-
match (cast_from.is_integral(), cast_to.is_integral()) {
80-
(true, true) => {
81-
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
82-
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
83-
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
84-
!is_isize_or_usize(cast_from)
85-
&& !is_isize_or_usize(cast_to)
86-
&& from_nbits < to_nbits
87-
&& !cast_signed_to_unsigned
78+
match (cast_from.kind(), cast_to.kind()) {
79+
(ty::Bool, ty::Uint(_) | ty::Int(_)) => msrv.meets(cx, msrvs::FROM_BOOL),
80+
(ty::Uint(_), ty::Uint(UintTy::Usize)) | (ty::Uint(UintTy::U8) | ty::Int(_), ty::Int(IntTy::Isize)) => {
81+
utils::int_ty_to_nbits(cast_from, cx.tcx) <= 16
8882
},
89-
90-
(true, false) => {
91-
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
92-
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
93-
32
94-
} else {
95-
64
96-
};
97-
!is_isize_or_usize(cast_from) && from_nbits < to_nbits
98-
},
99-
(false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true,
100-
(_, _) => {
101-
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
83+
// No `f16` to `f32`: https://github.com/rust-lang/rust/issues/123831
84+
(ty::Uint(UintTy::Usize) | ty::Int(IntTy::Isize), _)
85+
| (_, ty::Uint(UintTy::Usize) | ty::Int(IntTy::Isize))
86+
| (ty::Float(FloatTy::F16), ty::Float(FloatTy::F32)) => false,
87+
(ty::Uint(_) | ty::Int(_), ty::Int(_)) | (ty::Uint(_), ty::Uint(_)) => {
88+
utils::int_ty_to_nbits(cast_from, cx.tcx) < utils::int_ty_to_nbits(cast_to, cx.tcx)
10289
},
90+
(ty::Uint(_) | ty::Int(_), ty::Float(fl)) => utils::int_ty_to_nbits(cast_from, cx.tcx) < fl.bit_width(),
91+
(ty::Char, ty::Uint(_)) => utils::int_ty_to_nbits(cast_to, cx.tcx) >= 32,
92+
(ty::Float(fl_from), ty::Float(fl_to)) => fl_from.bit_width() < fl_to.bit_width(),
93+
_ => false,
10394
}
10495
}

tests/ui/cast_lossless_char.fixed

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![warn(clippy::cast_lossless)]
2+
#![allow(clippy::char_lit_as_u8)]
3+
4+
type I32 = i32;
5+
type U32 = u32;
6+
7+
fn main() {
8+
let _ = u32::from('a');
9+
//~^ cast_lossless
10+
let _ = 'a' as i32;
11+
let _ = u64::from('a');
12+
//~^ cast_lossless
13+
let _ = 'a' as i64;
14+
let _ = U32::from('a');
15+
//~^ cast_lossless
16+
let _ = 'a' as I32;
17+
18+
let _ = 'a' as u8;
19+
let _ = 'a' as i8;
20+
}

tests/ui/cast_lossless_char.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#![warn(clippy::cast_lossless)]
2+
#![allow(clippy::char_lit_as_u8)]
3+
4+
type I32 = i32;
5+
type U32 = u32;
6+
7+
fn main() {
8+
let _ = 'a' as u32;
9+
//~^ cast_lossless
10+
let _ = 'a' as i32;
11+
let _ = 'a' as u64;
12+
//~^ cast_lossless
13+
let _ = 'a' as i64;
14+
let _ = 'a' as U32;
15+
//~^ cast_lossless
16+
let _ = 'a' as I32;
17+
18+
let _ = 'a' as u8;
19+
let _ = 'a' as i8;
20+
}

tests/ui/cast_lossless_char.stderr

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
error: casts from `char` to `u32` can be expressed infallibly using `From`
2+
--> tests/ui/cast_lossless_char.rs:8:13
3+
|
4+
LL | let _ = 'a' as u32;
5+
| ^^^^^^^^^^
6+
|
7+
= help: an `as` cast can become silently lossy if the types change in the future
8+
= note: `-D clippy::cast-lossless` implied by `-D warnings`
9+
= help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
10+
help: use `u32::from` instead
11+
|
12+
LL - let _ = 'a' as u32;
13+
LL + let _ = u32::from('a');
14+
|
15+
16+
error: casts from `char` to `u64` can be expressed infallibly using `From`
17+
--> tests/ui/cast_lossless_char.rs:11:13
18+
|
19+
LL | let _ = 'a' as u64;
20+
| ^^^^^^^^^^
21+
|
22+
= help: an `as` cast can become silently lossy if the types change in the future
23+
help: use `u64::from` instead
24+
|
25+
LL - let _ = 'a' as u64;
26+
LL + let _ = u64::from('a');
27+
|
28+
29+
error: casts from `char` to `u32` can be expressed infallibly using `From`
30+
--> tests/ui/cast_lossless_char.rs:14:13
31+
|
32+
LL | let _ = 'a' as U32;
33+
| ^^^^^^^^^^
34+
|
35+
= help: an `as` cast can become silently lossy if the types change in the future
36+
help: use `U32::from` instead
37+
|
38+
LL - let _ = 'a' as U32;
39+
LL + let _ = U32::from('a');
40+
|
41+
42+
error: aborting due to 3 previous errors
43+

0 commit comments

Comments
 (0)