diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs new file mode 100644 index 00000000000..33b06b8fe7c --- /dev/null +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -0,0 +1,54 @@ +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, FloatTy, Ty}; + +use crate::utils::{is_isize_or_usize, span_lint}; + +use super::{utils, CAST_POSSIBLE_TRUNCATION}; + +pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { + let msg = match (cast_from.is_integral(), cast_to.is_integral()) { + (true, true) => { + let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx); + let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); + + let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => (to_nbits < from_nbits, ""), + (true, false) => ( + to_nbits <= 32, + if to_nbits == 32 { + " on targets with 64-bit wide pointers" + } else { + "" + }, + ), + (false, true) => (from_nbits == 64, " on targets with 32-bit wide pointers"), + }; + + if !should_lint { + return; + } + + format!( + "casting `{}` to `{}` may truncate the value{}", + cast_from, cast_to, suffix, + ) + }, + + (false, true) => { + format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) + }, + + (_, _) => { + if matches!(cast_from.kind(), &ty::Float(FloatTy::F64)) + && matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) + { + "casting `f64` to `f32` may truncate the value".to_string() + } else { + return; + } + }, + }; + + span_lint(cx, CAST_POSSIBLE_TRUNCATION, expr.span, &msg); +} diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs index 6c2464e0090..9b89b076d90 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -1,4 +1,5 @@ mod cast_lossless; +mod cast_possible_truncation; mod cast_precision_loss; mod utils; @@ -312,52 +313,18 @@ fn check_truncation_and_wrapping(cx: &LateContext<'_>, expr: &Expr<'_>, cast_fro let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed(); let from_nbits = int_ty_to_nbits(cast_from, cx.tcx); let to_nbits = int_ty_to_nbits(cast_to, cx.tcx); - let (span_truncation, suffix_truncation, span_wrap, suffix_wrap) = - match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { - (true, true) | (false, false) => ( - to_nbits < from_nbits, - ArchSuffix::None, - to_nbits == from_nbits && cast_unsigned_to_signed, - ArchSuffix::None, - ), - (true, false) => ( - to_nbits <= 32, - if to_nbits == 32 { - ArchSuffix::_64 - } else { - ArchSuffix::None - }, - to_nbits <= 32 && cast_unsigned_to_signed, - ArchSuffix::_32, - ), - (false, true) => ( - from_nbits == 64, - ArchSuffix::_32, - cast_unsigned_to_signed, - if from_nbits == 64 { - ArchSuffix::_64 - } else { - ArchSuffix::_32 - }, - ), - }; - if span_truncation { - span_lint( - cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - &format!( - "casting `{}` to `{}` may truncate the value{}", - cast_from, - cast_to, - match suffix_truncation { - ArchSuffix::_32 => arch_32_suffix, - ArchSuffix::_64 => arch_64_suffix, - ArchSuffix::None => "", - } - ), - ); - } + let (span_wrap, suffix_wrap) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) { + (true, true) | (false, false) => (to_nbits == from_nbits && cast_unsigned_to_signed, ArchSuffix::None), + (true, false) => (to_nbits <= 32 && cast_unsigned_to_signed, ArchSuffix::_32), + (false, true) => ( + cast_unsigned_to_signed, + if from_nbits == 64 { + ArchSuffix::_64 + } else { + ArchSuffix::_32 + }, + ), + }; if span_wrap { span_lint( cx, @@ -529,14 +496,9 @@ fn lint_numeric_casts<'tcx>( ) { cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to); + cast_possible_truncation::check(cx, expr, cast_from, cast_to); match (cast_from.is_integral(), cast_to.is_integral()) { (false, true) => { - span_lint( - cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - &format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to), - ); if !cast_to.is_signed() { span_lint( cx, @@ -553,16 +515,6 @@ fn lint_numeric_casts<'tcx>( check_loss_of_sign(cx, expr, cast_expr, cast_from, cast_to); check_truncation_and_wrapping(cx, expr, cast_from, cast_to); }, - (false, false) => { - if let (&ty::Float(FloatTy::F64), &ty::Float(FloatTy::F32)) = (&cast_from.kind(), &cast_to.kind()) { - span_lint( - cx, - CAST_POSSIBLE_TRUNCATION, - expr.span, - "casting `f64` to `f32` may truncate the value", - ); - } - }, (_, _) => {}, } }