Skip to content

Commit 1c65c55

Browse files
committed
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.
1 parent d10ac47 commit 1c65c55

6 files changed

Lines changed: 74 additions & 22 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4170,6 +4170,7 @@ version = "0.0.0"
41704170
dependencies = [
41714171
"bitflags",
41724172
"rustc_abi",
4173+
"rustc_apfloat",
41734174
"rustc_ast",
41744175
"rustc_ast_pretty",
41754176
"rustc_attr_parsing",

compiler/rustc_lint/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ edition = "2024"
77
# tidy-alphabetical-start
88
bitflags = "2.4.1"
99
rustc_abi = { path = "../rustc_abi" }
10+
rustc_apfloat = "0.2.0"
1011
rustc_ast = { path = "../rustc_ast" }
1112
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
1213
rustc_attr_parsing = { path = "../rustc_attr_parsing" }

compiler/rustc_lint/src/types/literal.rs

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use hir::{ExprKind, Node};
22
use rustc_abi::{Integer, Size};
3+
use rustc_apfloat::Float;
4+
use rustc_apfloat::ieee::{DoubleS, HalfS, IeeeFloat, QuadS, Semantics, SingleS};
35
use rustc_hir::{HirId, attrs};
46
use rustc_middle::ty::Ty;
57
use rustc_middle::ty::layout::IntegerExt;
68
use rustc_middle::{bug, ty};
7-
use rustc_span::Span;
9+
use rustc_span::{Span, Symbol};
810
use {rustc_ast as ast, rustc_hir as hir};
911

1012
use crate::LateContext;
@@ -383,6 +385,13 @@ fn lint_uint_literal<'tcx>(
383385
}
384386
}
385387

388+
/// `None` if `v` does not parse as the float type, otherwise indicates whether a literal rounds
389+
/// to infinity.
390+
fn float_is_infinite<S: Semantics>(v: Symbol) -> Option<bool> {
391+
let x: IeeeFloat<S> = v.as_str().parse().ok()?;
392+
Some(x.is_infinite())
393+
}
394+
386395
pub(crate) fn lint_literal<'tcx>(
387396
cx: &LateContext<'tcx>,
388397
type_limits: &TypeLimits,
@@ -405,18 +414,18 @@ pub(crate) fn lint_literal<'tcx>(
405414
lint_uint_literal(cx, hir_id, span, lit, t)
406415
}
407416
ty::Float(t) => {
408-
let (is_infinite, sym) = match lit.node {
409-
ast::LitKind::Float(v, _) => match t {
410-
// FIXME(f16_f128): add this check once `is_infinite` is reliable (ABI
411-
// issues resolved).
412-
ty::FloatTy::F16 => (Ok(false), v),
413-
ty::FloatTy::F32 => (v.as_str().parse().map(f32::is_infinite), v),
414-
ty::FloatTy::F64 => (v.as_str().parse().map(f64::is_infinite), v),
415-
ty::FloatTy::F128 => (Ok(false), v),
416-
},
417-
_ => bug!(),
417+
let ast::LitKind::Float(v, _) = lit.node else {
418+
bug!();
418419
};
419-
if is_infinite == Ok(true) {
420+
421+
let is_infinite = match t {
422+
ty::FloatTy::F16 => float_is_infinite::<HalfS>(v),
423+
ty::FloatTy::F32 => float_is_infinite::<SingleS>(v),
424+
ty::FloatTy::F64 => float_is_infinite::<DoubleS>(v),
425+
ty::FloatTy::F128 => float_is_infinite::<QuadS>(v),
426+
};
427+
428+
if is_infinite == Some(true) {
420429
cx.emit_span_lint(
421430
OVERFLOWING_LITERALS,
422431
span,
@@ -426,7 +435,7 @@ pub(crate) fn lint_literal<'tcx>(
426435
.sess()
427436
.source_map()
428437
.span_to_snippet(lit.span)
429-
.unwrap_or_else(|_| sym.to_string()),
438+
.unwrap_or_else(|_| v.to_string()),
430439
},
431440
);
432441
}

library/core/src/fmt/float.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ macro_rules! impl_general_format {
1313
($($t:ident)*) => {
1414
$(impl GeneralFormat for $t {
1515
fn already_rounded_value_should_use_exponential(&self) -> bool {
16+
#[allow(overflowing_literals)] // f16 is always within this value
17+
let max_abs = 1e+16;
18+
1619
let abs = $t::abs(*self);
17-
(abs != 0.0 && abs < 1e-4) || abs >= 1e+16
20+
(abs != 0.0 && abs < 1e-4) || abs >= max_abs
1821
}
1922
})*
2023
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
//@ compile-flags: -O
22

3+
#![feature(f16)]
4+
#![feature(f128)]
35
#![deny(overflowing_literals)]
46

57
fn main() {
68
let x2: i8 = --128; //~ ERROR literal out of range for `i8`
79
//~| WARN use of a double negation
810

11+
let x = -65520.0_f16; //~ ERROR literal out of range for `f16`
12+
let x = 65520.0_f16; //~ ERROR literal out of range for `f16`
913
let x = -3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
1014
let x = 3.40282357e+38_f32; //~ ERROR literal out of range for `f32`
1115
let x = -1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64`
1216
let x = 1.7976931348623159e+308_f64; //~ ERROR literal out of range for `f64`
17+
let x = -1.1897314953572317650857593266280075e+4932_f128; //~ ERROR literal out of range for `f128`
18+
let x = 1.1897314953572317650857593266280075e+4932_f128; //~ ERROR literal out of range for `f128`
1319
}
Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: use of a double negation
2-
--> $DIR/lint-type-overflow2.rs:6:18
2+
--> $DIR/lint-type-overflow2.rs:8:18
33
|
44
LL | let x2: i8 = --128;
55
| ^^^^^
@@ -13,50 +13,82 @@ LL | let x2: i8 = -(-128);
1313
| + +
1414

1515
error: literal out of range for `i8`
16-
--> $DIR/lint-type-overflow2.rs:6:20
16+
--> $DIR/lint-type-overflow2.rs:8:20
1717
|
1818
LL | let x2: i8 = --128;
1919
| ^^^
2020
|
2121
= note: the literal `128` does not fit into the type `i8` whose range is `-128..=127`
2222
= help: consider using the type `u8` instead
2323
note: the lint level is defined here
24-
--> $DIR/lint-type-overflow2.rs:3:9
24+
--> $DIR/lint-type-overflow2.rs:5:9
2525
|
2626
LL | #![deny(overflowing_literals)]
2727
| ^^^^^^^^^^^^^^^^^^^^
2828

29+
error: literal out of range for `f16`
30+
--> $DIR/lint-type-overflow2.rs:11:14
31+
|
32+
LL | let x = -65520.0_f16;
33+
| ^^^^^^^^^^^
34+
|
35+
= note: the literal `65520.0_f16` does not fit into the type `f16` and will be converted to `f16::INFINITY`
36+
37+
error: literal out of range for `f16`
38+
--> $DIR/lint-type-overflow2.rs:12:14
39+
|
40+
LL | let x = 65520.0_f16;
41+
| ^^^^^^^^^^^
42+
|
43+
= note: the literal `65520.0_f16` does not fit into the type `f16` and will be converted to `f16::INFINITY`
44+
2945
error: literal out of range for `f32`
30-
--> $DIR/lint-type-overflow2.rs:9:14
46+
--> $DIR/lint-type-overflow2.rs:13:14
3147
|
3248
LL | let x = -3.40282357e+38_f32;
3349
| ^^^^^^^^^^^^^^^^^^
3450
|
3551
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
3652

3753
error: literal out of range for `f32`
38-
--> $DIR/lint-type-overflow2.rs:10:14
54+
--> $DIR/lint-type-overflow2.rs:14:14
3955
|
4056
LL | let x = 3.40282357e+38_f32;
4157
| ^^^^^^^^^^^^^^^^^^
4258
|
4359
= note: the literal `3.40282357e+38_f32` does not fit into the type `f32` and will be converted to `f32::INFINITY`
4460

4561
error: literal out of range for `f64`
46-
--> $DIR/lint-type-overflow2.rs:11:14
62+
--> $DIR/lint-type-overflow2.rs:15:14
4763
|
4864
LL | let x = -1.7976931348623159e+308_f64;
4965
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
5066
|
5167
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
5268

5369
error: literal out of range for `f64`
54-
--> $DIR/lint-type-overflow2.rs:12:14
70+
--> $DIR/lint-type-overflow2.rs:16:14
5571
|
5672
LL | let x = 1.7976931348623159e+308_f64;
5773
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
5874
|
5975
= note: the literal `1.7976931348623159e+308_f64` does not fit into the type `f64` and will be converted to `f64::INFINITY`
6076

61-
error: aborting due to 5 previous errors; 1 warning emitted
77+
error: literal out of range for `f128`
78+
--> $DIR/lint-type-overflow2.rs:17:14
79+
|
80+
LL | let x = -1.1897314953572317650857593266280075e+4932_f128;
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82+
|
83+
= note: the literal `1.1897314953572317650857593266280075e+4932_f128` does not fit into the type `f128` and will be converted to `f128::INFINITY`
84+
85+
error: literal out of range for `f128`
86+
--> $DIR/lint-type-overflow2.rs:18:14
87+
|
88+
LL | let x = 1.1897314953572317650857593266280075e+4932_f128;
89+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
90+
|
91+
= note: the literal `1.1897314953572317650857593266280075e+4932_f128` does not fit into the type `f128` and will be converted to `f128::INFINITY`
92+
93+
error: aborting due to 9 previous errors; 1 warning emitted
6294

0 commit comments

Comments
 (0)