about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Macleod <alex@macleod.io>2024-07-22 19:00:58 +0000
committerAlex Macleod <alex@macleod.io>2024-07-24 14:32:41 +0000
commit6d28e1a954b9047fba0d50d78811c01d88e59f37 (patch)
tree752be7da15eb5d280db5813976cbb37bedf7d4d2
parent1807580a49d31457ca1fd9d3bcbbb9bf1cfd7a34 (diff)
downloadrust-6d28e1a954b9047fba0d50d78811c01d88e59f37.tar.gz
rust-6d28e1a954b9047fba0d50d78811c01d88e59f37.zip
Lint casts to `u128` in `cast_lossless`
-rw-r--r--clippy_lints/src/casts/cast_lossless.rs111
-rw-r--r--clippy_lints/src/casts/mod.rs36
-rw-r--r--clippy_utils/src/sugg.rs9
-rw-r--r--tests/ui/cast_lossless_bool.stderr149
-rw-r--r--tests/ui/cast_lossless_float.stderr129
-rw-r--r--tests/ui/cast_lossless_integer.fixed129
-rw-r--r--tests/ui/cast_lossless_integer.rs129
-rw-r--r--tests/ui/cast_lossless_integer.stderr523
-rw-r--r--tests/ui/floating_point_powf.fixed8
-rw-r--r--tests/ui/floating_point_powf.rs8
-rw-r--r--tests/ui/floating_point_powf.stderr32
-rw-r--r--tests/ui/types.fixed13
-rw-r--r--tests/ui/types.rs13
-rw-r--r--tests/ui/types.stderr11
14 files changed, 973 insertions, 327 deletions
diff --git a/clippy_lints/src/casts/cast_lossless.rs b/clippy_lints/src/casts/cast_lossless.rs
index d52ad1c6f23..ff460a3fd8e 100644
--- a/clippy_lints/src/casts/cast_lossless.rs
+++ b/clippy_lints/src/casts/cast_lossless.rs
@@ -1,19 +1,21 @@
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::in_constant;
-use clippy_utils::source::{snippet_opt, snippet_with_applicability};
+use clippy_utils::source::snippet_opt;
+use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_isize_or_usize;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, QPath, TyKind};
+use rustc_hir::{Expr, QPath, TyKind};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, FloatTy, Ty, UintTy};
+use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_span::hygiene;
 
 use super::{utils, CAST_LOSSLESS};
 
 pub(super) fn check(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
-    cast_op: &Expr<'_>,
+    cast_from_expr: &Expr<'_>,
     cast_from: Ty<'_>,
     cast_to: Ty<'_>,
     cast_to_hir: &rustc_hir::Ty<'_>,
@@ -23,64 +25,54 @@ pub(super) fn check(
         return;
     }
 
-    // The suggestion is to use a function call, so if the original expression
-    // has parens on the outside, they are no longer needed.
-    let mut app = Applicability::MachineApplicable;
-    let opt = snippet_opt(cx, cast_op.span.source_callsite());
-    let sugg = opt.as_ref().map_or_else(
-        || {
-            app = Applicability::HasPlaceholders;
-            ".."
-        },
-        |snip| {
-            if should_strip_parens(cast_op, snip) {
-                &snip[1..snip.len() - 1]
-            } else {
-                snip.as_str()
-            }
-        },
-    );
-
-    // Display the type alias instead of the aliased type. Fixes #11285
-    //
-    // FIXME: Once `lazy_type_alias` is stabilized(?) we should use `rustc_middle` types instead,
-    // this will allow us to display the right type with `cast_from` as well.
-    let cast_to_fmt = if let TyKind::Path(QPath::Resolved(None, path)) = cast_to_hir.kind
-        // It's a bit annoying but the turbofish is optional for types. A type in an `as` cast
-        // shouldn't have these if they're primitives, which are the only things we deal with.
-        //
-        // This could be removed for performance if this check is determined to have a pretty major
-        // effect.
-        && path.segments.iter().all(|segment| segment.args.is_none())
-    {
-        snippet_with_applicability(cx, cast_to_hir.span, "..", &mut app)
-    } else {
-        cast_to.to_string().into()
-    };
-
-    let message = if cast_from.is_bool() {
-        format!("casting `{cast_from}` to `{cast_to_fmt}` is more cleanly stated with `{cast_to_fmt}::from(_)`")
-    } else {
-        format!("casting `{cast_from}` to `{cast_to_fmt}` may become silently lossy if you later change the type")
-    };
-
-    span_lint_and_sugg(
+    span_lint_and_then(
         cx,
         CAST_LOSSLESS,
         expr.span,
-        message,
-        "try",
-        format!("{cast_to_fmt}::from({sugg})"),
-        app,
+        format!("casts from `{cast_from}` to `{cast_to}` can be expressed infallibly using `From`"),
+        |diag| {
+            diag.help("an `as` cast can become silently lossy if the types change in the future");
+            let mut applicability = Applicability::MachineApplicable;
+            let from_sugg = Sugg::hir_with_context(cx, cast_from_expr, expr.span.ctxt(), "<from>", &mut applicability);
+            let Some(ty) = snippet_opt(cx, hygiene::walk_chain(cast_to_hir.span, expr.span.ctxt())) else {
+                return;
+            };
+            match cast_to_hir.kind {
+                TyKind::Infer => {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        "use `Into::into` instead",
+                        format!("{}.into()", from_sugg.maybe_par()),
+                        applicability,
+                    );
+                },
+                // Don't suggest `A<_>::B::From(x)` or `macro!()::from(x)`
+                kind if matches!(kind, TyKind::Path(QPath::Resolved(_, path)) if path.segments.iter().any(|s| s.args.is_some()))
+                    || !cast_to_hir.span.eq_ctxt(expr.span) =>
+                {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        format!("use `<{ty}>::from` instead"),
+                        format!("<{ty}>::from({from_sugg})"),
+                        applicability,
+                    );
+                },
+                _ => {
+                    diag.span_suggestion_verbose(
+                        expr.span,
+                        format!("use `{ty}::from` instead"),
+                        format!("{ty}::from({from_sugg})"),
+                        applicability,
+                    );
+                },
+            }
+        },
     );
 }
 
 fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: &Msrv) -> bool {
     // Do not suggest using From in consts/statics until it is valid to do so (see #2267).
-    //
-    // If destination is u128, do not lint because source type cannot be larger
-    // If source is bool, still lint due to the lint message differing (refers to style)
-    if in_constant(cx, expr.hir_id) || (!cast_from.is_bool() && matches!(cast_to.kind(), ty::Uint(UintTy::U128))) {
+    if in_constant(cx, expr.hir_id) {
         return false;
     }
 
@@ -110,12 +102,3 @@ fn should_lint(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to
         },
     }
 }
-
-fn should_strip_parens(cast_expr: &Expr<'_>, snip: &str) -> bool {
-    if let ExprKind::Binary(_, _, _) = cast_expr.kind {
-        if snip.starts_with('(') && snip.ends_with(')') {
-            return true;
-        }
-    }
-    false
-}
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index 773731113ca..c31716fbcee 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -763,45 +763,45 @@ impl<'tcx> LateLintPass<'tcx> for Casts {
             return;
         }
 
-        if let ExprKind::Cast(cast_expr, cast_to_hir) = expr.kind {
+        if let ExprKind::Cast(cast_from_expr, cast_to_hir) = expr.kind {
             if is_hir_ty_cfg_dependant(cx, cast_to_hir) {
                 return;
             }
             let (cast_from, cast_to) = (
-                cx.typeck_results().expr_ty(cast_expr),
+                cx.typeck_results().expr_ty(cast_from_expr),
                 cx.typeck_results().expr_ty(expr),
             );
 
-            if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_expr, cast_from, cast_to) {
+            if !expr.span.from_expansion() && unnecessary_cast::check(cx, expr, cast_from_expr, cast_from, cast_to) {
                 return;
             }
-            cast_slice_from_raw_parts::check(cx, expr, cast_expr, cast_to, &self.msrv);
-            ptr_cast_constness::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
-            as_ptr_cast_mut::check(cx, expr, cast_expr, cast_to);
-            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);
-            zero_ptr::check(cx, expr, cast_expr, cast_to_hir);
+            cast_slice_from_raw_parts::check(cx, expr, cast_from_expr, cast_to, &self.msrv);
+            ptr_cast_constness::check(cx, expr, cast_from_expr, cast_from, cast_to, &self.msrv);
+            as_ptr_cast_mut::check(cx, expr, cast_from_expr, cast_to);
+            fn_to_numeric_cast_any::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            fn_to_numeric_cast::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
+            zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
 
             if cast_to.is_numeric() {
-                cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir.span);
+                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_precision_loss::check(cx, expr, cast_from, cast_to);
-                    cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to);
-                    cast_abs_to_unsigned::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv);
-                    cast_nan_to_int::check(cx, expr, cast_expr, cast_from, cast_to);
+                    cast_sign_loss::check(cx, expr, cast_from_expr, cast_from, cast_to);
+                    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);
                 }
-                cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
-                cast_enum_constructor::check(cx, expr, cast_expr, cast_from);
+                cast_lossless::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir, &self.msrv);
+                cast_enum_constructor::check(cx, expr, cast_from_expr, cast_from);
             }
 
             as_underscore::check(cx, expr, cast_to_hir);
 
             if self.msrv.meets(msrvs::PTR_FROM_REF) {
-                ref_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+                ref_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             } else if self.msrv.meets(msrvs::BORROW_AS_PTR) {
-                borrow_as_ptr::check(cx, expr, cast_expr, cast_to_hir);
+                borrow_as_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
             }
         }
 
diff --git a/clippy_utils/src/sugg.rs b/clippy_utils/src/sugg.rs
index 6319c7bfa6b..0f86d89c980 100644
--- a/clippy_utils/src/sugg.rs
+++ b/clippy_utils/src/sugg.rs
@@ -52,7 +52,8 @@ impl Display for Sugg<'_> {
 impl<'a> Sugg<'a> {
     /// Prepare a suggestion from an expression.
     pub fn hir_opt(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Self> {
-        let get_snippet = |span| snippet(cx, span, "");
+        let ctxt = expr.span.ctxt();
+        let get_snippet = |span| snippet_with_context(cx, span, ctxt, "", &mut Applicability::Unspecified).0;
         snippet_opt(cx, expr.span).map(|_| Self::hir_from_snippet(expr, get_snippet))
     }
 
@@ -100,7 +101,9 @@ impl<'a> Sugg<'a> {
         applicability: &mut Applicability,
     ) -> Self {
         if expr.span.ctxt() == ctxt {
-            Self::hir_from_snippet(expr, |span| snippet(cx, span, default))
+            Self::hir_from_snippet(expr, |span| {
+                snippet_with_context(cx, span, ctxt, default, applicability).0
+            })
         } else {
             let (snip, _) = snippet_with_context(cx, expr.span, ctxt, default, applicability);
             Sugg::NonParen(snip)
@@ -109,7 +112,7 @@ impl<'a> Sugg<'a> {
 
     /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*`
     /// function variants of `Sugg`, since these use different snippet functions.
-    fn hir_from_snippet(expr: &hir::Expr<'_>, get_snippet: impl Fn(Span) -> Cow<'a, str>) -> Self {
+    fn hir_from_snippet(expr: &hir::Expr<'_>, mut get_snippet: impl FnMut(Span) -> Cow<'a, str>) -> Self {
         if let Some(range) = higher::Range::hir(expr) {
             let op = match range.limits {
                 ast::RangeLimits::HalfOpen => AssocOp::DotDot,
diff --git a/tests/ui/cast_lossless_bool.stderr b/tests/ui/cast_lossless_bool.stderr
index b47b35461f6..82d6b2e4b8e 100644
--- a/tests/ui/cast_lossless_bool.stderr
+++ b/tests/ui/cast_lossless_bool.stderr
@@ -1,95 +1,184 @@
-error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
+error: casts from `bool` to `u8` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:8:13
    |
 LL |     let _ = true as u8;
-   |             ^^^^^^^^^^ help: try: `u8::from(true)`
+   |             ^^^^^^^^^^
    |
+   = help: an `as` cast can become silently lossy if the types change in the future
    = note: `-D clippy::cast-lossless` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
+help: use `u8::from` instead
+   |
+LL |     let _ = u8::from(true);
+   |             ~~~~~~~~~~~~~~
 
-error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
+error: casts from `bool` to `u16` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:9:13
    |
 LL |     let _ = true as u16;
-   |             ^^^^^^^^^^^ help: try: `u16::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u16::from` instead
+   |
+LL |     let _ = u16::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `u32` is more cleanly stated with `u32::from(_)`
+error: casts from `bool` to `u32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:10:13
    |
 LL |     let _ = true as u32;
-   |             ^^^^^^^^^^^ help: try: `u32::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u32::from` instead
+   |
+LL |     let _ = u32::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `u64` is more cleanly stated with `u64::from(_)`
+error: casts from `bool` to `u64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:11:13
    |
 LL |     let _ = true as u64;
-   |             ^^^^^^^^^^^ help: try: `u64::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u64::from` instead
+   |
+LL |     let _ = u64::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `u128` is more cleanly stated with `u128::from(_)`
+error: casts from `bool` to `u128` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:12:13
    |
 LL |     let _ = true as u128;
-   |             ^^^^^^^^^^^^ help: try: `u128::from(true)`
+   |             ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u128::from` instead
+   |
+LL |     let _ = u128::from(true);
+   |             ~~~~~~~~~~~~~~~~
 
-error: casting `bool` to `usize` is more cleanly stated with `usize::from(_)`
+error: casts from `bool` to `usize` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:13:13
    |
 LL |     let _ = true as usize;
-   |             ^^^^^^^^^^^^^ help: try: `usize::from(true)`
+   |             ^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `usize::from` instead
+   |
+LL |     let _ = usize::from(true);
+   |             ~~~~~~~~~~~~~~~~~
 
-error: casting `bool` to `i8` is more cleanly stated with `i8::from(_)`
+error: casts from `bool` to `i8` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:15:13
    |
 LL |     let _ = true as i8;
-   |             ^^^^^^^^^^ help: try: `i8::from(true)`
+   |             ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i8::from` instead
+   |
+LL |     let _ = i8::from(true);
+   |             ~~~~~~~~~~~~~~
 
-error: casting `bool` to `i16` is more cleanly stated with `i16::from(_)`
+error: casts from `bool` to `i16` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:16:13
    |
 LL |     let _ = true as i16;
-   |             ^^^^^^^^^^^ help: try: `i16::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i16::from` instead
+   |
+LL |     let _ = i16::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `i32` is more cleanly stated with `i32::from(_)`
+error: casts from `bool` to `i32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:17:13
    |
 LL |     let _ = true as i32;
-   |             ^^^^^^^^^^^ help: try: `i32::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
+   |
+LL |     let _ = i32::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `i64` is more cleanly stated with `i64::from(_)`
+error: casts from `bool` to `i64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:18:13
    |
 LL |     let _ = true as i64;
-   |             ^^^^^^^^^^^ help: try: `i64::from(true)`
+   |             ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     let _ = i64::from(true);
+   |             ~~~~~~~~~~~~~~~
 
-error: casting `bool` to `i128` is more cleanly stated with `i128::from(_)`
+error: casts from `bool` to `i128` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:19:13
    |
 LL |     let _ = true as i128;
-   |             ^^^^^^^^^^^^ help: try: `i128::from(true)`
+   |             ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     let _ = i128::from(true);
+   |             ~~~~~~~~~~~~~~~~
 
-error: casting `bool` to `isize` is more cleanly stated with `isize::from(_)`
+error: casts from `bool` to `isize` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:20:13
    |
 LL |     let _ = true as isize;
-   |             ^^^^^^^^^^^^^ help: try: `isize::from(true)`
+   |             ^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `isize::from` instead
+   |
+LL |     let _ = isize::from(true);
+   |             ~~~~~~~~~~~~~~~~~
 
-error: casting `bool` to `u16` is more cleanly stated with `u16::from(_)`
+error: casts from `bool` to `u16` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:23:13
    |
 LL |     let _ = (true | false) as u16;
-   |             ^^^^^^^^^^^^^^^^^^^^^ help: try: `u16::from(true | false)`
+   |             ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u16::from` instead
+   |
+LL |     let _ = u16::from(true | false);
+   |             ~~~~~~~~~~~~~~~~~~~~~~~
 
-error: casting `bool` to `U8` is more cleanly stated with `U8::from(_)`
+error: casts from `bool` to `u8` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:25:13
    |
 LL |     let _ = true as U8;
-   |             ^^^^^^^^^^ help: try: `U8::from(true)`
+   |             ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `U8::from` instead
+   |
+LL |     let _ = U8::from(true);
+   |             ~~~~~~~~~~~~~~
 
-error: casting `bool` to `u8` is more cleanly stated with `u8::from(_)`
+error: casts from `bool` to `u8` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_bool.rs:53:13
    |
 LL |     let _ = true as u8;
-   |             ^^^^^^^^^^ help: try: `u8::from(true)`
+   |             ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u8::from` instead
+   |
+LL |     let _ = u8::from(true);
+   |             ~~~~~~~~~~~~~~
 
 error: aborting due to 15 previous errors
 
diff --git a/tests/ui/cast_lossless_float.stderr b/tests/ui/cast_lossless_float.stderr
index f2ba4e3b990..b36f8bcecf5 100644
--- a/tests/ui/cast_lossless_float.stderr
+++ b/tests/ui/cast_lossless_float.stderr
@@ -1,83 +1,160 @@
-error: casting `i8` to `f32` may become silently lossy if you later change the type
+error: casts from `i8` to `f32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:12:13
    |
 LL |     let _ = x0 as f32;
-   |             ^^^^^^^^^ help: try: `f32::from(x0)`
+   |             ^^^^^^^^^
    |
+   = help: an `as` cast can become silently lossy if the types change in the future
    = note: `-D clippy::cast-lossless` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
+help: use `f32::from` instead
+   |
+LL |     let _ = f32::from(x0);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i8` to `f64` may become silently lossy if you later change the type
+error: casts from `i8` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:13:13
    |
 LL |     let _ = x0 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x0)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x0);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i8` to `F32` may become silently lossy if you later change the type
+error: casts from `i8` to `f32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:14:13
    |
 LL |     let _ = x0 as F32;
-   |             ^^^^^^^^^ help: try: `F32::from(x0)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `F32::from` instead
+   |
+LL |     let _ = F32::from(x0);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i8` to `F64` may become silently lossy if you later change the type
+error: casts from `i8` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:15:13
    |
 LL |     let _ = x0 as F64;
-   |             ^^^^^^^^^ help: try: `F64::from(x0)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `F64::from` instead
+   |
+LL |     let _ = F64::from(x0);
+   |             ~~~~~~~~~~~~~
 
-error: casting `u8` to `f32` may become silently lossy if you later change the type
+error: casts from `u8` to `f32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:17:13
    |
 LL |     let _ = x1 as f32;
-   |             ^^^^^^^^^ help: try: `f32::from(x1)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f32::from` instead
+   |
+LL |     let _ = f32::from(x1);
+   |             ~~~~~~~~~~~~~
 
-error: casting `u8` to `f64` may become silently lossy if you later change the type
+error: casts from `u8` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:18:13
    |
 LL |     let _ = x1 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x1)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x1);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i16` to `f32` may become silently lossy if you later change the type
+error: casts from `i16` to `f32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:20:13
    |
 LL |     let _ = x2 as f32;
-   |             ^^^^^^^^^ help: try: `f32::from(x2)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f32::from` instead
+   |
+LL |     let _ = f32::from(x2);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i16` to `f64` may become silently lossy if you later change the type
+error: casts from `i16` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:21:13
    |
 LL |     let _ = x2 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x2)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x2);
+   |             ~~~~~~~~~~~~~
 
-error: casting `u16` to `f32` may become silently lossy if you later change the type
+error: casts from `u16` to `f32` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:23:13
    |
 LL |     let _ = x3 as f32;
-   |             ^^^^^^^^^ help: try: `f32::from(x3)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f32::from` instead
+   |
+LL |     let _ = f32::from(x3);
+   |             ~~~~~~~~~~~~~
 
-error: casting `u16` to `f64` may become silently lossy if you later change the type
+error: casts from `u16` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:24:13
    |
 LL |     let _ = x3 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x3)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x3);
+   |             ~~~~~~~~~~~~~
 
-error: casting `i32` to `f64` may become silently lossy if you later change the type
+error: casts from `i32` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:26:13
    |
 LL |     let _ = x4 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x4)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x4);
+   |             ~~~~~~~~~~~~~
 
-error: casting `u32` to `f64` may become silently lossy if you later change the type
+error: casts from `u32` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:28:13
    |
 LL |     let _ = x5 as f64;
-   |             ^^^^^^^^^ help: try: `f64::from(x5)`
+   |             ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(x5);
+   |             ~~~~~~~~~~~~~
 
-error: casting `f32` to `f64` may become silently lossy if you later change the type
+error: casts from `f32` to `f64` can be expressed infallibly using `From`
   --> tests/ui/cast_lossless_float.rs:31:13
    |
 LL |     let _ = 1.0f32 as f64;
-   |             ^^^^^^^^^^^^^ help: try: `f64::from(1.0f32)`
+   |             ^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `f64::from` instead
+   |
+LL |     let _ = f64::from(1.0f32);
+   |             ~~~~~~~~~~~~~~~~~
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/cast_lossless_integer.fixed b/tests/ui/cast_lossless_integer.fixed
index 291556a9774..cdb06567836 100644
--- a/tests/ui/cast_lossless_integer.fixed
+++ b/tests/ui/cast_lossless_integer.fixed
@@ -1,39 +1,93 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
-type I64 = i64;
-type U128 = u128;
+type I64Alias = i64;
 
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
-    let _ = i16::from(1i8);
-    let _ = i32::from(1i8);
-    let _ = i64::from(1i8);
-    let _ = i16::from(1u8);
-    let _ = i32::from(1u8);
-    let _ = i64::from(1u8);
-    let _ = u16::from(1u8);
-    let _ = u32::from(1u8);
-    let _ = u64::from(1u8);
-    let _ = i32::from(1i16);
-    let _ = i64::from(1i16);
-    let _ = i32::from(1u16);
-    let _ = i64::from(1u16);
-    let _ = u32::from(1u16);
-    let _ = u64::from(1u16);
-    let _ = i64::from(1i32);
-    let _ = i64::from(1u32);
-    let _ = u64::from(1u32);
+    u16::from(0u8);
+    //~^ cast_lossless
+    i16::from(0u8);
+    //~^ cast_lossless
+    u32::from(0u8);
+    //~^ cast_lossless
+    i32::from(0u8);
+    //~^ cast_lossless
+    u64::from(0u8);
+    //~^ cast_lossless
+    i64::from(0u8);
+    //~^ cast_lossless
+    u128::from(0u8);
+    //~^ cast_lossless
+    i128::from(0u8);
+    //~^ cast_lossless
+
+    u32::from(0u16);
+    //~^ cast_lossless
+    i32::from(0u16);
+    //~^ cast_lossless
+    u64::from(0u16);
+    //~^ cast_lossless
+    i64::from(0u16);
+    //~^ cast_lossless
+    u128::from(0u16);
+    //~^ cast_lossless
+    i128::from(0u16);
+    //~^ cast_lossless
+
+    u64::from(0u32);
+    //~^ cast_lossless
+    i64::from(0u32);
+    //~^ cast_lossless
+    u128::from(0u32);
+    //~^ cast_lossless
+    i128::from(0u32);
+    //~^ cast_lossless
+
+    u128::from(0u64);
+    //~^ cast_lossless
+    i128::from(0u64);
+    //~^ cast_lossless
+
+    i16::from(0i8);
+    //~^ cast_lossless
+    i32::from(0i8);
+    //~^ cast_lossless
+    i64::from(0i8);
+    //~^ cast_lossless
+    i128::from(0i8);
+    //~^ cast_lossless
+
+    i32::from(0i16);
+    //~^ cast_lossless
+    i64::from(0i16);
+    //~^ cast_lossless
+    i128::from(0i16);
+    //~^ cast_lossless
+
+    i64::from(0i32);
+    //~^ cast_lossless
+    i128::from(0i32);
+    //~^ cast_lossless
+
+    i128::from(0i64);
+    //~^ cast_lossless
 
     // Test with an expression wrapped in parens
     let _ = u16::from(1u8 + 1u8);
+    //~^ cast_lossless
 
-    let _ = I64::from(1i8);
+    let _ = I64Alias::from(1i8);
+    //~^ cast_lossless
 
-    // Do not lint if destination type is u128
-    // see https://github.com/rust-lang/rust-clippy/issues/12492
-    let _ = 1u8 as u128;
-    let _ = 1u8 as U128;
+    let _: u16 = 0u8.into();
+    //~^ cast_lossless
+    let _: i16 = (-1i8).into();
+    //~^ cast_lossless
+    let _: u16 = (1u8 + 2).into();
+    //~^ cast_lossless
+    let _: u32 = (1i8 as u16).into();
+    //~^ cast_lossless
 }
 
 // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
@@ -68,5 +122,30 @@ fn issue11458() {
     }
     let x = 10_u128;
     let _ = i32::from(sign_cast!(x, u8, i8));
+    //~^ cast_lossless
     let _ = i32::from(sign_cast!(x, u8, i8) + 1);
+    //~^ cast_lossless
+}
+
+fn issue12695() {
+    macro_rules! in_macro {
+        () => {
+            u32::from(1u8)
+            //~^ cast_lossless
+        };
+    }
+
+    let _ = in_macro!();
 }
+
+fn ty_from_macro() {
+    macro_rules! ty {
+        () => {
+            u32
+        };
+    }
+
+    let _ = <ty!()>::from(0u8);
+}
+
+const IN_CONST: u64 = 0u8 as u64;
diff --git a/tests/ui/cast_lossless_integer.rs b/tests/ui/cast_lossless_integer.rs
index a917c7a371d..1f510b1a303 100644
--- a/tests/ui/cast_lossless_integer.rs
+++ b/tests/ui/cast_lossless_integer.rs
@@ -1,39 +1,93 @@
 #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)]
 #![warn(clippy::cast_lossless)]
 
-type I64 = i64;
-type U128 = u128;
+type I64Alias = i64;
 
 fn main() {
     // Test clippy::cast_lossless with casts to integer types
-    let _ = 1i8 as i16;
-    let _ = 1i8 as i32;
-    let _ = 1i8 as i64;
-    let _ = 1u8 as i16;
-    let _ = 1u8 as i32;
-    let _ = 1u8 as i64;
-    let _ = 1u8 as u16;
-    let _ = 1u8 as u32;
-    let _ = 1u8 as u64;
-    let _ = 1i16 as i32;
-    let _ = 1i16 as i64;
-    let _ = 1u16 as i32;
-    let _ = 1u16 as i64;
-    let _ = 1u16 as u32;
-    let _ = 1u16 as u64;
-    let _ = 1i32 as i64;
-    let _ = 1u32 as i64;
-    let _ = 1u32 as u64;
+    0u8 as u16;
+    //~^ cast_lossless
+    0u8 as i16;
+    //~^ cast_lossless
+    0u8 as u32;
+    //~^ cast_lossless
+    0u8 as i32;
+    //~^ cast_lossless
+    0u8 as u64;
+    //~^ cast_lossless
+    0u8 as i64;
+    //~^ cast_lossless
+    0u8 as u128;
+    //~^ cast_lossless
+    0u8 as i128;
+    //~^ cast_lossless
+
+    0u16 as u32;
+    //~^ cast_lossless
+    0u16 as i32;
+    //~^ cast_lossless
+    0u16 as u64;
+    //~^ cast_lossless
+    0u16 as i64;
+    //~^ cast_lossless
+    0u16 as u128;
+    //~^ cast_lossless
+    0u16 as i128;
+    //~^ cast_lossless
+
+    0u32 as u64;
+    //~^ cast_lossless
+    0u32 as i64;
+    //~^ cast_lossless
+    0u32 as u128;
+    //~^ cast_lossless
+    0u32 as i128;
+    //~^ cast_lossless
+
+    0u64 as u128;
+    //~^ cast_lossless
+    0u64 as i128;
+    //~^ cast_lossless
+
+    0i8 as i16;
+    //~^ cast_lossless
+    0i8 as i32;
+    //~^ cast_lossless
+    0i8 as i64;
+    //~^ cast_lossless
+    0i8 as i128;
+    //~^ cast_lossless
+
+    0i16 as i32;
+    //~^ cast_lossless
+    0i16 as i64;
+    //~^ cast_lossless
+    0i16 as i128;
+    //~^ cast_lossless
+
+    0i32 as i64;
+    //~^ cast_lossless
+    0i32 as i128;
+    //~^ cast_lossless
+
+    0i64 as i128;
+    //~^ cast_lossless
 
     // Test with an expression wrapped in parens
     let _ = (1u8 + 1u8) as u16;
+    //~^ cast_lossless
 
-    let _ = 1i8 as I64;
+    let _ = 1i8 as I64Alias;
+    //~^ cast_lossless
 
-    // Do not lint if destination type is u128
-    // see https://github.com/rust-lang/rust-clippy/issues/12492
-    let _ = 1u8 as u128;
-    let _ = 1u8 as U128;
+    let _: u16 = 0u8 as _;
+    //~^ cast_lossless
+    let _: i16 = -1i8 as _;
+    //~^ cast_lossless
+    let _: u16 = (1u8 + 2) as _;
+    //~^ cast_lossless
+    let _: u32 = 1i8 as u16 as _;
+    //~^ cast_lossless
 }
 
 // The lint would suggest using `f64::from(input)` here but the `XX::from` function is not const,
@@ -68,5 +122,30 @@ fn issue11458() {
     }
     let x = 10_u128;
     let _ = sign_cast!(x, u8, i8) as i32;
+    //~^ cast_lossless
     let _ = (sign_cast!(x, u8, i8) + 1) as i32;
+    //~^ cast_lossless
+}
+
+fn issue12695() {
+    macro_rules! in_macro {
+        () => {
+            1u8 as u32
+            //~^ cast_lossless
+        };
+    }
+
+    let _ = in_macro!();
 }
+
+fn ty_from_macro() {
+    macro_rules! ty {
+        () => {
+            u32
+        };
+    }
+
+    let _ = 0u8 as ty!();
+}
+
+const IN_CONST: u64 = 0u8 as u64;
diff --git a/tests/ui/cast_lossless_integer.stderr b/tests/ui/cast_lossless_integer.stderr
index aaece939285..c93ecb8fb56 100644
--- a/tests/ui/cast_lossless_integer.stderr
+++ b/tests/ui/cast_lossless_integer.stderr
@@ -1,137 +1,488 @@
-error: casting `i8` to `i16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:9:13
+error: casts from `u8` to `u16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:8:5
    |
-LL |     let _ = 1i8 as i16;
-   |             ^^^^^^^^^^ help: try: `i16::from(1i8)`
+LL |     0u8 as u16;
+   |     ^^^^^^^^^^
    |
+   = help: an `as` cast can become silently lossy if the types change in the future
    = note: `-D clippy::cast-lossless` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
+help: use `u16::from` instead
+   |
+LL |     u16::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `i16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:10:5
+   |
+LL |     0u8 as i16;
+   |     ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i16::from` instead
+   |
+LL |     i16::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `u32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:12:5
+   |
+LL |     0u8 as u32;
+   |     ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u32::from` instead
+   |
+LL |     u32::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:14:5
+   |
+LL |     0u8 as i32;
+   |     ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
+   |
+LL |     i32::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `u64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:16:5
+   |
+LL |     0u8 as u64;
+   |     ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u64::from` instead
+   |
+LL |     u64::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:18:5
+   |
+LL |     0u8 as i64;
+   |     ^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     i64::from(0u8);
+   |     ~~~~~~~~~~~~~~
+
+error: casts from `u8` to `u128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:20:5
+   |
+LL |     0u8 as u128;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u128::from` instead
+   |
+LL |     u128::from(0u8);
+   |     ~~~~~~~~~~~~~~~
+
+error: casts from `u8` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:22:5
+   |
+LL |     0u8 as i128;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0u8);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:10:13
+error: casts from `u16` to `u32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:25:5
    |
-LL |     let _ = 1i8 as i32;
-   |             ^^^^^^^^^^ help: try: `i32::from(1i8)`
+LL |     0u16 as u32;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u32::from` instead
+   |
+LL |     u32::from(0u16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `i8` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:11:13
+error: casts from `u16` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:27:5
+   |
+LL |     0u16 as i32;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
    |
-LL |     let _ = 1i8 as i64;
-   |             ^^^^^^^^^^ help: try: `i64::from(1i8)`
+LL |     i32::from(0u16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u8` to `i16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:12:13
+error: casts from `u16` to `u64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:29:5
    |
-LL |     let _ = 1u8 as i16;
-   |             ^^^^^^^^^^ help: try: `i16::from(1u8)`
+LL |     0u16 as u64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u64::from` instead
+   |
+LL |     u64::from(0u16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:13:13
+error: casts from `u16` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:31:5
+   |
+LL |     0u16 as i64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
    |
-LL |     let _ = 1u8 as i32;
-   |             ^^^^^^^^^^ help: try: `i32::from(1u8)`
+LL |     i64::from(0u16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u8` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:14:13
+error: casts from `u16` to `u128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:33:5
+   |
+LL |     0u16 as u128;
+   |     ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u128::from` instead
+   |
+LL |     u128::from(0u16);
+   |     ~~~~~~~~~~~~~~~~
+
+error: casts from `u16` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:35:5
+   |
+LL |     0u16 as i128;
+   |     ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0u16);
+   |     ~~~~~~~~~~~~~~~~
+
+error: casts from `u32` to `u64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:38:5
+   |
+LL |     0u32 as u64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u64::from` instead
+   |
+LL |     u64::from(0u32);
+   |     ~~~~~~~~~~~~~~~
+
+error: casts from `u32` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:40:5
+   |
+LL |     0u32 as i64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     i64::from(0u32);
+   |     ~~~~~~~~~~~~~~~
+
+error: casts from `u32` to `u128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:42:5
+   |
+LL |     0u32 as u128;
+   |     ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u128::from` instead
+   |
+LL |     u128::from(0u32);
+   |     ~~~~~~~~~~~~~~~~
+
+error: casts from `u32` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:44:5
+   |
+LL |     0u32 as i128;
+   |     ^^^^^^^^^^^^
    |
-LL |     let _ = 1u8 as i64;
-   |             ^^^^^^^^^^ help: try: `i64::from(1u8)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0u32);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `u8` to `u16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:15:13
+error: casts from `u64` to `u128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:47:5
+   |
+LL |     0u64 as u128;
+   |     ^^^^^^^^^^^^
    |
-LL |     let _ = 1u8 as u16;
-   |             ^^^^^^^^^^ help: try: `u16::from(1u8)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u128::from` instead
+   |
+LL |     u128::from(0u64);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `u8` to `u32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:16:13
+error: casts from `u64` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:49:5
+   |
+LL |     0u64 as i128;
+   |     ^^^^^^^^^^^^
    |
-LL |     let _ = 1u8 as u32;
-   |             ^^^^^^^^^^ help: try: `u32::from(1u8)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0u64);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `u8` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:17:13
+error: casts from `i8` to `i16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:52:5
+   |
+LL |     0i8 as i16;
+   |     ^^^^^^^^^^
    |
-LL |     let _ = 1u8 as u64;
-   |             ^^^^^^^^^^ help: try: `u64::from(1u8)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i16::from` instead
+   |
+LL |     i16::from(0i8);
+   |     ~~~~~~~~~~~~~~
 
-error: casting `i16` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:18:13
+error: casts from `i8` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:54:5
+   |
+LL |     0i8 as i32;
+   |     ^^^^^^^^^^
    |
-LL |     let _ = 1i16 as i32;
-   |             ^^^^^^^^^^^ help: try: `i32::from(1i16)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
+   |
+LL |     i32::from(0i8);
+   |     ~~~~~~~~~~~~~~
 
-error: casting `i16` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:19:13
+error: casts from `i8` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:56:5
+   |
+LL |     0i8 as i64;
+   |     ^^^^^^^^^^
    |
-LL |     let _ = 1i16 as i64;
-   |             ^^^^^^^^^^^ help: try: `i64::from(1i16)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     i64::from(0i8);
+   |     ~~~~~~~~~~~~~~
 
-error: casting `u16` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:20:13
+error: casts from `i8` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:58:5
+   |
+LL |     0i8 as i128;
+   |     ^^^^^^^^^^^
    |
-LL |     let _ = 1u16 as i32;
-   |             ^^^^^^^^^^^ help: try: `i32::from(1u16)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0i8);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u16` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:21:13
+error: casts from `i16` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:61:5
+   |
+LL |     0i16 as i32;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
    |
-LL |     let _ = 1u16 as i64;
-   |             ^^^^^^^^^^^ help: try: `i64::from(1u16)`
+LL |     i32::from(0i16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u16` to `u32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:22:13
+error: casts from `i16` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:63:5
    |
-LL |     let _ = 1u16 as u32;
-   |             ^^^^^^^^^^^ help: try: `u32::from(1u16)`
+LL |     0i16 as i64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     i64::from(0i16);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u16` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:23:13
+error: casts from `i16` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:65:5
+   |
+LL |     0i16 as i128;
+   |     ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
    |
-LL |     let _ = 1u16 as u64;
-   |             ^^^^^^^^^^^ help: try: `u64::from(1u16)`
+LL |     i128::from(0i16);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `i32` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:24:13
+error: casts from `i32` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:68:5
    |
-LL |     let _ = 1i32 as i64;
-   |             ^^^^^^^^^^^ help: try: `i64::from(1i32)`
+LL |     0i32 as i64;
+   |     ^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i64::from` instead
+   |
+LL |     i64::from(0i32);
+   |     ~~~~~~~~~~~~~~~
 
-error: casting `u32` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:25:13
+error: casts from `i32` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:70:5
+   |
+LL |     0i32 as i128;
+   |     ^^^^^^^^^^^^
    |
-LL |     let _ = 1u32 as i64;
-   |             ^^^^^^^^^^^ help: try: `i64::from(1u32)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0i32);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `u32` to `u64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:26:13
+error: casts from `i64` to `i128` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:73:5
+   |
+LL |     0i64 as i128;
+   |     ^^^^^^^^^^^^
    |
-LL |     let _ = 1u32 as u64;
-   |             ^^^^^^^^^^^ help: try: `u64::from(1u32)`
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i128::from` instead
+   |
+LL |     i128::from(0i64);
+   |     ~~~~~~~~~~~~~~~~
 
-error: casting `u8` to `u16` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:29:13
+error: casts from `u8` to `u16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:77:13
    |
 LL |     let _ = (1u8 + 1u8) as u16;
-   |             ^^^^^^^^^^^^^^^^^^ help: try: `u16::from(1u8 + 1u8)`
+   |             ^^^^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `u16::from` instead
+   |
+LL |     let _ = u16::from(1u8 + 1u8);
+   |             ~~~~~~~~~~~~~~~~~~~~
+
+error: casts from `i8` to `i64` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:80:13
+   |
+LL |     let _ = 1i8 as I64Alias;
+   |             ^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `I64Alias::from` instead
+   |
+LL |     let _ = I64Alias::from(1i8);
+   |             ~~~~~~~~~~~~~~~~~~~
+
+error: casts from `u8` to `u16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:83:18
+   |
+LL |     let _: u16 = 0u8 as _;
+   |                  ^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `Into::into` instead
+   |
+LL |     let _: u16 = 0u8.into();
+   |                  ~~~~~~~~~~
 
-error: casting `i8` to `I64` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:31:13
+error: casts from `i8` to `i16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:85:18
+   |
+LL |     let _: i16 = -1i8 as _;
+   |                  ^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `Into::into` instead
    |
-LL |     let _ = 1i8 as I64;
-   |             ^^^^^^^^^^ help: try: `I64::from(1i8)`
+LL |     let _: i16 = (-1i8).into();
+   |                  ~~~~~~~~~~~~~
 
-error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:70:13
+error: casts from `u8` to `u16` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:87:18
+   |
+LL |     let _: u16 = (1u8 + 2) as _;
+   |                  ^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `Into::into` instead
+   |
+LL |     let _: u16 = (1u8 + 2).into();
+   |                  ~~~~~~~~~~~~~~~~
+
+error: casts from `u16` to `u32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:89:18
+   |
+LL |     let _: u32 = 1i8 as u16 as _;
+   |                  ^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `Into::into` instead
+   |
+LL |     let _: u32 = (1i8 as u16).into();
+   |                  ~~~~~~~~~~~~~~~~~~~
+
+error: casts from `i8` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:124:13
    |
 LL |     let _ = sign_cast!(x, u8, i8) as i32;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8))`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
+   |
+LL |     let _ = i32::from(sign_cast!(x, u8, i8));
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: casting `i8` to `i32` may become silently lossy if you later change the type
-  --> tests/ui/cast_lossless_integer.rs:71:13
+error: casts from `i8` to `i32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:126:13
    |
 LL |     let _ = (sign_cast!(x, u8, i8) + 1) as i32;
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `i32::from(sign_cast!(x, u8, i8) + 1)`
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `i32::from` instead
+   |
+LL |     let _ = i32::from(sign_cast!(x, u8, i8) + 1);
+   |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: casts from `u8` to `u32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:133:13
+   |
+LL |             1u8 as u32
+   |             ^^^^^^^^^^
+...
+LL |     let _ = in_macro!();
+   |             ----------- in this macro invocation
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+   = note: this error originates in the macro `in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use `u32::from` instead
+   |
+LL |             u32::from(1u8)
+   |
+
+error: casts from `u8` to `u32` can be expressed infallibly using `From`
+  --> tests/ui/cast_lossless_integer.rs:148:13
+   |
+LL |     let _ = 0u8 as ty!();
+   |             ^^^^^^^^^^^^
+   |
+   = help: an `as` cast can become silently lossy if the types change in the future
+help: use `<ty!()>::from` instead
+   |
+LL |     let _ = <ty!()>::from(0u8);
+   |             ~~~~~~~~~~~~~~~~~~
 
-error: aborting due to 22 previous errors
+error: aborting due to 40 previous errors
 
diff --git a/tests/ui/floating_point_powf.fixed b/tests/ui/floating_point_powf.fixed
index a44938fdf69..25f09a63795 100644
--- a/tests/ui/floating_point_powf.fixed
+++ b/tests/ui/floating_point_powf.fixed
@@ -25,6 +25,14 @@ fn main() {
     let _ = 1.5_f64.sqrt();
     let _ = 1.5_f64.powi(3);
 
+    macro_rules! m {
+        ($e:expr) => {
+            5.5 - $e
+        };
+    }
+
+    let _ = (1f32 + m!(2.0)).exp2();
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.rs b/tests/ui/floating_point_powf.rs
index 80f6c1791d7..9e9878de4ba 100644
--- a/tests/ui/floating_point_powf.rs
+++ b/tests/ui/floating_point_powf.rs
@@ -25,6 +25,14 @@ fn main() {
     let _ = 1.5_f64.powf(1.0 / 2.0);
     let _ = 1.5_f64.powf(3.0);
 
+    macro_rules! m {
+        ($e:expr) => {
+            5.5 - $e
+        };
+    }
+
+    let _ = 2f32.powf(1f32 + m!(2.0));
+
     // Cases where the lint shouldn't be applied
     let _ = x.powf(2.1);
     let _ = x.powf(-2.1);
diff --git a/tests/ui/floating_point_powf.stderr b/tests/ui/floating_point_powf.stderr
index 671383401b5..c944f14fa34 100644
--- a/tests/ui/floating_point_powf.stderr
+++ b/tests/ui/floating_point_powf.stderr
@@ -119,76 +119,82 @@ LL |     let _ = 1.5_f64.powf(3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `1.5_f64.powi(3)`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:35:13
+  --> tests/ui/floating_point_powf.rs:34:13
+   |
+LL |     let _ = 2f32.powf(1f32 + m!(2.0));
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(1f32 + m!(2.0)).exp2()`
+
+error: exponent for bases 2 and e can be computed more accurately
+  --> tests/ui/floating_point_powf.rs:43:13
    |
 LL |     let _ = 2f64.powf(x);
    |             ^^^^^^^^^^^^ help: consider using: `x.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:36:13
+  --> tests/ui/floating_point_powf.rs:44:13
    |
 LL |     let _ = 2f64.powf(3.1);
    |             ^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:37:13
+  --> tests/ui/floating_point_powf.rs:45:13
    |
 LL |     let _ = 2f64.powf(-3.1);
    |             ^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp2()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:38:13
+  --> tests/ui/floating_point_powf.rs:46:13
    |
 LL |     let _ = std::f64::consts::E.powf(x);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:39:13
+  --> tests/ui/floating_point_powf.rs:47:13
    |
 LL |     let _ = std::f64::consts::E.powf(3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `3.1f64.exp()`
 
 error: exponent for bases 2 and e can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:40:13
+  --> tests/ui/floating_point_powf.rs:48:13
    |
 LL |     let _ = std::f64::consts::E.powf(-3.1);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(-3.1f64).exp()`
 
 error: square-root of a number can be computed more efficiently and accurately
-  --> tests/ui/floating_point_powf.rs:41:13
+  --> tests/ui/floating_point_powf.rs:49:13
    |
 LL |     let _ = x.powf(1.0 / 2.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.sqrt()`
 
 error: cube-root of a number can be computed more accurately
-  --> tests/ui/floating_point_powf.rs:42:13
+  --> tests/ui/floating_point_powf.rs:50:13
    |
 LL |     let _ = x.powf(1.0 / 3.0);
    |             ^^^^^^^^^^^^^^^^^ help: consider using: `x.cbrt()`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:43:13
+  --> tests/ui/floating_point_powf.rs:51:13
    |
 LL |     let _ = x.powf(3.0);
    |             ^^^^^^^^^^^ help: consider using: `x.powi(3)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:44:13
+  --> tests/ui/floating_point_powf.rs:52:13
    |
 LL |     let _ = x.powf(-2.0);
    |             ^^^^^^^^^^^^ help: consider using: `x.powi(-2)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:45:13
+  --> tests/ui/floating_point_powf.rs:53:13
    |
 LL |     let _ = x.powf(-2_147_483_648.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(-2_147_483_648)`
 
 error: exponentiation with integer powers can be computed more efficiently
-  --> tests/ui/floating_point_powf.rs:46:13
+  --> tests/ui/floating_point_powf.rs:54:13
    |
 LL |     let _ = x.powf(2_147_483_647.0);
    |             ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `x.powi(2_147_483_647)`
 
-error: aborting due to 31 previous errors
+error: aborting due to 32 previous errors
 
diff --git a/tests/ui/types.fixed b/tests/ui/types.fixed
deleted file mode 100644
index 6f1f55f0e62..00000000000
--- a/tests/ui/types.fixed
+++ /dev/null
@@ -1,13 +0,0 @@
-#![allow(dead_code, unused_variables)]
-#![warn(clippy::cast_lossless)]
-
-// should not warn on lossy casting in constant types
-// because not supported yet
-const C: i32 = 42;
-const C_I64: i64 = C as i64;
-
-fn main() {
-    // should suggest i64::from(c)
-    let c: i32 = 42;
-    let c_i64: i64 = i64::from(c);
-}
diff --git a/tests/ui/types.rs b/tests/ui/types.rs
deleted file mode 100644
index 960aee4600c..00000000000
--- a/tests/ui/types.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-#![allow(dead_code, unused_variables)]
-#![warn(clippy::cast_lossless)]
-
-// should not warn on lossy casting in constant types
-// because not supported yet
-const C: i32 = 42;
-const C_I64: i64 = C as i64;
-
-fn main() {
-    // should suggest i64::from(c)
-    let c: i32 = 42;
-    let c_i64: i64 = c as i64;
-}
diff --git a/tests/ui/types.stderr b/tests/ui/types.stderr
deleted file mode 100644
index 02e75018129..00000000000
--- a/tests/ui/types.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error: casting `i32` to `i64` may become silently lossy if you later change the type
-  --> tests/ui/types.rs:12:22
-   |
-LL |     let c_i64: i64 = c as i64;
-   |                      ^^^^^^^^ help: try: `i64::from(c)`
-   |
-   = note: `-D clippy::cast-lossless` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::cast_lossless)]`
-
-error: aborting due to 1 previous error
-