diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index 9e0eaef596420..451dd7e1dda76 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -342,7 +342,7 @@ pub trait Visitor<'v>: Sized { fn visit_pat_expr(&mut self, expr: &'v PatExpr<'v>) -> Self::Result { walk_pat_expr(self, expr) } - fn visit_lit(&mut self, _hir_id: HirId, _lit: Lit, _negated: bool) -> Self::Result { + fn visit_lit(&mut self, _hir_id: HirId, _lit: Lit, _is_negated_pat: bool) -> Self::Result { Self::Result::output() } fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 1f37ac2d3e0bc..0be242ffa9336 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -151,8 +151,8 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas hir_visit::walk_pat(self, p); } - fn visit_lit(&mut self, hir_id: HirId, lit: hir::Lit, negated: bool) { - lint_callback!(self, check_lit, hir_id, lit, negated); + fn visit_lit(&mut self, hir_id: HirId, lit: hir::Lit, is_negated_pat: bool) { + lint_callback!(self, check_lit, hir_id, lit, is_negated_pat); } fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) { diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index 5c101048b8010..cd9e08bf9cb53 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -21,7 +21,7 @@ macro_rules! late_lint_methods { fn check_stmt(a: &'tcx rustc_hir::Stmt<'tcx>); fn check_arm(a: &'tcx rustc_hir::Arm<'tcx>); fn check_pat(a: &'tcx rustc_hir::Pat<'tcx>); - fn check_lit(hir_id: rustc_hir::HirId, a: rustc_hir::Lit, negated: bool); + fn check_lit(hir_id: rustc_hir::HirId, a: rustc_hir::Lit, is_negated_pat: bool); fn check_expr(a: &'tcx rustc_hir::Expr<'tcx>); fn check_expr_post(a: &'tcx rustc_hir::Expr<'tcx>); fn check_ty(a: &'tcx rustc_hir::Ty<'tcx, rustc_hir::AmbigArg>); diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index a12e347284f7c..9a93d63bd96a6 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -194,10 +194,15 @@ declare_lint! { #[derive(Copy, Clone, Default)] pub(crate) struct TypeLimits { - /// Id of the last visited negated expression - negated_expr_id: Option, - /// Span of the last visited negated expression - negated_expr_span: Option, + last_visited_negation: Option, +} + +#[derive(Copy, Clone)] +struct NegationInfo { + /// A negation expression (a `rustc_hir::ExprKind::Unary`) + negation_span: Span, + /// The operand of the negation expression. + negated_id: hir::HirId, } impl_lint_pass!(TypeLimits => [ @@ -210,7 +215,7 @@ impl_lint_pass!(TypeLimits => [ impl TypeLimits { pub(crate) fn new() -> TypeLimits { - TypeLimits { negated_expr_id: None, negated_expr_span: None } + TypeLimits { last_visited_negation: None } } } @@ -539,22 +544,32 @@ fn lint_fn_pointer<'tcx>( } impl<'tcx> LateLintPass<'tcx> for TypeLimits { - fn check_lit(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, lit: hir::Lit, negated: bool) { - if negated { - self.negated_expr_id = Some(hir_id); - self.negated_expr_span = Some(lit.span); - } - lint_literal(cx, self, hir_id, lit.span, &lit, negated); + fn check_lit( + &mut self, + cx: &LateContext<'tcx>, + hir_id: HirId, + lit: hir::Lit, + is_negated_pat: bool, + ) { + let surrounding_negation = if is_negated_pat { + // In this case, lit.span refers to a `rustc_hir::hir::PatExprKind::Lit`, + // which includes the minus sign in front. + Some(lit.span) + } else if let Some(negation_info) = self.last_visited_negation + && negation_info.negated_id == hir_id + { + Some(negation_info.negation_span) + } else { + None + }; + lint_literal(cx, hir_id, lit.span, &lit, surrounding_negation); } fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) { match e.kind { hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - // Propagate negation, if the negation itself isn't negated - if self.negated_expr_id != Some(e.hir_id) { - self.negated_expr_id = Some(expr.hir_id); - self.negated_expr_span = Some(e.span); - } + self.last_visited_negation = + Some(NegationInfo { negation_span: e.span, negated_id: expr.hir_id }); } hir::ExprKind::Binary(binop, ref l, ref r) => { if is_comparison(binop.node) { diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs index 45d79fec75ae9..bed26ee6f3d25 100644 --- a/compiler/rustc_lint/src/types/literal.rs +++ b/compiler/rustc_lint/src/types/literal.rs @@ -17,7 +17,7 @@ use crate::lints::{ OverflowingBinHexSub, OverflowingInt, OverflowingIntHelp, OverflowingLiteral, OverflowingUInt, RangeEndpointOutOfRange, SurrogateCharCast, TooLargeCharCast, UseInclusiveRange, }; -use crate::types::{OVERFLOWING_LITERALS, TypeLimits}; +use crate::types::OVERFLOWING_LITERALS; /// Attempts to special-case the overflowing literal lint when it occurs as a range endpoint (`expr..MAX+1`). /// Returns `true` iff the lint was emitted. @@ -260,17 +260,17 @@ fn literal_to_i128(val: u128, negative: bool) -> Option { fn lint_int_literal<'tcx>( cx: &LateContext<'tcx>, - type_limits: &TypeLimits, hir_id: HirId, span: Span, lit: &hir::Lit, t: ty::IntTy, v: u128, + surrounding_negation: Option, ) { let int_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = int_ty_range(int_type); let max = max as u128; - let negative = type_limits.negated_expr_id == Some(hir_id); + let negative = surrounding_negation.is_some(); // Detect literal value out of range [min, max] inclusive // avoiding use of -min to prevent overflow/panic @@ -294,7 +294,7 @@ fn lint_int_literal<'tcx>( return; } - let span = if negative { type_limits.negated_expr_span.unwrap() } else { span }; + let span = surrounding_negation.unwrap_or(span); let lit = cx .sess() .source_map() @@ -400,23 +400,22 @@ fn float_is_infinite(v: Symbol) -> Option { pub(crate) fn lint_literal<'tcx>( cx: &LateContext<'tcx>, - type_limits: &TypeLimits, hir_id: HirId, span: Span, lit: &hir::Lit, - negated: bool, + surrounding_negation: Option, ) { match *cx.typeck_results().node_type(hir_id).kind() { ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { - lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get()) + lint_int_literal(cx, hir_id, span, lit, t, v.get(), surrounding_negation) } _ => bug!(), }; } ty::Uint(t) => { - assert!(!negated); + assert!(surrounding_negation.is_none()); lint_uint_literal(cx, hir_id, span, lit, t) } ty::Float(t) => { diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs index 2ea921e5d4614..b7b9befd10b0b 100644 --- a/src/tools/clippy/clippy_lints/src/approx_const.rs +++ b/src/tools/clippy/clippy_lints/src/approx_const.rs @@ -75,7 +75,7 @@ impl ApproxConstant { } impl LateLintPass<'_> for ApproxConstant { - fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _negated: bool) { + fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: Lit, _is_negated_pat: bool) { match lit.node { LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty { FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"), diff --git a/tests/ui/lint/lint-type-overflow2.rs b/tests/ui/lint/lint-type-overflow2.rs index d3ff02aeb722f..622208b33cb08 100644 --- a/tests/ui/lint/lint-type-overflow2.rs +++ b/tests/ui/lint/lint-type-overflow2.rs @@ -5,9 +5,6 @@ #![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` diff --git a/tests/ui/lint/lint-type-overflow2.stderr b/tests/ui/lint/lint-type-overflow2.stderr index c045d243753e4..f8c0c6d4ef3a1 100644 --- a/tests/ui/lint/lint-type-overflow2.stderr +++ b/tests/ui/lint/lint-type-overflow2.stderr @@ -1,25 +1,10 @@ -warning: use of a double negation - --> $DIR/lint-type-overflow2.rs:8:18 - | -LL | let x2: i8 = --128; - | ^^^^^ - | - = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages - = note: use `-= 1` if you meant to decrement the value - = note: `#[warn(double_negations)]` on by default -help: add parentheses for clarity - | -LL | let x2: i8 = -(-128); - | + + - -error: literal out of range for `i8` - --> $DIR/lint-type-overflow2.rs:8:20 +error: literal out of range for `f16` + --> $DIR/lint-type-overflow2.rs:8:14 | -LL | let x2: i8 = --128; - | ^^^ +LL | let x = -65520.0_f16; + | ^^^^^^^^^^^ | - = 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 literal `65520.0_f16` does not fit into the type `f16` and will be converted to `f16::INFINITY` note: the lint level is defined here --> $DIR/lint-type-overflow2.rs:5:9 | @@ -27,15 +12,7 @@ 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 + --> $DIR/lint-type-overflow2.rs:9:14 | LL | let x = 65520.0_f16; | ^^^^^^^^^^^ @@ -43,7 +20,7 @@ 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:13:14 + --> $DIR/lint-type-overflow2.rs:10:14 | LL | let x = -3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ @@ -51,7 +28,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:14:14 + --> $DIR/lint-type-overflow2.rs:11:14 | LL | let x = 3.40282357e+38_f32; | ^^^^^^^^^^^^^^^^^^ @@ -59,7 +36,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:15:14 + --> $DIR/lint-type-overflow2.rs:12:14 | LL | let x = -1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -67,7 +44,7 @@ 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:16:14 + --> $DIR/lint-type-overflow2.rs:13:14 | LL | let x = 1.7976931348623159e+308_f64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -75,7 +52,7 @@ 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 `f128` - --> $DIR/lint-type-overflow2.rs:17:14 + --> $DIR/lint-type-overflow2.rs:14:14 | LL | let x = -1.1897314953572317650857593266280075e+4932_f128; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -83,12 +60,12 @@ 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 + --> $DIR/lint-type-overflow2.rs:15: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 +error: aborting due to 8 previous errors diff --git a/tests/ui/lint/lint-type-overflow3.rs b/tests/ui/lint/lint-type-overflow3.rs new file mode 100644 index 0000000000000..d51f94fae696c --- /dev/null +++ b/tests/ui/lint/lint-type-overflow3.rs @@ -0,0 +1,21 @@ +//@ compile-flags: --emit link +// The above flags (which are passed in `cargo build`) are required for +// the `arithmetic_overflow` lint to function. + +#![deny(overflowing_literals, arithmetic_overflow)] + +fn main() { + let x: i8 = 128; + //~^ ERROR literal out of range for `i8` + let x: i8 = -128; + let x: i8 = --128; //~ WARN use of a double negation + //~^ ERROR this arithmetic operation will overflow + let x: i8 = ---128; //~ WARN use of a double negation + //~^ ERROR this arithmetic operation will overflow + let x: i8 = ----128; //~ WARN use of a double negation + //~^ ERROR this arithmetic operation will overflow + let x: i8 = -----128; //~ WARN use of a double negation + //~^ ERROR this arithmetic operation will overflow + let x: i8 = ------128; //~ WARN use of a double negation + //~^ ERROR this arithmetic operation will overflow +} diff --git a/tests/ui/lint/lint-type-overflow3.stderr b/tests/ui/lint/lint-type-overflow3.stderr new file mode 100644 index 0000000000000..3dc7fbec1eebf --- /dev/null +++ b/tests/ui/lint/lint-type-overflow3.stderr @@ -0,0 +1,118 @@ +warning: use of a double negation + --> $DIR/lint-type-overflow3.rs:11:17 + | +LL | let x: i8 = --128; + | ^^^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value + = note: `#[warn(double_negations)]` on by default +help: add parentheses for clarity + | +LL | let x: i8 = -(-128); + | + + + +warning: use of a double negation + --> $DIR/lint-type-overflow3.rs:13:18 + | +LL | let x: i8 = ---128; + | ^^^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value +help: add parentheses for clarity + | +LL | let x: i8 = --(-128); + | + + + +warning: use of a double negation + --> $DIR/lint-type-overflow3.rs:15:19 + | +LL | let x: i8 = ----128; + | ^^^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value +help: add parentheses for clarity + | +LL | let x: i8 = ---(-128); + | + + + +warning: use of a double negation + --> $DIR/lint-type-overflow3.rs:17:20 + | +LL | let x: i8 = -----128; + | ^^^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value +help: add parentheses for clarity + | +LL | let x: i8 = ----(-128); + | + + + +warning: use of a double negation + --> $DIR/lint-type-overflow3.rs:19:21 + | +LL | let x: i8 = ------128; + | ^^^^^ + | + = note: the prefix `--` could be misinterpreted as a decrement operator which exists in other languages + = note: use `-= 1` if you meant to decrement the value +help: add parentheses for clarity + | +LL | let x: i8 = -----(-128); + | + + + +error: this arithmetic operation will overflow + --> $DIR/lint-type-overflow3.rs:11:17 + | +LL | let x: i8 = --128; + | ^^^^^ attempt to negate `i8::MIN`, which would overflow + | +note: the lint level is defined here + --> $DIR/lint-type-overflow3.rs:5:31 + | +LL | #![deny(overflowing_literals, arithmetic_overflow)] + | ^^^^^^^^^^^^^^^^^^^ + +error: this arithmetic operation will overflow + --> $DIR/lint-type-overflow3.rs:13:18 + | +LL | let x: i8 = ---128; + | ^^^^^ attempt to negate `i8::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-type-overflow3.rs:15:19 + | +LL | let x: i8 = ----128; + | ^^^^^ attempt to negate `i8::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-type-overflow3.rs:17:20 + | +LL | let x: i8 = -----128; + | ^^^^^ attempt to negate `i8::MIN`, which would overflow + +error: this arithmetic operation will overflow + --> $DIR/lint-type-overflow3.rs:19:21 + | +LL | let x: i8 = ------128; + | ^^^^^ attempt to negate `i8::MIN`, which would overflow + +error: literal out of range for `i8` + --> $DIR/lint-type-overflow3.rs:8:17 + | +LL | let x: 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-overflow3.rs:5:9 + | +LL | #![deny(overflowing_literals, arithmetic_overflow)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors; 5 warnings emitted +