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

@ -4170,6 +4170,7 @@ version = "0.0.0"
dependencies = [
"bitflags",
"rustc_abi",
"rustc_apfloat",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr_parsing",

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()),
},
);
}

View file

@ -13,8 +13,14 @@ macro_rules! impl_general_format {
($($t:ident)*) => {
$(impl GeneralFormat for $t {
fn already_rounded_value_should_use_exponential(&self) -> bool {
// `max_abs` rounds to infinity for `f16`. This is fine to save us from a more
// complex macro, it just means a positive-exponent `f16` will never print as
// scientific notation by default (reasonably, the max is 65504.0).
#[allow(overflowing_literals)]
let max_abs = 1e+16;
let abs = $t::abs(*self);
(abs != 0.0 && abs < 1e-4) || abs >= 1e+16
(abs != 0.0 && abs < 1e-4) || abs >= max_abs
}
})*
}

View file

@ -1,13 +1,19 @@
//@ compile-flags: -O
#![feature(f16)]
#![feature(f128)]
#![deny(overflowing_literals)]
fn main() {
let x2: i8 = --128; //~ ERROR literal out of range for `i8`
//~| WARN use of a double negation
let x = -65520.0_f16; //~ ERROR literal out of range for `f16`
let x = 65520.0_f16; //~ ERROR literal out of range for `f16`
let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
let x = -1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64`
let x = 1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64`
let x = -1.1897314953572317650857593266280075e+4932_f128; //~ ERROR literal out of range for `f128`
let x = 1.1897314953572317650857593266280075e+4932_f128; //~ ERROR literal out of range for `f128`
}

View file

@ -1,5 +1,5 @@
warning: use of a double negation
--> $DIR/lint-type-overflow2.rs:6:18
--> $DIR/lint-type-overflow2.rs:8:18
|
LL | let x2: i8 = --128;
| ^^^^^
@ -13,7 +13,7 @@ LL | let x2: i8 = -(-128);
| + +
error: literal out of range for `i8`
--> $DIR/lint-type-overflow2.rs:6:20
--> $DIR/lint-type-overflow2.rs:8:20
|
LL | let x2: i8 = --128;
| ^^^
@ -21,13 +21,29 @@ LL | let x2: i8 = --128;
= note: the literal `128` does not fit into the type `i8` whose range is `-128..=127`
= help: consider using the type `u8` instead
note: the lint level is defined here
--> $DIR/lint-type-overflow2.rs:3:9
--> $DIR/lint-type-overflow2.rs:5:9
|
LL | #![deny(overflowing_literals)]
| ^^^^^^^^^^^^^^^^^^^^
error: literal out of range for `f16`
--> $DIR/lint-type-overflow2.rs:11:14
|
LL | let x = -65520.0_f16;
| ^^^^^^^^^^^
|
= note: the literal `65520.0_f16` does not fit into the type `f16` and will be converted to `f16::INFINITY`
error: literal out of range for `f16`
--> $DIR/lint-type-overflow2.rs:12:14
|
LL | let x = 65520.0_f16;
| ^^^^^^^^^^^
|
= note: the literal `65520.0_f16` does not fit into the type `f16` and will be converted to `f16::INFINITY`
error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:9:14
--> $DIR/lint-type-overflow2.rs:13:14
|
LL | let x = -3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
@ -35,7 +51,7 @@ LL | let x = -3.40282357e+38_f32;
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
error: literal out of range for `f32`
--> $DIR/lint-type-overflow2.rs:10:14
--> $DIR/lint-type-overflow2.rs:14:14
|
LL | let x = 3.40282357e+38_f32;
| ^^^^^^^^^^^^^^^^^^
@ -43,7 +59,7 @@ LL | let x = 3.40282357e+38_f32;
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:11:14
--> $DIR/lint-type-overflow2.rs:15:14
|
LL | let x = -1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -51,12 +67,28 @@ LL | let x = -1.7976931348623159e+308_f64;
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
error: literal out of range for `f64`
--> $DIR/lint-type-overflow2.rs:12:14
--> $DIR/lint-type-overflow2.rs:16:14
|
LL | let x = 1.7976931348623159e+308_f64;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
error: aborting due to 5 previous errors; 1 warning emitted
error: literal out of range for `f128`
--> $DIR/lint-type-overflow2.rs:17:14
|
LL | let x = -1.1897314953572317650857593266280075e+4932_f128;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.1897314953572317650857593266280075e+4932_f128` does not fit into the type `f128` and will be converted to `f128::INFINITY`
error: literal out of range for `f128`
--> $DIR/lint-type-overflow2.rs:18:14
|
LL | let x = 1.1897314953572317650857593266280075e+4932_f128;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the literal `1.1897314953572317650857593266280075e+4932_f128` does not fit into the type `f128` and will be converted to `f128::INFINITY`
error: aborting due to 9 previous errors; 1 warning emitted