1 //! lint on C-like enums that are `repr(isize/usize)` and have values that
2 //! don't fit into an `i32`
4 use clippy_utils
::consts
::{miri_to_const, Constant}
;
5 use clippy_utils
::diagnostics
::span_lint
;
6 use rustc_hir
::{Item, ItemKind}
;
7 use rustc_lint
::{LateContext, LateLintPass}
;
8 use rustc_middle
::ty
::util
::IntTypeExt
;
9 use rustc_middle
::ty
::{self, IntTy, UintTy}
;
10 use rustc_session
::{declare_lint_pass, declare_tool_lint}
;
11 use std
::convert
::TryFrom
;
13 declare_clippy_lint
! {
15 /// Checks for C-like enumerations that are
16 /// `repr(isize/usize)` and have values that don't fit into an `i32`.
18 /// ### Why is this bad?
19 /// This will truncate the variant value on 32 bit
20 /// architectures, but works fine on 64 bit.
24 /// # #[cfg(target_pointer_width = "64")]
26 /// enum NonPortable {
27 /// X = 0x1_0000_0000,
31 pub ENUM_CLIKE_UNPORTABLE_VARIANT
,
33 "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
36 declare_lint_pass
!(UnportableVariant
=> [ENUM_CLIKE_UNPORTABLE_VARIANT
]);
38 impl<'tcx
> LateLintPass
<'tcx
> for UnportableVariant
{
39 #[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap, clippy::cast_sign_loss)]
40 fn check_item(&mut self, cx
: &LateContext
<'tcx
>, item
: &'tcx Item
<'_
>) {
41 if cx
.tcx
.data_layout
.pointer_size
.bits() != 64 {
44 if let ItemKind
::Enum(def
, _
) = &item
.kind
{
45 for var
in def
.variants
{
46 if let Some(anon_const
) = &var
.disr_expr
{
47 let def_id
= cx
.tcx
.hir().body_owner_def_id(anon_const
.body
);
48 let mut ty
= cx
.tcx
.type_of(def_id
.to_def_id());
51 .const_eval_poly(def_id
.to_def_id())
53 .map(|val
| rustc_middle
::ty
::Const
::from_value(cx
.tcx
, val
, ty
));
54 if let Some(Constant
::Int(val
)) = constant
.and_then(miri_to_const
) {
55 if let ty
::Adt(adt
, _
) = ty
.kind() {
57 ty
= adt
.repr
.discr_type().to_ty(cx
.tcx
);
61 ty
::Int(IntTy
::Isize
) => {
62 let val
= ((val
as i128
) << 64) >> 64;
63 if i32::try_from(val
).is_ok() {
67 ty
::Uint(UintTy
::Usize
) if val
> u128
::from(u32::MAX
) => {}
,
72 ENUM_CLIKE_UNPORTABLE_VARIANT
,
74 "C-like enum variant discriminant is not portable to 32-bit targets",