Skip to content

Commit fbd6291

Browse files
committed
fix f16/f128 lints
1 parent 9b8c42c commit fbd6291

File tree

8 files changed

+134
-78
lines changed

8 files changed

+134
-78
lines changed

clippy_lints/src/casts/cast_lossless.rs

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use clippy_utils::ty::is_isize_or_usize;
77
use rustc_errors::Applicability;
88
use rustc_hir::{Expr, QPath, TyKind};
99
use rustc_lint::LateContext;
10-
use rustc_middle::ty::{self, FloatTy, Ty};
10+
use rustc_middle::ty::{self, Ty};
1111
use rustc_span::hygiene;
1212

1313
use super::{CAST_LOSSLESS, utils};
@@ -76,28 +76,42 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M
7676
return false;
7777
}
7878

79-
match (
80-
utils::int_ty_to_nbits(cx.tcx, cast_from),
81-
utils::int_ty_to_nbits(cx.tcx, cast_to),
82-
) {
83-
(Some(from_nbits), Some(to_nbits)) => {
84-
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
85-
!is_isize_or_usize(cast_from)
86-
&& !is_isize_or_usize(cast_to)
87-
&& from_nbits < to_nbits
88-
&& !cast_signed_to_unsigned
89-
},
79+
if matches!(cast_from.kind(), ty::Bool) && cast_to.is_integral() {
80+
return msrv.meets(cx, msrvs::FROM_BOOL);
81+
}
9082

91-
(Some(from_nbits), None) => {
92-
// FIXME: handle `f16` and `f128`
93-
let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
94-
32
95-
} else {
96-
64
97-
};
98-
!is_isize_or_usize(cast_from) && from_nbits < to_nbits
99-
},
100-
(None, Some(_)) if cast_from.is_bool() && msrv.meets(cx, msrvs::FROM_BOOL) => true,
101-
_ => matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)),
83+
if cast_from.is_numeric() {
84+
return match (cast_from.is_integral(), cast_to.is_integral()) {
85+
(true, true) => {
86+
let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
87+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
88+
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
89+
!is_isize_or_usize(cast_from)
90+
&& !is_isize_or_usize(cast_to)
91+
&& from_nbits < to_nbits
92+
&& !cast_signed_to_unsigned
93+
},
94+
(true, false) => {
95+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
96+
let to_nbits = utils::float_ty_to_nbits(cast_to);
97+
if from_nbits == 64 && to_nbits == 128 {
98+
// FIXME(f16_f128): https://github.com/rust-lang/rust/blob/91fad92585b2dafc52a074e502b2a6c1f093ca35/library/core/src/convert/num.rs#L171
99+
return false;
100+
}
101+
!is_isize_or_usize(cast_from) && from_nbits < to_nbits
102+
},
103+
(false, true) => false,
104+
(false, false) => {
105+
let from_nbits = utils::float_ty_to_nbits(cast_from);
106+
let to_nbits = utils::float_ty_to_nbits(cast_to);
107+
if from_nbits == 16 && to_nbits == 32 {
108+
// FIXME(f16_f128): https://github.com/rust-lang/rust/issues/123831
109+
return false;
110+
}
111+
from_nbits < to_nbits
112+
},
113+
};
102114
}
115+
116+
false
103117
}

clippy_lints/src/casts/cast_possible_truncation.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_errors::{Applicability, Diag};
99
use rustc_hir::def::{DefKind, Res};
1010
use rustc_hir::{BinOpKind, Expr, ExprKind};
1111
use rustc_lint::LateContext;
12-
use rustc_middle::ty::{self, FloatTy, Ty};
12+
use rustc_middle::ty::{self, Ty};
1313
use rustc_span::Span;
1414

1515
use super::{CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION, utils};
@@ -91,14 +91,15 @@ pub(super) fn check(
9191
cast_to: Ty<'_>,
9292
cast_to_span: Span,
9393
) {
94-
let msg = match (cast_from.kind(), utils::int_ty_to_nbits(cx.tcx, cast_to)) {
95-
(ty::Int(_) | ty::Uint(_), Some(to_nbits)) => {
94+
let msg = match (cast_from.kind(), cast_to.is_integral()) {
95+
(ty::Int(_) | ty::Uint(_), true) => {
9696
let from_nbits = apply_reductions(
9797
cx,
98-
utils::int_ty_to_nbits(cx.tcx, cast_from).unwrap(),
98+
utils::int_ty_to_nbits(cast_from, cx.tcx),
9999
cast_expr,
100100
cast_from.is_signed(),
101101
);
102+
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
102103

103104
let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
104105
(true, true) | (false, false) => (to_nbits < from_nbits, ""),
@@ -120,7 +121,7 @@ pub(super) fn check(
120121
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
121122
},
122123

123-
(ty::Adt(def, _), Some(to_nbits)) if def.is_enum() => {
124+
(ty::Adt(def, _), true) if def.is_enum() => {
124125
let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind
125126
&& let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id)
126127
{
@@ -131,6 +132,7 @@ pub(super) fn check(
131132
} else {
132133
(utils::enum_ty_to_nbits(*def, cx.tcx), None)
133134
};
135+
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
134136

135137
let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),));
136138
let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
@@ -155,12 +157,18 @@ pub(super) fn check(
155157
format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
156158
},
157159

158-
(ty::Float(_), Some(_)) => {
160+
(ty::Float(_), true) => {
159161
format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
160162
},
161163

162-
(ty::Float(FloatTy::F64), None) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
163-
"casting `f64` to `f32` may truncate the value".to_string()
164+
(ty::Float(_), false) => {
165+
let from_nbits = utils::float_ty_to_nbits(cast_from);
166+
let to_nbits = utils::float_ty_to_nbits(cast_to);
167+
if from_nbits > to_nbits {
168+
format!("casting `f{from_nbits}` to `f{to_nbits}` may truncate the value")
169+
} else {
170+
return;
171+
}
164172
},
165173

166174
_ => return,

clippy_lints/src/casts/cast_possible_wrap.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,9 @@ enum EmitState {
1717
}
1818

1919
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
20-
let (Some(from_nbits), Some(to_nbits)) = (
21-
utils::int_ty_to_nbits(cx.tcx, cast_from),
22-
utils::int_ty_to_nbits(cx.tcx, cast_to),
23-
) else {
20+
if !(cast_from.is_integral() && cast_to.is_integral()) {
2421
return;
25-
};
22+
}
2623

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

38+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
39+
let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
40+
4141
let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) {
4242
(true, true) => {
4343
// casts between two ptr sized integers are trivially always the same size

clippy_lints/src/casts/cast_precision_loss.rs

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,25 @@ use clippy_utils::diagnostics::span_lint;
22
use clippy_utils::ty::is_isize_or_usize;
33
use rustc_hir::Expr;
44
use rustc_lint::LateContext;
5-
use rustc_middle::ty::{self, FloatTy, Ty};
5+
use rustc_middle::ty::Ty;
66

77
use super::{CAST_PRECISION_LOSS, utils};
88

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

14-
// FIXME: handle `f16` and `f128`
15-
let to_nbits = match cast_to.kind() {
16-
ty::Float(f @ (FloatTy::F32 | FloatTy::F64)) => f.bit_width(),
17-
_ => return,
18-
};
14+
let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
15+
let to_nbits = utils::float_ty_to_nbits(cast_to);
1916

2017
if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) {
2118
return;
2219
}
2320

24-
let cast_to_f64 = to_nbits == 64;
25-
let mantissa_nbits = if cast_to_f64 { 52 } else { 23 };
26-
let arch_dependent = is_isize_or_usize(cast_from) && cast_to_f64;
21+
let mantissa_nbits = utils::float_ty_to_mantissa_nbits(cast_to);
22+
23+
let arch_dependent = is_isize_or_usize(cast_from) && to_nbits == 64;
2724
let arch_dependent_str = "on targets with 64-bit wide pointers ";
2825
let from_nbits_str = if arch_dependent {
2926
"64".to_owned()
@@ -42,7 +39,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
4239
"casting `{0}` to `{1}` causes a loss of precision {2}(`{0}` is {3} bits wide, \
4340
but `{1}`'s mantissa is only {4} bits wide)",
4441
cast_from,
45-
if cast_to_f64 { "f64" } else { "f32" },
42+
format!("f{to_nbits}"),
4643
if arch_dependent { arch_dependent_str } else { "" },
4744
from_nbits_str,
4845
mantissa_nbits

clippy_lints/src/casts/fn_to_numeric_cast.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@ use super::{FN_TO_NUMERIC_CAST, utils};
99

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

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

20-
if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() {
21-
let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
23+
if (to_nbits >= cx.tcx.data_layout.pointer_size.bits()) && !cast_to.is_usize() {
2224
span_lint_and_sugg(
2325
cx,
2426
FN_TO_NUMERIC_CAST,

clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils};
99

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

2023
if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
2124
span_lint_and_sugg(

clippy_lints/src/casts/unnecessary_cast.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::casts::utils;
12
use clippy_utils::diagnostics::span_lint_and_sugg;
23
use clippy_utils::numeric_literal::NumericLiteral;
34
use clippy_utils::source::{SpanRangeExt, snippet_opt};
@@ -9,7 +10,7 @@ use rustc_hir::def::{DefKind, Res};
910
use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
1011
use rustc_lint::{LateContext, LintContext};
1112
use rustc_middle::ty::adjustment::Adjust;
12-
use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
13+
use rustc_middle::ty::{self, Ty};
1314
use rustc_span::{Symbol, sym};
1415
use std::ops::ControlFlow;
1516

@@ -108,8 +109,8 @@ pub(super) fn check<'tcx>(
108109
&& let Some(src) = cast_expr.span.get_source_text(cx)
109110
&& cast_to.is_floating_point()
110111
&& let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
111-
&& let from_nbits = 128 - n.get().leading_zeros()
112-
&& let to_nbits = fp_ty_mantissa_nbits(cast_to)
112+
&& let from_nbits = 128 - u64::from(n.get().leading_zeros())
113+
&& let to_nbits = utils::float_ty_to_mantissa_nbits(cast_to)
113114
&& from_nbits != 0
114115
&& to_nbits != 0
115116
&& from_nbits <= to_nbits
@@ -257,16 +258,6 @@ fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> {
257258
}
258259
}
259260

260-
/// Returns the mantissa bits wide of a fp type.
261-
/// Will return 0 if the type is not a fp
262-
fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
263-
match typ.kind() {
264-
ty::Float(FloatTy::F32) => 23,
265-
ty::Float(FloatTy::F64) | ty::Infer(InferTy::FloatVar(_)) => 52,
266-
_ => 0,
267-
}
268-
}
269-
270261
/// Finds whether an `Expr` returns a type alias.
271262
///
272263
/// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark,

clippy_lints/src/casts/utils.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,55 @@
11
use clippy_utils::ty::{EnumValue, read_explicit_enum_value};
2-
use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
2+
use rustc_middle::ty::{self, AdtDef, FloatTy, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
33

4-
/// Returns the size in bits of an integral type, or `None` if `ty` is not an
5-
/// integral type.
6-
pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> {
7-
match ty.kind() {
8-
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()),
9-
ty::Int(i) => i.bit_width(),
10-
ty::Uint(i) => i.bit_width(),
11-
_ => None,
4+
/// Returns the size in bits of an integral type.
5+
/// Panics if the type is not an int or uint variant
6+
pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
7+
match typ.kind() {
8+
ty::Int(i) => match i {
9+
IntTy::Isize => tcx.data_layout.pointer_size.bits(),
10+
IntTy::I8 => 8,
11+
IntTy::I16 => 16,
12+
IntTy::I32 => 32,
13+
IntTy::I64 => 64,
14+
IntTy::I128 => 128,
15+
},
16+
ty::Uint(i) => match i {
17+
UintTy::Usize => tcx.data_layout.pointer_size.bits(),
18+
UintTy::U8 => 8,
19+
UintTy::U16 => 16,
20+
UintTy::U32 => 32,
21+
UintTy::U64 => 64,
22+
UintTy::U128 => 128,
23+
},
24+
_ => unreachable!(),
25+
}
26+
}
27+
28+
/// Returns the size in bits of an floating type.
29+
/// Panics if the type is not an float variant
30+
pub(super) fn float_ty_to_nbits(typ: Ty<'_>) -> u64 {
31+
match typ.kind() {
32+
ty::Float(i) => match i {
33+
FloatTy::F16 => 16,
34+
FloatTy::F32 => 32,
35+
FloatTy::F64 => 64,
36+
FloatTy::F128 => 128,
37+
},
38+
_ => unreachable!(),
39+
}
40+
}
41+
42+
/// Returns the mantissa size in bits of an floating type.
43+
/// Panics if the type is not an float variant
44+
pub(super) fn float_ty_to_mantissa_nbits(typ: Ty<'_>) -> u64 {
45+
match typ.kind() {
46+
ty::Float(i) => match i {
47+
FloatTy::F16 => 10,
48+
FloatTy::F32 => 23,
49+
FloatTy::F64 => 52,
50+
FloatTy::F128 => 112,
51+
},
52+
_ => unreachable!(),
1253
}
1354
}
1455

0 commit comments

Comments
 (0)