about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/casts/cast_possible_wrap.rs30
-rw-r--r--clippy_lints/src/casts/cast_sign_loss.rs29
-rw-r--r--clippy_lints/src/casts/mod.rs4
-rw-r--r--clippy_lints/src/casts/utils.rs15
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--tests/ui/cast.rs13
-rw-r--r--tests/ui/cast.stderr96
7 files changed, 140 insertions, 49 deletions
diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs
index e26c03ccda9..9eaa6e4cf26 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, 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 a70bd886191..f870d27b796 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, use `{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 d2e62ee56e4..47cc1da0a6e 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -890,9 +890,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 d846d78b9ee..707fc2a8eed 100644
--- a/clippy_lints/src/casts/utils.rs
+++ b/clippy_lints/src/casts/utils.rs
@@ -60,3 +60,18 @@ 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<CastTo> {
+    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/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 896d607fbcd..032c5e4c752 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.rs b/tests/ui/cast.rs
index 525be821650..fab02bf7b24 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 1cb30d95667..8c48855123f 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, use `cast_unsigned()` instead: `i32::MIN.cast_unsigned()`
 ...
 LL |     m!();
    |     ---- in this macro invocation
@@ -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, use `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