Skip to content

Use None::<u64> instead of 0 to denote an absence of value #14957

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions clippy_lints/src/casts/cast_lossless.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,29 +76,28 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M
return false;
}

match (cast_from.is_integral(), cast_to.is_integral()) {
(true, true) => {
match (
utils::int_ty_to_nbits(cx.tcx, cast_from),
utils::int_ty_to_nbits(cx.tcx, cast_to),
) {
(Some(from_nbits), Some(to_nbits)) => {
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
!is_isize_or_usize(cast_from)
&& !is_isize_or_usize(cast_to)
&& from_nbits < to_nbits
&& !cast_signed_to_unsigned
},

(true, false) => {
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
(Some(from_nbits), None) => {
// FIXME: handle `f16` and `f128`
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
32
} else {
64
};
!is_isize_or_usize(cast_from) && from_nbits < to_nbits
},
(false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true,
(_, _) => {
matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
},
(None, Some(_)) if cast_from.is_bool() && msrv.meets(cx, msrvs::FROM_BOOL) => true,
_ => matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)),
}
}
14 changes: 6 additions & 8 deletions clippy_lints/src/casts/cast_possible_truncation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,14 @@ pub(super) fn check(
cast_to: Ty<'_>,
cast_to_span: Span,
) {
let msg = match (cast_from.kind(), cast_to.is_integral()) {
(ty::Int(_) | ty::Uint(_), true) => {
let msg = match (cast_from.kind(), utils::int_ty_to_nbits(cx.tcx, cast_to)) {
(ty::Int(_) | ty::Uint(_), Some(to_nbits)) => {
let from_nbits = apply_reductions(
cx,
utils::int_ty_to_nbits(cast_from, cx.tcx),
utils::int_ty_to_nbits(cx.tcx, cast_from).unwrap(),
cast_expr,
cast_from.is_signed(),
);
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, ""),
Expand All @@ -121,7 +120,7 @@ pub(super) fn check(
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
},

(ty::Adt(def, _), true) if def.is_enum() => {
(ty::Adt(def, _), Some(to_nbits)) 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)
{
Expand All @@ -132,7 +131,6 @@ pub(super) fn check(
} 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.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),));
let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
Expand All @@ -157,11 +155,11 @@ pub(super) fn check(
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
},

(ty::Float(_), true) => {
(ty::Float(_), Some(_)) => {
format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
},

(ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
(ty::Float(FloatTy::F64), None) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
"casting `f64` to `f32` may truncate the value".to_string()
},

Expand Down
10 changes: 5 additions & 5 deletions clippy_lints/src/casts/cast_possible_wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,12 @@ enum EmitState {
}

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
if !(cast_from.is_integral() && cast_to.is_integral()) {
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),
) else {
return;
}
};

// emit a lint if a cast is:
// 1. unsigned to signed
Expand All @@ -35,9 +38,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
return;
}

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 = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) {
(true, true) => {
// casts between two ptr sized integers are trivially always the same size
Expand Down
16 changes: 8 additions & 8 deletions clippy_lints/src/casts/cast_precision_loss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ use rustc_middle::ty::{self, FloatTy, Ty};
use super::{CAST_PRECISION_LOSS, utils};

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
if !cast_from.is_integral() || cast_to.is_integral() {
let Some(from_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_from) else {
return;
}
};

let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) {
32
} else {
64
// FIXME: handle `f16` and `f128`
let to_nbits = match cast_to.kind() {
ty::Float(f @ (FloatTy::F32 | FloatTy::F64)) => f.bit_width(),
_ => return,
};

if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) {
Expand All @@ -29,9 +28,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
let from_nbits_str = if arch_dependent {
"64".to_owned()
} else if is_isize_or_usize(cast_from) {
// FIXME: handle 16 bits `usize` type
"32 or 64".to_owned()
} else {
utils::int_ty_to_nbits(cast_from, cx.tcx).to_string()
from_nbits.to_string()
};

span_lint(
Expand Down
14 changes: 6 additions & 8 deletions clippy_lints/src/casts/fn_to_numeric_cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,22 @@ use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty, UintTy};
use rustc_middle::ty::{self, Ty};

use super::{FN_TO_NUMERIC_CAST, utils};

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
// We only want to check casts to `ty::Uint` or `ty::Int`
match cast_to.kind() {
ty::Uint(_) | ty::Int(..) => { /* continue on */ },
_ => return,
}
let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else {
return;
};

match cast_from.kind() {
ty::FnDef(..) | ty::FnPtr(..) => {
let mut applicability = Applicability::MaybeIncorrect;
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);

if (to_nbits >= cx.tcx.data_layout.pointer_size.bits()) && (*cast_to.kind() != ty::Uint(UintTy::Usize)) {
if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() {
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
span_lint_and_sugg(
cx,
FN_TO_NUMERIC_CAST,
Expand Down
8 changes: 3 additions & 5 deletions clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@ use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils};

pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
// We only want to check casts to `ty::Uint` or `ty::Int`
match cast_to.kind() {
ty::Uint(_) | ty::Int(..) => { /* continue on */ },
_ => return,
}
let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else {
return;
};
match cast_from.kind() {
ty::FnDef(..) | ty::FnPtr(..) => {
let mut applicability = Applicability::MaybeIncorrect;
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);

let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
span_lint_and_sugg(
cx,
Expand Down
29 changes: 8 additions & 21 deletions clippy_lints/src/casts/utils.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,14 @@
use clippy_utils::ty::{EnumValue, read_explicit_enum_value};
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
pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
match typ.kind() {
ty::Int(i) => match i {
IntTy::Isize => tcx.data_layout.pointer_size.bits(),
IntTy::I8 => 8,
IntTy::I16 => 16,
IntTy::I32 => 32,
IntTy::I64 => 64,
IntTy::I128 => 128,
},
ty::Uint(i) => match i {
UintTy::Usize => tcx.data_layout.pointer_size.bits(),
UintTy::U8 => 8,
UintTy::U16 => 16,
UintTy::U32 => 32,
UintTy::U64 => 64,
UintTy::U128 => 128,
},
_ => 0,
/// Returns the size in bits of an integral type, or `None` if `ty` is not an
/// integral type.
pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> {
match ty.kind() {
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()),
ty::Int(i) => i.bit_width(),
ty::Uint(i) => i.bit_width(),
_ => None,
}
}

Expand Down