From 064825e734e9472925664ad681e055602ea62397 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Fri, 1 Aug 2025 20:13:48 +0200 Subject: [PATCH 1/3] Add suggestion to `cast_sign_loss` and `cast_possible_wrap` using the `cast_{un,}signed()` methods --- clippy_lints/src/casts/cast_possible_wrap.rs | 30 ++++++- clippy_lints/src/casts/cast_sign_loss.rs | 29 ++++++- clippy_lints/src/casts/mod.rs | 4 +- clippy_lints/src/casts/utils.rs | 32 ++++++++ clippy_utils/src/msrvs.rs | 2 +- tests/ui/cast.stderr | 82 ++++++++++---------- 6 files changed, 131 insertions(+), 48 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index e26c03ccda93..5a8b3e6d9a41 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -1,4 +1,7 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; +use rustc_errors::Applicability; use rustc_hir::Expr; use rustc_lint::LateContext; use rustc_middle::ty::Ty; @@ -16,7 +19,14 @@ enum EmitState { LintOnPtrSize(u64), } -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { +pub(super) fn check( + cx: &LateContext<'_>, + expr: &Expr<'_>, + cast_op: &Expr<'_>, + cast_from: Ty<'_>, + cast_to: Ty<'_>, + msrv: Msrv, +) { let (Some(from_nbits), Some(to_nbits)) = ( utils::int_ty_to_nbits(cx.tcx, cast_from), utils::int_ty_to_nbits(cx.tcx, cast_to), @@ -85,5 +95,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca .note("`usize` and `isize` may be as small as 16 bits on some platforms") .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types"); } + + if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST) + && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to) + { + let method = match cast { + utils::CastTo::Signed => "cast_signed()", + utils::CastTo::Unsigned => "cast_unsigned()", + }; + let mut app = Applicability::MaybeIncorrect; + let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app); + + diag.span_suggestion( + expr.span, + format!("if this is intentional, consider using `{method}` instead"), + format!("{}.{method}", sugg.maybe_paren()), + app, + ); + } }); } diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index a70bd8861919..757d53e394ff 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -2,15 +2,18 @@ use std::convert::Infallible; use std::ops::ControlFlow; use clippy_utils::consts::{ConstEvalCtxt, Constant}; -use clippy_utils::diagnostics::span_lint; +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::msrvs::{self, Msrv}; +use clippy_utils::sugg::Sugg; use clippy_utils::visitors::{Descend, for_each_expr_without_closures}; use clippy_utils::{method_chain_args, sext, sym}; +use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, Ty}; use rustc_span::Symbol; -use super::CAST_SIGN_LOSS; +use super::{CAST_SIGN_LOSS, utils}; /// A list of methods that can never return a negative value. /// Includes methods that panic rather than returning a negative value. @@ -42,13 +45,33 @@ pub(super) fn check<'cx>( cast_op: &Expr<'_>, cast_from: Ty<'cx>, cast_to: Ty<'_>, + msrv: Msrv, ) { if should_lint(cx, cast_op, cast_from, cast_to) { - span_lint( + span_lint_and_then( cx, CAST_SIGN_LOSS, expr.span, format!("casting `{cast_from}` to `{cast_to}` may lose the sign of the value"), + |diag| { + if msrv.meets(cx, msrvs::INTEGER_SIGN_CAST) + && let Some(cast) = utils::is_signedness_cast(cast_from, cast_to) + { + let method = match cast { + utils::CastTo::Signed => "cast_signed()", + utils::CastTo::Unsigned => "cast_unsigned()", + }; + let mut app = Applicability::MaybeIncorrect; + let sugg = Sugg::hir_with_context(cx, cast_op, expr.span.ctxt(), "..", &mut app); + + diag.span_suggestion( + expr.span, + format!("if this is intentional, consider using `{method}` instead"), + format!("{}.{method}", sugg.maybe_paren()), + app, + ); + } + }, ); } } diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 37accff5eaa8..4df2d81ea355 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -887,9 +887,9 @@ impl<'tcx> LateLintPass<'tcx> for Casts { if cast_to.is_numeric() { cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span); if cast_from.is_numeric() { - cast_possible_wrap::check(cx, expr, cast_from, cast_to); + cast_possible_wrap::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); cast_precision_loss::check(cx, expr, cast_from, cast_to); - cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to); + cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); cast_abs_to_unsigned::check(cx, expr, cast_from_expr, cast_from, cast_to, self.msrv); cast_nan_to_int::check(cx, expr, cast_from_expr, cast_from, cast_to); } diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index d846d78b9ee7..8251e48da5cd 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -60,3 +60,35 @@ pub(super) fn enum_ty_to_nbits(adt: AdtDef<'_>, tcx: TyCtxt<'_>) -> u64 { neg_bits.max(pos_bits).into() } } + +pub(super) enum CastTo { + Signed, + Unsigned, +} +/// Returns `Some` if the type cast is between 2 integral types that differ +/// only in signedness, otherwise `None`. The value of `Some` is which +/// signedness is casted to. +pub(super) fn is_signedness_cast(cast_from: Ty<'_>, cast_to: Ty<'_>) -> Option { + if !cast_from.is_integral() || !cast_to.is_integral() { + return None; + } + if cast_from.is_signed() == cast_to.is_signed() { + return None; + } + if as_uint_ty(cast_from) != as_uint_ty(cast_to) { + return None; + } + + if cast_to.is_signed() { + Some(CastTo::Signed) + } else { + Some(CastTo::Unsigned) + } +} +fn as_uint_ty(ty: Ty<'_>) -> Option { + match ty.kind() { + ty::Uint(uint_ty) => Some(*uint_ty), + ty::Int(int_ty) => Some(int_ty.to_unsigned()), + _ => None, + } +} diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs index 24ed4c3a8bec..a38550a7b552 100644 --- a/clippy_utils/src/msrvs.rs +++ b/clippy_utils/src/msrvs.rs @@ -24,7 +24,7 @@ macro_rules! msrv_aliases { // names may refer to stabilized feature flags or library items msrv_aliases! { 1,88,0 { LET_CHAINS } - 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF } + 1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT, CONST_CHAR_IS_DIGIT, UNSIGNED_IS_MULTIPLE_OF, INTEGER_SIGN_CAST } 1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL } 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR } 1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 1cb30d956679..13e0a5583cdc 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -194,7 +194,7 @@ error: casting `u8` to `i8` may wrap around the value --> tests/ui/cast.rs:88:5 | LL | 1u8 as i8; - | ^^^^^^^^^ + | ^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u8.cast_signed()` | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` @@ -203,25 +203,25 @@ error: casting `u16` to `i16` may wrap around the value --> tests/ui/cast.rs:91:5 | LL | 1u16 as i16; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u16.cast_signed()` error: casting `u32` to `i32` may wrap around the value --> tests/ui/cast.rs:94:5 | LL | 1u32 as i32; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u32.cast_signed()` error: casting `u64` to `i64` may wrap around the value --> tests/ui/cast.rs:97:5 | LL | 1u64 as i64; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u64.cast_signed()` error: casting `usize` to `isize` may wrap around the value --> tests/ui/cast.rs:100:5 | LL | 1usize as isize; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1usize.cast_signed()` error: casting `usize` to `i8` may truncate the value --> tests/ui/cast.rs:104:5 @@ -321,43 +321,43 @@ error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:138:5 | LL | -1i32 as u32; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1i32).cast_unsigned()` error: casting `isize` to `usize` may lose the sign of the value --> tests/ui/cast.rs:142:5 | LL | -1isize as usize; - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1isize).cast_unsigned()` error: casting `i8` to `u8` may lose the sign of the value --> tests/ui/cast.rs:154:5 | LL | (i8::MIN).abs() as u8; - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(i8::MIN).abs().cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:159:5 | LL | (-1i64).abs() as u64; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1i64).abs().cast_unsigned()` error: casting `isize` to `usize` may lose the sign of the value --> tests/ui/cast.rs:161:5 | LL | (-1isize).abs() as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1isize).abs().cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:169:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(unsafe { (-1i64).checked_abs().unwrap_unchecked() }).cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:185:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }).cast_unsigned()` error: casting `i64` to `i8` may truncate the value --> tests/ui/cast.rs:237:5 @@ -495,79 +495,79 @@ error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:438:9 | LL | (x * x) as u32; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:444:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x * x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:447:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(2_i32).checked_pow(3).unwrap().cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:449:5 | LL | (-2_i32).pow(3) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-2_i32).pow(3).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:454:5 | LL | (-5_i32 % 2) as u32; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-5_i32 % 2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:457:5 | LL | (-5_i32 % -2) as u32; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-5_i32 % -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:461:5 | LL | (-2_i32 >> 1) as u32; - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-2_i32 >> 1).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:465:5 | LL | (x * x) as u32; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:467:5 | LL | (x * x * x) as u32; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x * x).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:471:5 | LL | (y * y * y * y * -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y * y * y * -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:474:5 | LL | (y * y * y / y * 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y * y / y * 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:476:5 | LL | (y * y / y * 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y / y * 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:479:5 | LL | (y / y * y * -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y / y * y * -2).cast_unsigned()` error: equal expressions as operands to `/` --> tests/ui/cast.rs:479:6 @@ -581,97 +581,97 @@ error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:483:5 | LL | (y + y + y + -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y + y + y + -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:486:5 | LL | (y + y + y + 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y + y + y + 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:490:5 | LL | (z + -2) as u16; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(z + -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:493:5 | LL | (z + z + 2) as u16; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(z + z + 2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:497:9 | LL | (a * a * b * b * c * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * a * b * b * c * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:499:9 | LL | (a * b * c) as u32; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:502:9 | LL | (a * -b * c) as u32; - | ^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * -b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:505:9 | LL | (a * b * c * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:507:9 | LL | (a * -2) as u32; - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:510:9 | LL | (a * b * c * -2) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c * -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:513:9 | LL | (a / b) as u32; - | ^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:515:9 | LL | (a / b * c) as u32; - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:518:9 | LL | (a / b + b * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b + b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:521:9 | LL | a.saturating_pow(3) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `a.saturating_pow(3).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:524:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a.abs() * b.pow(2) / c.abs()).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:532:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss - | ^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `i32::MIN.cast_unsigned()` ... LL | m!(); | ---- in this macro invocation From 0eb16ea97b5161da7874f772e20e49f02af20189 Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sat, 2 Aug 2025 00:16:08 +0200 Subject: [PATCH 2/3] Add test to ensure that suggestions are only emitted if MSRV supports it --- tests/ui/cast.rs | 13 +++++++++++++ tests/ui/cast.stderr | 14 +++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index 525be8216500..fab02bf7b24e 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -569,3 +569,16 @@ fn issue12721() { (255 % 999999u64) as u8; //~^ cast_possible_truncation } + +mod issue14150 { + #[clippy::msrv = "1.87"] + fn msrv_supports_cast_signed() { + _ = 1u8 as i8; + //~^ cast_possible_wrap + } + #[clippy::msrv = "1.86"] + fn msrv_doesnt_supports_cast_signed() { + _ = 1u8 as i8; + //~^ cast_possible_wrap + } +} diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index 13e0a5583cdc..f131369df241 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -752,5 +752,17 @@ LL - (255 % 999999u64) as u8; LL + u8::try_from(255 % 999999u64); | -error: aborting due to 92 previous errors +error: casting `u8` to `i8` may wrap around the value + --> tests/ui/cast.rs:576:13 + | +LL | _ = 1u8 as i8; + | ^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u8.cast_signed()` + +error: casting `u8` to `i8` may wrap around the value + --> tests/ui/cast.rs:581:13 + | +LL | _ = 1u8 as i8; + | ^^^^^^^^^ + +error: aborting due to 94 previous errors From 4e286bb8fb305d6ba864ff8b2c806b4fd189657a Mon Sep 17 00:00:00 2001 From: RunDevelopment Date: Sun, 3 Aug 2025 13:44:56 +0200 Subject: [PATCH 3/3] Apply suggestions from code review --- clippy_lints/src/casts/cast_possible_wrap.rs | 2 +- clippy_lints/src/casts/cast_sign_loss.rs | 2 +- clippy_lints/src/casts/utils.rs | 23 +----- tests/ui/cast.stderr | 84 ++++++++++---------- 4 files changed, 47 insertions(+), 64 deletions(-) diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs index 5a8b3e6d9a41..9eaa6e4cf26e 100644 --- a/clippy_lints/src/casts/cast_possible_wrap.rs +++ b/clippy_lints/src/casts/cast_possible_wrap.rs @@ -108,7 +108,7 @@ pub(super) fn check( diag.span_suggestion( expr.span, - format!("if this is intentional, consider using `{method}` instead"), + format!("if this is intentional, use `{method}` instead"), format!("{}.{method}", sugg.maybe_paren()), app, ); diff --git a/clippy_lints/src/casts/cast_sign_loss.rs b/clippy_lints/src/casts/cast_sign_loss.rs index 757d53e394ff..f870d27b796e 100644 --- a/clippy_lints/src/casts/cast_sign_loss.rs +++ b/clippy_lints/src/casts/cast_sign_loss.rs @@ -66,7 +66,7 @@ pub(super) fn check<'cx>( diag.span_suggestion( expr.span, - format!("if this is intentional, consider using `{method}` instead"), + format!("if this is intentional, use `{method}` instead"), format!("{}.{method}", sugg.maybe_paren()), app, ); diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index 8251e48da5cd..707fc2a8eed3 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -69,26 +69,9 @@ pub(super) enum CastTo { /// only in signedness, otherwise `None`. The value of `Some` is which /// signedness is casted to. pub(super) fn is_signedness_cast(cast_from: Ty<'_>, cast_to: Ty<'_>) -> Option { - if !cast_from.is_integral() || !cast_to.is_integral() { - return None; - } - if cast_from.is_signed() == cast_to.is_signed() { - return None; - } - if as_uint_ty(cast_from) != as_uint_ty(cast_to) { - return None; - } - - if cast_to.is_signed() { - Some(CastTo::Signed) - } else { - Some(CastTo::Unsigned) - } -} -fn as_uint_ty(ty: Ty<'_>) -> Option { - match ty.kind() { - ty::Uint(uint_ty) => Some(*uint_ty), - ty::Int(int_ty) => Some(int_ty.to_unsigned()), + match (cast_from.kind(), cast_to.kind()) { + (ty::Int(from), ty::Uint(to)) if from.to_unsigned() == *to => Some(CastTo::Unsigned), + (ty::Uint(from), ty::Int(to)) if *from == to.to_unsigned() => Some(CastTo::Signed), _ => None, } } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index f131369df241..8c48855123f9 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -194,7 +194,7 @@ error: casting `u8` to `i8` may wrap around the value --> tests/ui/cast.rs:88:5 | LL | 1u8 as i8; - | ^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u8.cast_signed()` + | ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()` | = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::cast_possible_wrap)]` @@ -203,25 +203,25 @@ error: casting `u16` to `i16` may wrap around the value --> tests/ui/cast.rs:91:5 | LL | 1u16 as i16; - | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u16.cast_signed()` + | ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u16.cast_signed()` error: casting `u32` to `i32` may wrap around the value --> tests/ui/cast.rs:94:5 | LL | 1u32 as i32; - | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u32.cast_signed()` + | ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u32.cast_signed()` error: casting `u64` to `i64` may wrap around the value --> tests/ui/cast.rs:97:5 | LL | 1u64 as i64; - | ^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u64.cast_signed()` + | ^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u64.cast_signed()` error: casting `usize` to `isize` may wrap around the value --> tests/ui/cast.rs:100:5 | LL | 1usize as isize; - | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1usize.cast_signed()` + | ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1usize.cast_signed()` error: casting `usize` to `i8` may truncate the value --> tests/ui/cast.rs:104:5 @@ -321,43 +321,43 @@ error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:138:5 | LL | -1i32 as u32; - | ^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1i32).cast_unsigned()` + | ^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i32).cast_unsigned()` error: casting `isize` to `usize` may lose the sign of the value --> tests/ui/cast.rs:142:5 | LL | -1isize as usize; - | ^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1isize).cast_unsigned()` + | ^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).cast_unsigned()` error: casting `i8` to `u8` may lose the sign of the value --> tests/ui/cast.rs:154:5 | LL | (i8::MIN).abs() as u8; - | ^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(i8::MIN).abs().cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(i8::MIN).abs().cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:159:5 | LL | (-1i64).abs() as u64; - | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1i64).abs().cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1i64).abs().cast_unsigned()` error: casting `isize` to `usize` may lose the sign of the value --> tests/ui/cast.rs:161:5 | LL | (-1isize).abs() as usize; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-1isize).abs().cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-1isize).abs().cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:169:5 | LL | (unsafe { (-1i64).checked_abs().unwrap_unchecked() }) as u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(unsafe { (-1i64).checked_abs().unwrap_unchecked() }).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_abs().unwrap_unchecked() }).cast_unsigned()` error: casting `i64` to `u64` may lose the sign of the value --> tests/ui/cast.rs:185:5 | LL | (unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }) as u64; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(unsafe { (-1i64).checked_isqrt().unwrap_unchecked() }).cast_unsigned()` error: casting `i64` to `i8` may truncate the value --> tests/ui/cast.rs:237:5 @@ -495,79 +495,79 @@ error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:438:9 | LL | (x * x) as u32; - | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x).cast_unsigned()` + | ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:444:32 | LL | let _a = |x: i32| -> u32 { (x * x * x * x) as u32 }; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x * x * x).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:447:5 | LL | (2_i32).checked_pow(3).unwrap() as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(2_i32).checked_pow(3).unwrap().cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(2_i32).checked_pow(3).unwrap().cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:449:5 | LL | (-2_i32).pow(3) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-2_i32).pow(3).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32).pow(3).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:454:5 | LL | (-5_i32 % 2) as u32; - | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-5_i32 % 2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % 2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:457:5 | LL | (-5_i32 % -2) as u32; - | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-5_i32 % -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-5_i32 % -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:461:5 | LL | (-2_i32 >> 1) as u32; - | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(-2_i32 >> 1).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(-2_i32 >> 1).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:465:5 | LL | (x * x) as u32; - | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x).cast_unsigned()` + | ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:467:5 | LL | (x * x * x) as u32; - | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(x * x * x).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(x * x * x).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:471:5 | LL | (y * y * y * y * -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y * y * y * -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y * y * -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:474:5 | LL | (y * y * y / y * 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y * y / y * 2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y * y / y * 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:476:5 | LL | (y * y / y * 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y * y / y * 2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y * y / y * 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:479:5 | LL | (y / y * y * -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y / y * y * -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y / y * y * -2).cast_unsigned()` error: equal expressions as operands to `/` --> tests/ui/cast.rs:479:6 @@ -581,97 +581,97 @@ error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:483:5 | LL | (y + y + y + -2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y + y + y + -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:486:5 | LL | (y + y + y + 2) as u16; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(y + y + y + 2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(y + y + y + 2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:490:5 | LL | (z + -2) as u16; - | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(z + -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + -2).cast_unsigned()` error: casting `i16` to `u16` may lose the sign of the value --> tests/ui/cast.rs:493:5 | LL | (z + z + 2) as u16; - | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(z + z + 2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(z + z + 2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:497:9 | LL | (a * a * b * b * c * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * a * b * b * c * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * a * b * b * c * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:499:9 | LL | (a * b * c) as u32; - | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:502:9 | LL | (a * -b * c) as u32; - | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * -b * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:505:9 | LL | (a * b * c * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:507:9 | LL | (a * -2) as u32; - | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:510:9 | LL | (a * b * c * -2) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a * b * c * -2).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a * b * c * -2).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:513:9 | LL | (a / b) as u32; - | ^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b).cast_unsigned()` + | ^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:515:9 | LL | (a / b * c) as u32; - | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:518:9 | LL | (a / b + b * c) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a / b + b * c).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a / b + b * c).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:521:9 | LL | a.saturating_pow(3) as u32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `a.saturating_pow(3).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `a.saturating_pow(3).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:524:9 | LL | (a.abs() * b.pow(2) / c.abs()) as u32 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `(a.abs() * b.pow(2) / c.abs()).cast_unsigned()` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `(a.abs() * b.pow(2) / c.abs()).cast_unsigned()` error: casting `i32` to `u32` may lose the sign of the value --> tests/ui/cast.rs:532:21 | LL | let _ = i32::MIN as u32; // cast_sign_loss - | ^^^^^^^^^^^^^^^ help: if this is intentional, consider using `cast_unsigned()` instead: `i32::MIN.cast_unsigned()` + | ^^^^^^^^^^^^^^^ help: if this is intentional, use `cast_unsigned()` instead: `i32::MIN.cast_unsigned()` ... LL | m!(); | ---- in this macro invocation @@ -756,7 +756,7 @@ error: casting `u8` to `i8` may wrap around the value --> tests/ui/cast.rs:576:13 | LL | _ = 1u8 as i8; - | ^^^^^^^^^ help: if this is intentional, consider using `cast_signed()` instead: `1u8.cast_signed()` + | ^^^^^^^^^ help: if this is intentional, use `cast_signed()` instead: `1u8.cast_signed()` error: casting `u8` to `i8` may wrap around the value --> tests/ui/cast.rs:581:13