Skip to content
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
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4170,6 +4170,7 @@ version = "0.0.0"
dependencies = [
"bitflags",
"rustc_abi",
"rustc_apfloat",
"rustc_ast",
"rustc_ast_pretty",
"rustc_attr_parsing",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_lint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
35 changes: 22 additions & 13 deletions compiler/rustc_lint/src/types/literal.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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()),
},
);
}
Expand Down
8 changes: 7 additions & 1 deletion library/core/src/fmt/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

let max_abs = 1e+16;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found this comment hard to understand. I think you're saying that 1e+16 is too big too represent as an f16, which is why we get the error, so we need to suppress that with the allow. Is the abs >= max_abs comparison still valid? Does 1e+16 get rounded up to positive infinity and therefore the comparison always fails?

Some more detail is needed to make this clear.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's exactly it; abs >= 1e+16 is always true since f16 has a max of 65504.0. In context here, it just means that there isn't a f16 with a positive exponent that will get formatted in scientific notation by default.

I'll clarify this comment soon.


let abs = $t::abs(*self);
(abs != 0.0 && abs < 1e-4) || abs >= 1e+16
(abs != 0.0 && abs < 1e-4) || abs >= max_abs
}
})*
}
Expand Down
6 changes: 6 additions & 0 deletions tests/ui/lint/lint-type-overflow2.rs
Original file line number Diff line number Diff line change
@@ -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`
}
48 changes: 40 additions & 8 deletions tests/ui/lint/lint-type-overflow2.stderr
Original file line number Diff line number Diff line change
@@ -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;
| ^^^^^
Expand All @@ -13,50 +13,82 @@ 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;
| ^^^
|
= 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;
| ^^^^^^^^^^^^^^^^^^
|
= 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;
| ^^^^^^^^^^^^^^^^^^
|
= 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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= 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

Loading