From d1231eabf9fb80aed4c9645a2d38883faa18bab5 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Fri, 31 Jan 2025 17:19:19 +0000
Subject: [PATCH 1/3] Add regression test

---
 tests/ui/pattern/overflowing-literals.rs     | 20 ++++++++++++++
 tests/ui/pattern/overflowing-literals.stderr | 29 ++++++++++++++++++++
 2 files changed, 49 insertions(+)
 create mode 100644 tests/ui/pattern/overflowing-literals.rs
 create mode 100644 tests/ui/pattern/overflowing-literals.stderr

diff --git a/tests/ui/pattern/overflowing-literals.rs b/tests/ui/pattern/overflowing-literals.rs
new file mode 100644
index 0000000000000..ab92283ff67c6
--- /dev/null
+++ b/tests/ui/pattern/overflowing-literals.rs
@@ -0,0 +1,20 @@
+//! Check that overflowing literals are in patterns are rejected
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+type TooBig = pattern_type!(u8 is 500..);
+//~^ ERROR:  literal out of range for `u8`
+type TooSmall = pattern_type!(i8 is -500..);
+//~^ ERROR:  literal out of range for `i8`
+type TooBigSigned = pattern_type!(i8 is 200..);
+//~^ ERROR:  literal out of range for `i8`
+
+fn main() {
+    match 5_u8 {
+        500 => {}
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/overflowing-literals.stderr b/tests/ui/pattern/overflowing-literals.stderr
new file mode 100644
index 0000000000000..b6609303cb7df
--- /dev/null
+++ b/tests/ui/pattern/overflowing-literals.stderr
@@ -0,0 +1,29 @@
+error: literal out of range for `u8`
+  --> $DIR/overflowing-literals.rs:8:35
+   |
+LL | type TooBig = pattern_type!(u8 is 500..);
+   |                                   ^^^
+   |
+   = note: the literal `500` does not fit into the type `u8` whose range is `0..=255`
+   = note: `#[deny(overflowing_literals)]` on by default
+
+error: literal out of range for `i8`
+  --> $DIR/overflowing-literals.rs:10:37
+   |
+LL | type TooSmall = pattern_type!(i8 is -500..);
+   |                                     ^^^^
+   |
+   = note: the literal `-500` does not fit into the type `i8` whose range is `-128..=127`
+   = help: consider using the type `i16` instead
+
+error: literal out of range for `i8`
+  --> $DIR/overflowing-literals.rs:12:41
+   |
+LL | type TooBigSigned = pattern_type!(i8 is 200..);
+   |                                         ^^^
+   |
+   = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127`
+   = help: consider using the type `u8` instead
+
+error: aborting due to 3 previous errors
+

From 9f5473f7ad7b0bc9a100d82a39142f714a2b48f7 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Sat, 1 Feb 2025 11:56:03 +0000
Subject: [PATCH 2/3] Avoid passing around an `Expr` that is only needed for
 its HirId and its Span

---
 compiler/rustc_lint/src/types.rs         |  2 +-
 compiler/rustc_lint/src/types/literal.rs | 69 +++++++++++++-----------
 2 files changed, 40 insertions(+), 31 deletions(-)

diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 0060f33888ebd..3c8a7ada4bf12 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -557,7 +557,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     }
                 }
             }
-            hir::ExprKind::Lit(lit) => lint_literal(cx, self, e, lit),
+            hir::ExprKind::Lit(lit) => lint_literal(cx, self, e.hir_id, e.span, lit),
             hir::ExprKind::Call(path, [l, r])
                 if let ExprKind::Path(ref qpath) = path.kind
                     && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index 4b5163522f866..7d49b260acca8 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -1,8 +1,10 @@
 use hir::{ExprKind, Node, is_range_literal};
 use rustc_abi::{Integer, Size};
+use rustc_hir::HirId;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::{bug, ty};
+use rustc_span::Span;
 use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
 
 use crate::LateContext;
@@ -21,21 +23,22 @@ fn lint_overflowing_range_endpoint<'tcx>(
     lit: &hir::Lit,
     lit_val: u128,
     max: u128,
-    expr: &'tcx hir::Expr<'tcx>,
+    hir_id: HirId,
+    lit_span: Span,
     ty: &str,
 ) -> bool {
     // Look past casts to support cases like `0..256 as u8`
-    let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id)
+    let (hir_id, span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(hir_id)
         && let ExprKind::Cast(_, _) = par_expr.kind
     {
-        (par_expr, expr.span)
+        (par_expr.hir_id, par_expr.span)
     } else {
-        (expr, expr.span)
+        (hir_id, lit_span)
     };
 
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
-    let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false };
+    let Node::ExprField(field) = cx.tcx.parent_hir_node(hir_id) else { return false };
     let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
     if !is_range_literal(struct_expr) {
         return false;
@@ -45,7 +48,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if !(end.expr.hir_id == expr.hir_id && lit_val - 1 == max) {
+    if !(end.expr.hir_id == hir_id && lit_val - 1 == max) {
         return false;
     };
 
@@ -57,7 +60,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
         _ => bug!(),
     };
 
-    let sub_sugg = if expr.span.lo() == lit_span.lo() {
+    let sub_sugg = if span.lo() == lit_span.lo() {
         let Ok(start) = cx.sess().source_map().span_to_snippet(start.span) else { return false };
         UseInclusiveRange::WithoutParen {
             sugg: struct_expr.span.shrink_to_lo().to(lit_span.shrink_to_hi()),
@@ -67,7 +70,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
         }
     } else {
         UseInclusiveRange::WithParen {
-            eq_sugg: expr.span.shrink_to_lo(),
+            eq_sugg: span.shrink_to_lo(),
             lit_sugg: lit_span,
             literal: lit_val - 1,
             suffix,
@@ -125,7 +128,8 @@ fn get_bin_hex_repr(cx: &LateContext<'_>, lit: &hir::Lit) -> Option<String> {
 
 fn report_bin_hex_error(
     cx: &LateContext<'_>,
-    expr: &hir::Expr<'_>,
+    hir_id: HirId,
+    span: Span,
     ty: attr::IntType,
     size: Size,
     repr_str: String,
@@ -144,11 +148,11 @@ fn report_bin_hex_error(
     };
     let sign =
         if negative { OverflowingBinHexSign::Negative } else { OverflowingBinHexSign::Positive };
-    let sub = get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative).map(
+    let sub = get_type_suggestion(cx.typeck_results().node_type(hir_id), val, negative).map(
         |suggestion_ty| {
             if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
                 let (sans_suffix, _) = repr_str.split_at(pos);
-                OverflowingBinHexSub::Suggestion { span: expr.span, suggestion_ty, sans_suffix }
+                OverflowingBinHexSub::Suggestion { span, suggestion_ty, sans_suffix }
             } else {
                 OverflowingBinHexSub::Help { suggestion_ty }
             }
@@ -156,7 +160,7 @@ fn report_bin_hex_error(
     );
     let sign_bit_sub = (!negative)
         .then(|| {
-            let ty::Int(int_ty) = cx.typeck_results().node_type(expr.hir_id).kind() else {
+            let ty::Int(int_ty) = cx.typeck_results().node_type(hir_id).kind() else {
                 return None;
             };
 
@@ -177,7 +181,7 @@ fn report_bin_hex_error(
                 };
 
             Some(OverflowingBinHexSignBitSub {
-                span: expr.span,
+                span,
                 lit_no_suffix,
                 negative_val: actually.clone(),
                 int_ty: int_ty.name_str(),
@@ -186,7 +190,7 @@ fn report_bin_hex_error(
         })
         .flatten();
 
-    cx.emit_span_lint(OVERFLOWING_LITERALS, expr.span, OverflowingBinHex {
+    cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingBinHex {
         ty: t,
         lit: repr_str.clone(),
         dec: val,
@@ -236,7 +240,8 @@ fn literal_to_i128(val: u128, negative: bool) -> Option<i128> {
 fn lint_int_literal<'tcx>(
     cx: &LateContext<'tcx>,
     type_limits: &TypeLimits,
-    e: &'tcx hir::Expr<'tcx>,
+    hir_id: HirId,
+    span: Span,
     lit: &hir::Lit,
     t: ty::IntTy,
     v: u128,
@@ -244,7 +249,7 @@ fn lint_int_literal<'tcx>(
     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(e.hir_id);
+    let negative = type_limits.negated_expr_id == Some(hir_id);
 
     // Detect literal value out of range [min, max] inclusive
     // avoiding use of -min to prevent overflow/panic
@@ -252,7 +257,8 @@ fn lint_int_literal<'tcx>(
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
             report_bin_hex_error(
                 cx,
-                e,
+                hir_id,
+                span,
                 attr::IntType::SignedInt(ty::ast_int_ty(t)),
                 Integer::from_int_ty(cx, t).size(),
                 repr_str,
@@ -262,18 +268,18 @@ fn lint_int_literal<'tcx>(
             return;
         }
 
-        if lint_overflowing_range_endpoint(cx, lit, v, max, e, t.name_str()) {
+        if lint_overflowing_range_endpoint(cx, lit, v, max, hir_id, span, t.name_str()) {
             // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`.
             return;
         }
 
-        let span = if negative { type_limits.negated_expr_span.unwrap() } else { e.span };
+        let span = if negative { type_limits.negated_expr_span.unwrap() } else { span };
         let lit = cx
             .sess()
             .source_map()
             .span_to_snippet(span)
             .unwrap_or_else(|_| if negative { format!("-{v}") } else { v.to_string() });
-        let help = get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
+        let help = get_type_suggestion(cx.typeck_results().node_type(hir_id), v, negative)
             .map(|suggestion_ty| OverflowingIntHelp { suggestion_ty });
 
         cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingInt {
@@ -288,7 +294,8 @@ fn lint_int_literal<'tcx>(
 
 fn lint_uint_literal<'tcx>(
     cx: &LateContext<'tcx>,
-    e: &'tcx hir::Expr<'tcx>,
+    hir_id: HirId,
+    span: Span,
     lit: &hir::Lit,
     t: ty::UintTy,
 ) {
@@ -302,7 +309,7 @@ fn lint_uint_literal<'tcx>(
     };
 
     if lit_val < min || lit_val > max {
-        if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) {
+        if let Node::Expr(par_e) = cx.tcx.parent_hir_node(hir_id) {
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
@@ -316,14 +323,15 @@ fn lint_uint_literal<'tcx>(
                 _ => {}
             }
         }
-        if lint_overflowing_range_endpoint(cx, lit, lit_val, max, e, t.name_str()) {
+        if lint_overflowing_range_endpoint(cx, lit, lit_val, max, hir_id, span, t.name_str()) {
             // The overflowing literal lint was emitted by `lint_overflowing_range_endpoint`.
             return;
         }
         if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
             report_bin_hex_error(
                 cx,
-                e,
+                hir_id,
+                span,
                 attr::IntType::UnsignedInt(ty::ast_uint_ty(t)),
                 Integer::from_uint_ty(cx, t).size(),
                 repr_str,
@@ -332,7 +340,7 @@ fn lint_uint_literal<'tcx>(
             );
             return;
         }
-        cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingUInt {
+        cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingUInt {
             ty: t.name_str(),
             lit: cx
                 .sess()
@@ -348,19 +356,20 @@ fn lint_uint_literal<'tcx>(
 pub(crate) fn lint_literal<'tcx>(
     cx: &LateContext<'tcx>,
     type_limits: &TypeLimits,
-    e: &'tcx hir::Expr<'tcx>,
+    hir_id: HirId,
+    span: Span,
     lit: &hir::Lit,
 ) {
-    match *cx.typeck_results().node_type(e.hir_id).kind() {
+    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, e, lit, t, v.get())
+                    lint_int_literal(cx, type_limits, hir_id, span, lit, t, v.get())
                 }
                 _ => bug!(),
             };
         }
-        ty::Uint(t) => lint_uint_literal(cx, e, lit, t),
+        ty::Uint(t) => 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 {
@@ -374,7 +383,7 @@ pub(crate) fn lint_literal<'tcx>(
                 _ => bug!(),
             };
             if is_infinite == Ok(true) {
-                cx.emit_span_lint(OVERFLOWING_LITERALS, e.span, OverflowingLiteral {
+                cx.emit_span_lint(OVERFLOWING_LITERALS, span, OverflowingLiteral {
                     ty: t.name_str(),
                     lit: cx
                         .sess()

From 9a2073d50059708d9150204348bbea087cd5f9c8 Mon Sep 17 00:00:00 2001
From: Oli Scherer <github333195615777966@oli-obk.de>
Date: Sat, 1 Feb 2025 10:06:35 +0000
Subject: [PATCH 3/3] Uniformly handle HIR literals in visitors and lints

---
 compiler/rustc_hir/src/intravisit.rs          |  8 +++-
 compiler/rustc_lint/src/late.rs               |  4 ++
 compiler/rustc_lint/src/passes.rs             |  1 +
 compiler/rustc_lint/src/types.rs              | 13 ++++++-
 compiler/rustc_lint/src/types/literal.rs      | 11 ++++--
 .../clippy/clippy_lints/src/approx_const.rs   | 38 +++++++++----------
 tests/ui/pattern/overflowing-literals.rs      |  1 +
 tests/ui/pattern/overflowing-literals.stderr  | 10 ++++-
 8 files changed, 57 insertions(+), 29 deletions(-)

diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 6519552d6046b..f632041dba9f2 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -345,6 +345,9 @@ 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: &'v Lit, _negated: bool) -> Self::Result {
+        Self::Result::output()
+    }
     fn visit_anon_const(&mut self, c: &'v AnonConst) -> Self::Result {
         walk_anon_const(self, c)
     }
@@ -764,7 +767,7 @@ pub fn walk_pat_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v PatField<'
 pub fn walk_pat_expr<'v, V: Visitor<'v>>(visitor: &mut V, expr: &'v PatExpr<'v>) -> V::Result {
     try_visit!(visitor.visit_id(expr.hir_id));
     match &expr.kind {
-        PatExprKind::Lit { .. } => V::Result::output(),
+        PatExprKind::Lit { lit, negated } => visitor.visit_lit(expr.hir_id, lit, *negated),
         PatExprKind::ConstBlock(c) => visitor.visit_inline_const(c),
         PatExprKind::Path(qpath) => visitor.visit_qpath(qpath, expr.hir_id, expr.span),
     }
@@ -912,7 +915,8 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
             try_visit!(visitor.visit_expr(expr));
             visit_opt!(visitor, visit_ty_unambig, ty);
         }
-        ExprKind::Lit(_) | ExprKind::Err(_) => {}
+        ExprKind::Lit(lit) => try_visit!(visitor.visit_lit(expression.hir_id, lit, false)),
+        ExprKind::Err(_) => {}
     }
     V::Result::output()
 }
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index 826ecc22c24ba..3ee908ba9bf44 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -152,6 +152,10 @@ 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: &'tcx hir::Lit, negated: bool) {
+        lint_callback!(self, check_lit, hir_id, lit, negated);
+    }
+
     fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
         self.with_lint_attrs(field.hir_id, |cx| hir_visit::walk_expr_field(cx, field))
     }
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index 8cc8f911d3a6d..77bd13aacf737 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -23,6 +23,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: &'tcx rustc_hir::Lit, negated: 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 3c8a7ada4bf12..80007f34db356 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -5,7 +5,7 @@ use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, Wrapp
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::DiagMessage;
 use rustc_hir::intravisit::VisitorExt;
-use rustc_hir::{AmbigArg, Expr, ExprKind, LangItem};
+use rustc_hir::{AmbigArg, Expr, ExprKind, HirId, LangItem};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton};
 use rustc_middle::ty::{
@@ -536,6 +536,16 @@ fn lint_fn_pointer<'tcx>(
 }
 
 impl<'tcx> LateLintPass<'tcx> for TypeLimits {
+    fn check_lit(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        hir_id: HirId,
+        lit: &'tcx hir::Lit,
+        negated: bool,
+    ) {
+        lint_literal(cx, self, hir_id, lit.span, lit, negated)
+    }
+
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
         match e.kind {
             hir::ExprKind::Unary(hir::UnOp::Neg, expr) => {
@@ -557,7 +567,6 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
                     }
                 }
             }
-            hir::ExprKind::Lit(lit) => lint_literal(cx, self, e.hir_id, e.span, lit),
             hir::ExprKind::Call(path, [l, r])
                 if let ExprKind::Path(ref qpath) = path.kind
                     && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
diff --git a/compiler/rustc_lint/src/types/literal.rs b/compiler/rustc_lint/src/types/literal.rs
index 7d49b260acca8..71e6e229907ac 100644
--- a/compiler/rustc_lint/src/types/literal.rs
+++ b/compiler/rustc_lint/src/types/literal.rs
@@ -245,11 +245,12 @@ fn lint_int_literal<'tcx>(
     lit: &hir::Lit,
     t: ty::IntTy,
     v: u128,
+    negated: bool,
 ) {
     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 = negated ^ (type_limits.negated_expr_id == Some(hir_id));
 
     // Detect literal value out of range [min, max] inclusive
     // avoiding use of -min to prevent overflow/panic
@@ -359,17 +360,21 @@ pub(crate) fn lint_literal<'tcx>(
     hir_id: HirId,
     span: Span,
     lit: &hir::Lit,
+    negated: bool,
 ) {
     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, type_limits, hir_id, span, lit, t, v.get(), negated)
                 }
                 _ => bug!(),
             };
         }
-        ty::Uint(t) => lint_uint_literal(cx, hir_id, span, lit, t),
+        ty::Uint(t) => {
+            assert!(!negated);
+            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 {
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 95c85f250e985..95f64b74044b1 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::msrvs::{self, Msrv};
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 use rustc_attr_parsing::RustcVersion;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{HirId, Lit};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::symbol;
+use rustc_span::{Span, symbol};
 use std::f64::consts as f64;
 
 declare_clippy_lint! {
@@ -73,22 +73,28 @@ impl ApproxConstant {
             msrv: conf.msrv.clone(),
         }
     }
+}
 
-    fn check_lit(&self, cx: &LateContext<'_>, lit: &LitKind, e: &Expr<'_>) {
-        match *lit {
+impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
+    fn check_lit(&mut self, cx: &LateContext<'_>, _hir_id: HirId, lit: &Lit, _negated: bool) {
+        match lit.node {
             LitKind::Float(s, LitFloatType::Suffixed(fty)) => match fty {
-                FloatTy::F16 => self.check_known_consts(cx, e, s, "f16"),
-                FloatTy::F32 => self.check_known_consts(cx, e, s, "f32"),
-                FloatTy::F64 => self.check_known_consts(cx, e, s, "f64"),
-                FloatTy::F128 => self.check_known_consts(cx, e, s, "f128"),
+                FloatTy::F16 => self.check_known_consts(cx, lit.span, s, "f16"),
+                FloatTy::F32 => self.check_known_consts(cx, lit.span, s, "f32"),
+                FloatTy::F64 => self.check_known_consts(cx, lit.span, s, "f64"),
+                FloatTy::F128 => self.check_known_consts(cx, lit.span, s, "f128"),
             },
             // FIXME(f16_f128): add `f16` and `f128` when these types become stable.
-            LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, e, s, "f{32, 64}"),
+            LitKind::Float(s, LitFloatType::Unsuffixed) => self.check_known_consts(cx, lit.span, s, "f{32, 64}"),
             _ => (),
         }
     }
 
-    fn check_known_consts(&self, cx: &LateContext<'_>, e: &Expr<'_>, s: symbol::Symbol, module: &str) {
+    extract_msrv_attr!(LateContext);
+}
+
+impl ApproxConstant {
+    fn check_known_consts(&self, cx: &LateContext<'_>, span: Span, s: symbol::Symbol, module: &str) {
         let s = s.as_str();
         if s.parse::<f64>().is_ok() {
             for &(constant, name, min_digits, msrv) in &KNOWN_CONSTS {
@@ -96,7 +102,7 @@ impl ApproxConstant {
                     span_lint_and_help(
                         cx,
                         APPROX_CONSTANT,
-                        e.span,
+                        span,
                         format!("approximate value of `{module}::consts::{name}` found"),
                         None,
                         "consider using the constant directly",
@@ -110,16 +116,6 @@ impl ApproxConstant {
 
 impl_lint_pass!(ApproxConstant => [APPROX_CONSTANT]);
 
-impl<'tcx> LateLintPass<'tcx> for ApproxConstant {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Lit(lit) = &e.kind {
-            self.check_lit(cx, &lit.node, e);
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
 /// Returns `false` if the number of significant figures in `value` are
 /// less than `min_digits`; otherwise, returns true if `value` is equal
 /// to `constant`, rounded to the number of digits present in `value`.
diff --git a/tests/ui/pattern/overflowing-literals.rs b/tests/ui/pattern/overflowing-literals.rs
index ab92283ff67c6..13016d3f7d197 100644
--- a/tests/ui/pattern/overflowing-literals.rs
+++ b/tests/ui/pattern/overflowing-literals.rs
@@ -15,6 +15,7 @@ type TooBigSigned = pattern_type!(i8 is 200..);
 fn main() {
     match 5_u8 {
         500 => {}
+        //~^ ERROR literal out of range for `u8`
         _ => {}
     }
 }
diff --git a/tests/ui/pattern/overflowing-literals.stderr b/tests/ui/pattern/overflowing-literals.stderr
index b6609303cb7df..8164b97fd4720 100644
--- a/tests/ui/pattern/overflowing-literals.stderr
+++ b/tests/ui/pattern/overflowing-literals.stderr
@@ -25,5 +25,13 @@ LL | type TooBigSigned = pattern_type!(i8 is 200..);
    = note: the literal `200` does not fit into the type `i8` whose range is `-128..=127`
    = help: consider using the type `u8` instead
 
-error: aborting due to 3 previous errors
+error: literal out of range for `u8`
+  --> $DIR/overflowing-literals.rs:17:9
+   |
+LL |         500 => {}
+   |         ^^^
+   |
+   = note: the literal `500` does not fit into the type `u8` whose range is `0..=255`
+
+error: aborting due to 4 previous errors