diff --git a/CHANGELOG.md b/CHANGELOG.md index f41dcce0e000..1b52a6fcd05e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3068,6 +3068,7 @@ Released 2018-09-13 [`bytes_nth`]: https://rust-lang.github.io/rust-clippy/master/index.html#bytes_nth [`cargo_common_metadata`]: https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata [`case_sensitive_file_extension_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#case_sensitive_file_extension_comparisons +[`cast_enum_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_enum_truncation [`cast_lossless`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_lossless [`cast_possible_truncation`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_truncation [`cast_possible_wrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_possible_wrap diff --git a/clippy_lints/src/casts/cast_possible_truncation.rs b/clippy_lints/src/casts/cast_possible_truncation.rs index ea74d5acbda0..9b189ea1ef8f 100644 --- a/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/clippy_lints/src/casts/cast_possible_truncation.rs @@ -1,12 +1,15 @@ use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::expr_or_init; -use clippy_utils::ty::is_isize_or_usize; +use clippy_utils::ty::{get_discriminant_value, is_isize_or_usize}; +use rustc_ast::ast; +use rustc_attr::IntType; +use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, FloatTy, Ty}; -use super::{utils, CAST_POSSIBLE_TRUNCATION}; +use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option { if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { @@ -75,8 +78,8 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b } pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) { - let msg = match (cast_from.is_integral(), cast_to.is_integral()) { - (true, true) => { + let msg = match (cast_from.kind(), cast_to.is_integral()) { + (ty::Int(_) | ty::Uint(_), true) => { let from_nbits = apply_reductions( cx, utils::int_ty_to_nbits(cast_from, cx.tcx), @@ -108,19 +111,60 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, ) }, - (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)) + (ty::Adt(def, _), true) if def.is_enum() => { + let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind + && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id) { - "casting `f64` to `f32` may truncate the value".to_string() + let i = def.variant_index_with_ctor_id(id); + let variant = &def.variants[i]; + let nbits = utils::enum_value_nbits(get_discriminant_value(cx.tcx, def, i)); + (nbits, Some(variant)) } else { + (utils::enum_ty_to_nbits(def, cx.tcx), None) + }; + let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx); + + let cast_from_ptr_size = def.repr.int.map_or(true, |ty| { + matches!( + ty, + IntType::SignedInt(ast::IntTy::Isize) | IntType::UnsignedInt(ast::UintTy::Usize) + ) + }); + let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) { + (false, false) if from_nbits > to_nbits => "", + (true, false) if from_nbits > to_nbits => "", + (false, true) if from_nbits > 64 => "", + (false, true) if from_nbits > 32 => " on targets with 32-bit wide pointers", + _ => return, + }; + + if let Some(variant) = variant { + span_lint( + cx, + CAST_ENUM_TRUNCATION, + expr.span, + &format!( + "casting `{}::{}` to `{}` will truncate the value{}", + cast_from, variant.name, cast_to, suffix, + ), + ); return; } + format!( + "casting `{}` to `{}` may truncate the value{}", + cast_from, cast_to, suffix, + ) }, + + (ty::Float(_), true) => { + format!("casting `{}` to `{}` may truncate the value", cast_from, cast_to) + }, + + (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => { + "casting `f64` to `f32` may truncate the value".to_string() + }, + + _ => 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 51d47b35454c..f2077c569c04 100644 --- a/clippy_lints/src/casts/mod.rs +++ b/clippy_lints/src/casts/mod.rs @@ -390,6 +390,25 @@ declare_clippy_lint! { "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`" } +declare_clippy_lint! { + /// ### What it does + /// Checks for casts from an enum type to an integral type which will definitely truncate the + /// value. + /// + /// ### Why is this bad? + /// The resulting integral value will not match the value of the variant it came from. + /// + /// ### Example + /// ```rust + /// enum E { X = 256 }; + /// let _ = E::X as u8; + /// ``` + #[clippy::version = "1.60.0"] + pub CAST_ENUM_TRUNCATION, + suspicious, + "casts from an enum type to an integral type which will truncate the value" +} + pub struct Casts { msrv: Option, } @@ -415,6 +434,7 @@ impl_lint_pass!(Casts => [ FN_TO_NUMERIC_CAST_WITH_TRUNCATION, CHAR_LIT_AS_U8, PTR_AS_PTR, + CAST_ENUM_TRUNCATION, ]); impl<'tcx> LateLintPass<'tcx> for Casts { @@ -445,13 +465,12 @@ impl<'tcx> LateLintPass<'tcx> for Casts { fn_to_numeric_cast_with_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_to.is_numeric() && !in_external_macro(cx.sess(), expr.span) { + cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); if cast_from.is_numeric() { - cast_possible_truncation::check(cx, expr, cast_expr, cast_from, cast_to); cast_possible_wrap::check(cx, expr, cast_from, cast_to); cast_precision_loss::check(cx, expr, cast_from, cast_to); cast_sign_loss::check(cx, expr, cast_expr, cast_from, cast_to); } - cast_lossless::check(cx, expr, cast_expr, cast_from, cast_to, &self.msrv); } } diff --git a/clippy_lints/src/casts/utils.rs b/clippy_lints/src/casts/utils.rs index 00fd0b3473b4..bbed766c47a8 100644 --- a/clippy_lints/src/casts/utils.rs +++ b/clippy_lints/src/casts/utils.rs @@ -1,4 +1,5 @@ -use rustc_middle::ty::{self, IntTy, Ty, TyCtxt, UintTy}; +use clippy_utils::ty::{read_explicit_enum_value, EnumValue}; +use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr}; /// Returns the size in bits of an integral type. /// Will return 0 if the type is not an int or uint variant @@ -23,3 +24,52 @@ pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 { _ => 0, } } + +pub(super) fn enum_value_nbits(value: EnumValue) -> u64 { + match value { + EnumValue::Unsigned(x) => 128 - x.leading_zeros(), + EnumValue::Signed(x) if x < 0 => 128 - (-(x + 1)).leading_zeros() + 1, + EnumValue::Signed(x) => 128 - x.leading_zeros(), + } + .into() +} + +pub(super) fn enum_ty_to_nbits(adt: &AdtDef, tcx: TyCtxt<'_>) -> u64 { + let mut explicit = 0i128; + let (start, end) = adt + .variants + .iter() + .fold((0, i128::MIN), |(start, end), variant| match variant.discr { + VariantDiscr::Relative(x) => match explicit.checked_add(i128::from(x)) { + Some(x) => (start, end.max(x)), + None => (i128::MIN, end), + }, + VariantDiscr::Explicit(id) => match read_explicit_enum_value(tcx, id) { + Some(EnumValue::Signed(x)) => { + explicit = x; + (start.min(x), end.max(x)) + }, + Some(EnumValue::Unsigned(x)) => match i128::try_from(x) { + Ok(x) => { + explicit = x; + (start, end.max(x)) + }, + Err(_) => (i128::MIN, end), + }, + None => (start, end), + }, + }); + + if start > end { + // No variants. + 0 + } else { + let neg_bits = if start < 0 { + 128 - (-(start + 1)).leading_zeros() + 1 + } else { + 0 + }; + let pos_bits = if end > 0 { 128 - end.leading_zeros() } else { 0 }; + neg_bits.max(pos_bits).into() + } +} diff --git a/clippy_lints/src/lib.register_all.rs b/clippy_lints/src/lib.register_all.rs index a94f6b528b47..c6f8470cd7db 100644 --- a/clippy_lints/src/lib.register_all.rs +++ b/clippy_lints/src/lib.register_all.rs @@ -23,6 +23,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CHAR_LIT_AS_U8), LintId::of(casts::FN_TO_NUMERIC_CAST), diff --git a/clippy_lints/src/lib.register_lints.rs b/clippy_lints/src/lib.register_lints.rs index df40ca463141..75ef1b0a9d51 100644 --- a/clippy_lints/src/lib.register_lints.rs +++ b/clippy_lints/src/lib.register_lints.rs @@ -67,6 +67,7 @@ store.register_lints(&[ cargo::REDUNDANT_FEATURE_NAMES, cargo::WILDCARD_DEPENDENCIES, case_sensitive_file_extension_comparisons::CASE_SENSITIVE_FILE_EXTENSION_COMPARISONS, + casts::CAST_ENUM_TRUNCATION, casts::CAST_LOSSLESS, casts::CAST_POSSIBLE_TRUNCATION, casts::CAST_POSSIBLE_WRAP, diff --git a/clippy_lints/src/lib.register_suspicious.rs b/clippy_lints/src/lib.register_suspicious.rs index da56f8008049..6a8859e19d71 100644 --- a/clippy_lints/src/lib.register_suspicious.rs +++ b/clippy_lints/src/lib.register_suspicious.rs @@ -7,6 +7,7 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(attrs::BLANKET_CLIPPY_RESTRICTION_LINTS), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), + LintId::of(casts::CAST_ENUM_TRUNCATION), LintId::of(eval_order_dependence::EVAL_ORDER_DEPENDENCE), LintId::of(float_equality_without_abs::FLOAT_EQUALITY_WITHOUT_ABS), LintId::of(formatting::SUSPICIOUS_ASSIGNMENT_FORMATTING), diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs index 93b1d178ac25..a21a87899aa1 100644 --- a/clippy_lints/src/lib.rs +++ b/clippy_lints/src/lib.rs @@ -25,6 +25,7 @@ // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_ast; extern crate rustc_ast_pretty; +extern crate rustc_attr; extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; diff --git a/clippy_utils/src/ty.rs b/clippy_utils/src/ty.rs index 958e6d1ec461..7d74b69906d9 100644 --- a/clippy_utils/src/ty.rs +++ b/clippy_utils/src/ty.rs @@ -10,12 +10,14 @@ use rustc_hir::def_id::DefId; use rustc_hir::{Expr, TyKind, Unsafety}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::LateContext; +use rustc_middle::mir::interpret::{ConstValue, Scalar}; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; use rustc_middle::ty::{ - self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, + self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy, VariantDiscr, }; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; +use rustc_target::abi::{Size, VariantIdx}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::normalize::AtExt; use std::iter; @@ -515,3 +517,58 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option for EnumValue { + type Output = Self; + fn add(self, n: u32) -> Self::Output { + match self { + Self::Unsigned(x) => Self::Unsigned(x + u128::from(n)), + Self::Signed(x) => Self::Signed(x + i128::from(n)), + } + } +} + +/// Attempts to read the given constant as though it were an an enum value. +#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)] +pub fn read_explicit_enum_value(tcx: TyCtxt<'_>, id: DefId) -> Option { + if let Ok(ConstValue::Scalar(Scalar::Int(value))) = tcx.const_eval_poly(id) { + match tcx.type_of(id).kind() { + ty::Int(_) => Some(EnumValue::Signed(match value.size().bytes() { + 1 => i128::from(value.assert_bits(Size::from_bytes(1)) as u8 as i8), + 2 => i128::from(value.assert_bits(Size::from_bytes(2)) as u16 as i16), + 4 => i128::from(value.assert_bits(Size::from_bytes(4)) as u32 as i32), + 8 => i128::from(value.assert_bits(Size::from_bytes(8)) as u64 as i64), + 16 => value.assert_bits(Size::from_bytes(16)) as i128, + _ => return None, + })), + ty::Uint(_) => Some(EnumValue::Unsigned(match value.size().bytes() { + 1 => value.assert_bits(Size::from_bytes(1)), + 2 => value.assert_bits(Size::from_bytes(2)), + 4 => value.assert_bits(Size::from_bytes(4)), + 8 => value.assert_bits(Size::from_bytes(8)), + 16 => value.assert_bits(Size::from_bytes(16)), + _ => return None, + })), + _ => None, + } + } else { + None + } +} + +/// Gets the value of the given variant. +pub fn get_discriminant_value(tcx: TyCtxt<'_>, adt: &'_ AdtDef, i: VariantIdx) -> EnumValue { + let variant = &adt.variants[i]; + match variant.discr { + VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap(), + VariantDiscr::Relative(x) => match adt.variants[(i.as_usize() - x as usize).into()].discr { + VariantDiscr::Explicit(id) => read_explicit_enum_value(tcx, id).unwrap() + x, + VariantDiscr::Relative(_) => EnumValue::Unsigned(x.into()), + }, + } +} diff --git a/tests/ui/cast.rs b/tests/ui/cast.rs index ebc1ed5587fe..2e31ad3172ee 100644 --- a/tests/ui/cast.rs +++ b/tests/ui/cast.rs @@ -1,3 +1,6 @@ +#![feature(repr128)] +#![allow(incomplete_features)] + #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, @@ -115,4 +118,137 @@ fn main() { }) as u8; 999999u64.clamp(0, 255) as u8; 999999u64.clamp(0, 256) as u8; // should still be linted + + #[derive(Clone, Copy)] + enum E1 { + A, + B, + C, + } + impl E1 { + fn test(self) { + let _ = self as u8; // Don't lint. `0..=2` fits in u8 + } + } + + #[derive(Clone, Copy)] + enum E2 { + A = 255, + B, + } + impl E2 { + fn test(self) { + let _ = self as u8; + let _ = Self::B as u8; + let _ = self as i16; // Don't lint. `255..=256` fits in i16 + let _ = Self::A as u8; // Don't lint. + } + } + + #[derive(Clone, Copy)] + enum E3 { + A = -1, + B, + C = 50, + } + impl E3 { + fn test(self) { + let _ = self as i8; // Don't lint. `-1..=50` fits in i8 + } + } + + #[derive(Clone, Copy)] + enum E4 { + A = -128, + B, + } + impl E4 { + fn test(self) { + let _ = self as i8; // Don't lint. `-128..=-127` fits in i8 + } + } + + #[derive(Clone, Copy)] + enum E5 { + A = -129, + B = 127, + } + impl E5 { + fn test(self) { + let _ = self as i8; + let _ = Self::A as i8; + let _ = self as i16; // Don't lint. `-129..=127` fits in i16 + let _ = Self::B as u8; // Don't lint. + } + } + + #[derive(Clone, Copy)] + #[repr(u32)] + enum E6 { + A = u16::MAX as u32, + B, + } + impl E6 { + fn test(self) { + let _ = self as i16; + let _ = Self::A as u16; // Don't lint. `2^16-1` fits in u16 + let _ = self as u32; // Don't lint. `2^16-1..=2^16` fits in u32 + let _ = Self::A as u16; // Don't lint. + } + } + + #[derive(Clone, Copy)] + #[repr(u64)] + enum E7 { + A = u32::MAX as u64, + B, + } + impl E7 { + fn test(self) { + let _ = self as usize; + let _ = Self::A as usize; // Don't lint. + let _ = self as u64; // Don't lint. `2^32-1..=2^32` fits in u64 + } + } + + #[derive(Clone, Copy)] + #[repr(i128)] + enum E8 { + A = i128::MIN, + B, + C = 0, + D = i128::MAX, + } + impl E8 { + fn test(self) { + let _ = self as i128; // Don't lint. `-(2^127)..=2^127-1` fits it i128 + } + } + + #[derive(Clone, Copy)] + #[repr(u128)] + enum E9 { + A, + B = u128::MAX, + } + impl E9 { + fn test(self) { + let _ = Self::A as u8; // Don't lint. + let _ = self as u128; // Don't lint. `0..=2^128-1` fits in u128 + } + } + + #[derive(Clone, Copy)] + #[repr(usize)] + enum E10 { + A, + B = u32::MAX as usize, + } + impl E10 { + fn test(self) { + let _ = self as u16; + let _ = Self::B as u32; // Don't lint. + let _ = self as u64; // Don't lint. + } + } } diff --git a/tests/ui/cast.stderr b/tests/ui/cast.stderr index edf8790cf33d..7a68c0984f14 100644 --- a/tests/ui/cast.stderr +++ b/tests/ui/cast.stderr @@ -1,5 +1,5 @@ error: casting `i32` to `f32` causes a loss of precision (`i32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:11:5 + --> $DIR/cast.rs:14:5 | LL | x0 as f32; | ^^^^^^^^^ @@ -7,37 +7,37 @@ LL | x0 as f32; = note: `-D clippy::cast-precision-loss` implied by `-D warnings` error: casting `i64` to `f32` causes a loss of precision (`i64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:13:5 + --> $DIR/cast.rs:16:5 | LL | x1 as f32; | ^^^^^^^^^ error: casting `i64` to `f64` causes a loss of precision (`i64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:14:5 + --> $DIR/cast.rs:17:5 | LL | x1 as f64; | ^^^^^^^^^ error: casting `u32` to `f32` causes a loss of precision (`u32` is 32 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:16:5 + --> $DIR/cast.rs:19:5 | LL | x2 as f32; | ^^^^^^^^^ error: casting `u64` to `f32` causes a loss of precision (`u64` is 64 bits wide, but `f32`'s mantissa is only 23 bits wide) - --> $DIR/cast.rs:18:5 + --> $DIR/cast.rs:21:5 | LL | x3 as f32; | ^^^^^^^^^ error: casting `u64` to `f64` causes a loss of precision (`u64` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) - --> $DIR/cast.rs:19:5 + --> $DIR/cast.rs:22:5 | LL | x3 as f64; | ^^^^^^^^^ error: casting `f32` to `i32` may truncate the value - --> $DIR/cast.rs:21:5 + --> $DIR/cast.rs:24:5 | LL | 1f32 as i32; | ^^^^^^^^^^^ @@ -45,13 +45,13 @@ LL | 1f32 as i32; = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` error: casting `f32` to `u32` may truncate the value - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:25:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ error: casting `f32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:22:5 + --> $DIR/cast.rs:25:5 | LL | 1f32 as u32; | ^^^^^^^^^^^ @@ -59,43 +59,43 @@ LL | 1f32 as u32; = note: `-D clippy::cast-sign-loss` implied by `-D warnings` error: casting `f64` to `f32` may truncate the value - --> $DIR/cast.rs:23:5 + --> $DIR/cast.rs:26:5 | LL | 1f64 as f32; | ^^^^^^^^^^^ error: casting `i32` to `i8` may truncate the value - --> $DIR/cast.rs:24:5 + --> $DIR/cast.rs:27:5 | LL | 1i32 as i8; | ^^^^^^^^^^ error: casting `i32` to `u8` may truncate the value - --> $DIR/cast.rs:25:5 + --> $DIR/cast.rs:28:5 | LL | 1i32 as u8; | ^^^^^^^^^^ error: casting `f64` to `isize` may truncate the value - --> $DIR/cast.rs:26:5 + --> $DIR/cast.rs:29:5 | LL | 1f64 as isize; | ^^^^^^^^^^^^^ error: casting `f64` to `usize` may truncate the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:30:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `f64` to `usize` may lose the sign of the value - --> $DIR/cast.rs:27:5 + --> $DIR/cast.rs:30:5 | LL | 1f64 as usize; | ^^^^^^^^^^^^^ error: casting `u8` to `i8` may wrap around the value - --> $DIR/cast.rs:29:5 + --> $DIR/cast.rs:32:5 | LL | 1u8 as i8; | ^^^^^^^^^ @@ -103,52 +103,96 @@ LL | 1u8 as i8; = note: `-D clippy::cast-possible-wrap` implied by `-D warnings` error: casting `u16` to `i16` may wrap around the value - --> $DIR/cast.rs:30:5 + --> $DIR/cast.rs:33:5 | LL | 1u16 as i16; | ^^^^^^^^^^^ error: casting `u32` to `i32` may wrap around the value - --> $DIR/cast.rs:31:5 + --> $DIR/cast.rs:34:5 | LL | 1u32 as i32; | ^^^^^^^^^^^ error: casting `u64` to `i64` may wrap around the value - --> $DIR/cast.rs:32:5 + --> $DIR/cast.rs:35:5 | LL | 1u64 as i64; | ^^^^^^^^^^^ error: casting `usize` to `isize` may wrap around the value - --> $DIR/cast.rs:33:5 + --> $DIR/cast.rs:36:5 | LL | 1usize as isize; | ^^^^^^^^^^^^^^^ error: casting `i32` to `u32` may lose the sign of the value - --> $DIR/cast.rs:36:5 + --> $DIR/cast.rs:39:5 | LL | -1i32 as u32; | ^^^^^^^^^^^^ error: casting `isize` to `usize` may lose the sign of the value - --> $DIR/cast.rs:38:5 + --> $DIR/cast.rs:41:5 | LL | -1isize as usize; | ^^^^^^^^^^^^^^^^ error: casting `i64` to `i8` may truncate the value - --> $DIR/cast.rs:105:5 + --> $DIR/cast.rs:108:5 | LL | (-99999999999i64).min(1) as i8; // should be linted because signed | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: casting `u64` to `u8` may truncate the value - --> $DIR/cast.rs:117:5 + --> $DIR/cast.rs:120:5 | LL | 999999u64.clamp(0, 256) as u8; // should still be linted | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 24 previous errors +error: casting `main::E2` to `u8` may truncate the value + --> $DIR/cast.rs:141:21 + | +LL | let _ = self as u8; + | ^^^^^^^^^^ + +error: casting `main::E2::B` to `u8` will truncate the value + --> $DIR/cast.rs:142:21 + | +LL | let _ = Self::B as u8; + | ^^^^^^^^^^^^^ + | + = note: `-D clippy::cast-enum-truncation` implied by `-D warnings` + +error: casting `main::E5` to `i8` may truncate the value + --> $DIR/cast.rs:178:21 + | +LL | let _ = self as i8; + | ^^^^^^^^^^ + +error: casting `main::E5::A` to `i8` will truncate the value + --> $DIR/cast.rs:179:21 + | +LL | let _ = Self::A as i8; + | ^^^^^^^^^^^^^ + +error: casting `main::E6` to `i16` may truncate the value + --> $DIR/cast.rs:193:21 + | +LL | let _ = self as i16; + | ^^^^^^^^^^^ + +error: casting `main::E7` to `usize` may truncate the value on targets with 32-bit wide pointers + --> $DIR/cast.rs:208:21 + | +LL | let _ = self as usize; + | ^^^^^^^^^^^^^ + +error: casting `main::E10` to `u16` may truncate the value + --> $DIR/cast.rs:249:21 + | +LL | let _ = self as u16; + | ^^^^^^^^^^^ + +error: aborting due to 31 previous errors