lint: Use rustc_apfloat for overflowing_literals, add f16 and f128

Switch to parsing float literals for overflow checks using
`rustc_apfloat` rather than host floats. This avoids small variations in
platform support and makes it possible to start checking `f16` and
`f128` as well.

Using APFloat matches what we try to do elsewhere to avoid platform
inconsistencies.
This commit is contained in:
Trevor Gross 2026-01-22 23:34:15 -06:00
parent d10ac47c20
commit 9b15010686
6 changed files with 77 additions and 22 deletions

View file

@ -7,6 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
bitflags = "2.4.1"
rustc_abi = { path = "../rustc_abi" }
rustc_apfloat = "0.2.0"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr_parsing = { path = "../rustc_attr_parsing" }

View file

@ -1,10 +1,12 @@
use hir::{ExprKind, Node};
use rustc_abi::{Integer, Size};
use rustc_apfloat::Float;
use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, Semantics, SingleS};
use rustc_hir::{HirId, attrs};
use rustc_middle::ty::Ty;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::{bug, ty};
use rustc_span::Span;
use rustc_span::{Span, Symbol};
use {rustc_ast as ast, rustc_hir as hir};
use crate::LateContext;
@ -383,6 +385,13 @@ fn lint_uint_literal<'tcx>(
}
}
/// `None` if `v` does not parse as the float type, otherwise indicates whether a literal rounds
/// to infinity.
fn float_is_infinite<S: Semantics>(v: Symbol) -> Option<bool> {
let x: IeeeFloat<S> = v.as_str().parse().ok()?;
Some(x.is_infinite())
}
pub(crate) fn lint_literal<'tcx>(
cx: &LateContext<'tcx>,
type_limits: &TypeLimits,
@ -405,18 +414,18 @@ pub(crate) fn lint_literal<'tcx>(
lint_uint_literal(cx, hir_id, span, lit, t)
}
ty::Float(t) => {
let (is_infinite, sym) = match lit.node {
ast::LitKind::Float(v, _) => match t {
// FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
// issues resolved).
ty::FloatTy::F16 => (Ok(false), v),
ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v),
ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v),
ty::FloatTy::F128 => (Ok(false), v),
},
_ => bug!(),
let ast::LitKind::Float(v, _) = lit.node else {
bug!();
};
if is_infinite == Ok(true) {
let is_infinite = match t {
ty::FloatTy::F16 => float_is_infinite::<HalfS>(v),
ty::FloatTy::F32 => float_is_infinite::<SingleS>(v),
ty::FloatTy::F64 => float_is_infinite::<DoubleS>(v),
ty::FloatTy::F128 => float_is_infinite::<QuadS>(v),
};
if is_infinite == Some(true) {
cx.emit_span_lint(
OVERFLOWING_LITERALS,
span,
@ -426,7 +435,7 @@ pub(crate) fn lint_literal<'tcx>(
.sess()
.source_map()
.span_to_snippet(lit.span)
.unwrap_or_else(|_| sym.to_string()),
.unwrap_or_else(|_| v.to_string()),
},
);
}