diff --git a/clippy_lints/src/bool_assert_comparison.rs b/clippy_lints/src/bool_assert_comparison.rs index cdc192a47e4..2e061267ff5 100644 --- a/clippy_lints/src/bool_assert_comparison.rs +++ b/clippy_lints/src/bool_assert_comparison.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison { if let Some(span) = is_direct_expn_of(expr.span, mac) { if let Some(args) = higher::extract_assert_macro_args(expr) { if let [a, b, ..] = args[..] { - let nb_bool_args = is_bool_lit(a) as usize + is_bool_lit(b) as usize; + let nb_bool_args = usize::from(is_bool_lit(a)) + usize::from(is_bool_lit(b)); if nb_bool_args != 1 { // If there are two boolean arguments, we definitely don't understand diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs index 869deecfbd5..75dc9098033 100644 --- a/clippy_lints/src/casts/cast_lossless.rs +++ b/clippy_lints/src/casts/cast_lossless.rs @@ -72,7 +72,7 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to }; from_nbits < to_nbits }, - + (false, true) if matches!(cast_from.kind(), ty::Bool) => true, (_, _) => { matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)) }, diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 233abd17894..108f6fbc924 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -426,12 +426,16 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_any::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast::check(cx, expr, cast_expr, cast_from, cast_to); fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); - if cast_from.is_numeric() && cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); - cast_possible_wrap::check(cx, expr, cast_from, cast_to); - cast_precision_loss::check(cx, expr, cast_from, cast_to); + + if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { + if cast_from.is_numeric() { + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); + cast_possible_wrap::check(cx, expr, cast_from, cast_to); + cast_precision_loss::check(cx, expr, cast_from, cast_to); + cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); + } + cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to); - cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); } } diff --git a/tests/ui/cast_lossless_bool.fixed b/tests/ui/cast_lossless_bool.fixed new file mode 100644 index 00000000000..9e2da45c378 --- /dev/null +++ b/tests/ui/cast_lossless_bool.fixed @@ -0,0 +1,42 @@ +// run-rustfix + +#![allow(dead_code)] +#![warn(clippy::cast_lossless)] + +fn main() { + // Test clippy::cast_lossless with casts to integer types + let _ = u8::from(true); + let _ = u16::from(true); + let _ = u32::from(true); + let _ = u64::from(true); + let _ = u128::from(true); + let _ = usize::from(true); + + let _ = i8::from(true); + let _ = i16::from(true); + let _ = i32::from(true); + let _ = i64::from(true); + let _ = i128::from(true); + let _ = isize::from(true); + + // Test with an expression wrapped in parens + let _ = u16::from(true | false); +} + +// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, +// so we skip the lint if the expression is in a const fn. +// See #3656 +const fn abc(input: bool) -> u32 { + input as u32 +} + +// Same as the above issue. We can't suggest `::from` in const fns in impls +mod cast_lossless_in_impl { + struct A; + + impl A { + pub const fn convert(x: bool) -> u64 { + x as u64 + } + } +} diff --git a/tests/ui/cast_lossless_bool.rs b/tests/ui/cast_lossless_bool.rs new file mode 100644 index 00000000000..b6f6c59a01f --- /dev/null +++ b/tests/ui/cast_lossless_bool.rs @@ -0,0 +1,42 @@ +// run-rustfix + +#![allow(dead_code)] +#![warn(clippy::cast_lossless)] + +fn main() { + // Test clippy::cast_lossless with casts to integer types + let _ = true as u8; + let _ = true as u16; + let _ = true as u32; + let _ = true as u64; + let _ = true as u128; + let _ = true as usize; + + let _ = true as i8; + let _ = true as i16; + let _ = true as i32; + let _ = true as i64; + let _ = true as i128; + let _ = true as isize; + + // Test with an expression wrapped in parens + let _ = (true | false) as u16; +} + +// The lint would suggest using `u32::from(input)` here but the `XX::from` function is not const, +// so we skip the lint if the expression is in a const fn. +// See #3656 +const fn abc(input: bool) -> u32 { + input as u32 +} + +// Same as the above issue. We can't suggest `::from` in const fns in impls +mod cast_lossless_in_impl { + struct A; + + impl A { + pub const fn convert(x: bool) -> u64 { + x as u64 + } + } +} diff --git a/tests/ui/cast_lossless_bool.stderr b/tests/ui/cast_lossless_bool.stderr new file mode 100644 index 00000000000..a0d11f08acf --- /dev/null +++ b/tests/ui/cast_lossless_bool.stderr @@ -0,0 +1,82 @@ +error: casting `bool` to `u8` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:8:13 + | +LL | let _ = true as u8; + | ^^^^^^^^^^ help: try: `u8::from(true)` + | + = note: `-D clippy::cast-lossless` implied by `-D warnings` + +error: casting `bool` to `u16` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:9:13 + | +LL | let _ = true as u16; + | ^^^^^^^^^^^ help: try: `u16::from(true)` + +error: casting `bool` to `u32` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:10:13 + | +LL | let _ = true as u32; + | ^^^^^^^^^^^ help: try: `u32::from(true)` + +error: casting `bool` to `u64` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:11:13 + | +LL | let _ = true as u64; + | ^^^^^^^^^^^ help: try: `u64::from(true)` + +error: casting `bool` to `u128` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:12:13 + | +LL | let _ = true as u128; + | ^^^^^^^^^^^^ help: try: `u128::from(true)` + +error: casting `bool` to `usize` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:13:13 + | +LL | let _ = true as usize; + | ^^^^^^^^^^^^^ help: try: `usize::from(true)` + +error: casting `bool` to `i8` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:15:13 + | +LL | let _ = true as i8; + | ^^^^^^^^^^ help: try: `i8::from(true)` + +error: casting `bool` to `i16` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:16:13 + | +LL | let _ = true as i16; + | ^^^^^^^^^^^ help: try: `i16::from(true)` + +error: casting `bool` to `i32` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:17:13 + | +LL | let _ = true as i32; + | ^^^^^^^^^^^ help: try: `i32::from(true)` + +error: casting `bool` to `i64` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:18:13 + | +LL | let _ = true as i64; + | ^^^^^^^^^^^ help: try: `i64::from(true)` + +error: casting `bool` to `i128` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:19:13 + | +LL | let _ = true as i128; + | ^^^^^^^^^^^^ help: try: `i128::from(true)` + +error: casting `bool` to `isize` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:20:13 + | +LL | let _ = true as isize; + | ^^^^^^^^^^^^^ help: try: `isize::from(true)` + +error: casting `bool` to `u16` may become silently lossy if you later change the type + --> $DIR/cast_lossless_bool.rs:23:13 + | +LL | let _ = (true | false) as u16; + | ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)` + +error: aborting due to 13 previous errors +