about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/codemap_tests/unicode_2.stderr12
-rw-r--r--src/test/ui/lexer/error-stage.rs65
-rw-r--r--src/test/ui/lexer/error-stage.stderr48
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.rs5
-rw-r--r--src/test/ui/parser/bad-lit-suffixes.stderr67
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs6
-rw-r--r--src/tools/rustfmt/src/attr.rs6
-rw-r--r--src/tools/rustfmt/src/expr.rs41
19 files changed, 224 insertions, 187 deletions
diff --git a/src/test/ui/codemap_tests/unicode_2.stderr b/src/test/ui/codemap_tests/unicode_2.stderr
index a776a4a1e7e..19aae1d3c95 100644
--- a/src/test/ui/codemap_tests/unicode_2.stderr
+++ b/src/test/ui/codemap_tests/unicode_2.stderr
@@ -1,3 +1,9 @@
+error[E0425]: cannot find value `a̐é` in this scope
+  --> $DIR/unicode_2.rs:4:13
+   |
+LL |     let _ = a̐é;
+   |             ^^ not found in this scope
+
 error: invalid width `7` for integer literal
   --> $DIR/unicode_2.rs:2:25
    |
@@ -14,12 +20,6 @@ LL |     let _ = ("아あ", 1i42);
    |
    = help: valid widths are 8, 16, 32, 64 and 128
 
-error[E0425]: cannot find value `a̐é` in this scope
-  --> $DIR/unicode_2.rs:4:13
-   |
-LL |     let _ = a̐é;
-   |             ^^ not found in this scope
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0425`.
diff --git a/src/test/ui/lexer/error-stage.rs b/src/test/ui/lexer/error-stage.rs
index 05ae0e82bfb..c8d88f745a1 100644
--- a/src/test/ui/lexer/error-stage.rs
+++ b/src/test/ui/lexer/error-stage.rs
@@ -1,31 +1,80 @@
+// This test is about the treatment of invalid literals. In particular, some
+// literals are only considered invalid if they survive to HIR lowering.
+//
+// Literals with bad suffixes
+// --------------------------
+// Literals consist of a primary part and an optional suffix.
+// https://doc.rust-lang.org/reference/tokens.html#suffixes says:
+//
+//   Any kind of literal (string, integer, etc) with any suffix is valid as a
+//   token, and can be passed to a macro without producing an error. The macro
+//   itself will decide how to interpret such a token and whether to produce an
+//   error or not.
+//
+//   ```
+//   macro_rules! blackhole { ($tt:tt) => () }
+//   blackhole!("string"suffix); // OK
+//   ```
+//
+//   However, suffixes on literal tokens parsed as Rust code are restricted.
+//   Any suffixes are rejected on non-numeric literal tokens, and numeric
+//   literal tokens are accepted only with suffixes from the list below.
+//
+//   Integer: u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize
+//   Floating-point: f32, f64
+//
+// This means that something like `"string"any_suffix` is a token accepted by
+// the lexer, but rejected later for being an invalid combination of primary
+// part and suffix.
+//
+// `0b10f32` is a similar case. `0b10` is a valid primary part that is a valid
+// *integer* literal when no suffix is present. It only causes an error later
+// when combined with the `f32` float suffix.
+//
+// However, `0b10.0f32` is different. It is rejected by the lexer because
+// `0b10.0` is not a valid token even on its own.
+//
+// This difference is unfortunate, but it's baked into the language now.
+//
+// Too-large integer literals
+// --------------------------
+// https://doc.rust-lang.org/reference/tokens.html#integer-literals says that
+// literals like `128_i8` and `256_u8` "are too big for their type, but are
+// still valid tokens".
+
 macro_rules! sink {
     ($($x:tt;)*) => {()}
 }
 
-// The invalid literals are ignored because the macro consumes them.
+// The invalid literals are ignored because the macro consumes them. Except for
+// `0b10.0f32` because it's a lexer error.
 const _: () = sink! {
     "string"any_suffix; // OK
     10u123; // OK
     10.0f123; // OK
     0b10f32; // OK
+    0b10.0f32; //~ ERROR binary float literal is not supported
     999340282366920938463463374607431768211455999; // OK
 };
 
-// The invalid literals cause errors.
+// The invalid literals used to cause errors, but this was changed by #102944.
+// Except for `0b010.0f32`, because it's a lexer error.
 #[cfg(FALSE)]
 fn configured_out() {
-    "string"any_suffix; //~ ERROR suffixes on string literals are invalid
-    10u123; //~ ERROR invalid width `123` for integer literal
-    10.0f123; //~ ERROR invalid width `123` for float literal
-    0b10f32; //~ ERROR binary float literal is not supported
-    999340282366920938463463374607431768211455999; //~ ERROR integer literal is too large
+    "string"any_suffix; // OK
+    10u123; // OK
+    10.0f123; // OK
+    0b10f32; // OK
+    0b10.0f32; //~ ERROR binary float literal is not supported
+    999340282366920938463463374607431768211455999; // OK
 }
 
-// The invalid literals cause errors.
+// All the invalid literals cause errors.
 fn main() {
     "string"any_suffix; //~ ERROR suffixes on string literals are invalid
     10u123; //~ ERROR invalid width `123` for integer literal
     10.0f123; //~ ERROR invalid width `123` for float literal
     0b10f32; //~ ERROR binary float literal is not supported
+    0b10.0f32; //~ ERROR binary float literal is not supported
     999340282366920938463463374607431768211455999; //~ ERROR integer literal is too large
 }
diff --git a/src/test/ui/lexer/error-stage.stderr b/src/test/ui/lexer/error-stage.stderr
index 024b7d94037..697a7c28da1 100644
--- a/src/test/ui/lexer/error-stage.stderr
+++ b/src/test/ui/lexer/error-stage.stderr
@@ -1,45 +1,29 @@
-error: suffixes on string literals are invalid
-  --> $DIR/error-stage.rs:17:5
-   |
-LL |     "string"any_suffix;
-   |     ^^^^^^^^^^^^^^^^^^ invalid suffix `any_suffix`
-
-error: invalid width `123` for integer literal
-  --> $DIR/error-stage.rs:18:5
+error: binary float literal is not supported
+  --> $DIR/error-stage.rs:56:5
    |
-LL |     10u123;
+LL |     0b10.0f32;
    |     ^^^^^^
-   |
-   = help: valid widths are 8, 16, 32, 64 and 128
-
-error: invalid width `123` for float literal
-  --> $DIR/error-stage.rs:19:5
-   |
-LL |     10.0f123;
-   |     ^^^^^^^^
-   |
-   = help: valid widths are 32 and 64
 
 error: binary float literal is not supported
-  --> $DIR/error-stage.rs:20:5
+  --> $DIR/error-stage.rs:68:5
    |
-LL |     0b10f32;
-   |     ^^^^^^^ not supported
+LL |     0b10.0f32;
+   |     ^^^^^^
 
-error: integer literal is too large
-  --> $DIR/error-stage.rs:21:5
+error: binary float literal is not supported
+  --> $DIR/error-stage.rs:78:5
    |
-LL |     999340282366920938463463374607431768211455999;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     0b10.0f32;
+   |     ^^^^^^
 
 error: suffixes on string literals are invalid
-  --> $DIR/error-stage.rs:26:5
+  --> $DIR/error-stage.rs:74:5
    |
 LL |     "string"any_suffix;
    |     ^^^^^^^^^^^^^^^^^^ invalid suffix `any_suffix`
 
 error: invalid width `123` for integer literal
-  --> $DIR/error-stage.rs:27:5
+  --> $DIR/error-stage.rs:75:5
    |
 LL |     10u123;
    |     ^^^^^^
@@ -47,7 +31,7 @@ LL |     10u123;
    = help: valid widths are 8, 16, 32, 64 and 128
 
 error: invalid width `123` for float literal
-  --> $DIR/error-stage.rs:28:5
+  --> $DIR/error-stage.rs:76:5
    |
 LL |     10.0f123;
    |     ^^^^^^^^
@@ -55,16 +39,16 @@ LL |     10.0f123;
    = help: valid widths are 32 and 64
 
 error: binary float literal is not supported
-  --> $DIR/error-stage.rs:29:5
+  --> $DIR/error-stage.rs:77:5
    |
 LL |     0b10f32;
    |     ^^^^^^^ not supported
 
 error: integer literal is too large
-  --> $DIR/error-stage.rs:30:5
+  --> $DIR/error-stage.rs:79:5
    |
 LL |     999340282366920938463463374607431768211455999;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 10 previous errors
+error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs
index 58b30872677..8cb9ef7e0c9 100644
--- a/src/test/ui/parser/bad-lit-suffixes.rs
+++ b/src/test/ui/parser/bad-lit-suffixes.rs
@@ -28,12 +28,11 @@ fn main() {
 }
 
 #[rustc_dummy = "string"suffix]
-//~^ ERROR suffixes on string literals are invalid
+//~^ ERROR unexpected expression: `"string"suffix`
 fn f() {}
 
 #[must_use = "string"suffix]
-//~^ ERROR suffixes on string literals are invalid
-//~^^ ERROR malformed `must_use` attribute input
+//~^ ERROR unexpected expression: `"string"suffix`
 fn g() {}
 
 #[link(name = "string"suffix)]
diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr
index 14c0eda81be..756f99ab12c 100644
--- a/src/test/ui/parser/bad-lit-suffixes.stderr
+++ b/src/test/ui/parser/bad-lit-suffixes.stderr
@@ -10,6 +10,32 @@ error: suffixes on string literals are invalid
 LL |     "C"suffix
    |     ^^^^^^^^^ invalid suffix `suffix`
 
+error: unexpected expression: `"string"suffix`
+  --> $DIR/bad-lit-suffixes.rs:30:17
+   |
+LL | #[rustc_dummy = "string"suffix]
+   |                 ^^^^^^^^^^^^^^
+
+error: unexpected expression: `"string"suffix`
+  --> $DIR/bad-lit-suffixes.rs:34:14
+   |
+LL | #[must_use = "string"suffix]
+   |              ^^^^^^^^^^^^^^
+
+error: suffixes on string literals are invalid
+  --> $DIR/bad-lit-suffixes.rs:38:15
+   |
+LL | #[link(name = "string"suffix)]
+   |               ^^^^^^^^^^^^^^ invalid suffix `suffix`
+
+error: invalid suffix `suffix` for number literal
+  --> $DIR/bad-lit-suffixes.rs:42:41
+   |
+LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
+   |                                         ^^^^^^^ invalid suffix `suffix`
+   |
+   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
 error: suffixes on string literals are invalid
   --> $DIR/bad-lit-suffixes.rs:12:5
    |
@@ -110,44 +136,5 @@ LL |     1.0e10suffix;
    |
    = help: valid suffixes are `f32` and `f64`
 
-error: suffixes on string literals are invalid
-  --> $DIR/bad-lit-suffixes.rs:30:17
-   |
-LL | #[rustc_dummy = "string"suffix]
-   |                 ^^^^^^^^^^^^^^ invalid suffix `suffix`
-
-error: suffixes on string literals are invalid
-  --> $DIR/bad-lit-suffixes.rs:34:14
-   |
-LL | #[must_use = "string"suffix]
-   |              ^^^^^^^^^^^^^^ invalid suffix `suffix`
-
-error: malformed `must_use` attribute input
-  --> $DIR/bad-lit-suffixes.rs:34:1
-   |
-LL | #[must_use = "string"suffix]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: the following are the possible correct uses
-   |
-LL | #[must_use = "reason"]
-   |
-LL | #[must_use]
-   |
-
-error: suffixes on string literals are invalid
-  --> $DIR/bad-lit-suffixes.rs:39:15
-   |
-LL | #[link(name = "string"suffix)]
-   |               ^^^^^^^^^^^^^^ invalid suffix `suffix`
-
-error: invalid suffix `suffix` for number literal
-  --> $DIR/bad-lit-suffixes.rs:43:41
-   |
-LL | #[rustc_layout_scalar_valid_range_start(0suffix)]
-   |                                         ^^^^^^^ invalid suffix `suffix`
-   |
-   = help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
index 073e4af1318..df92579a85d 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_letter_range.rs
@@ -73,12 +73,21 @@ impl EarlyLintPass for AlmostCompleteLetterRange {
 }
 
 fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
-    if let ExprKind::Lit(start_lit) = &start.peel_parens().kind
-        && let ExprKind::Lit(end_lit) = &end.peel_parens().kind
+    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
+        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
         && matches!(
-            (&start_lit.kind, &end_lit.kind),
-            (LitKind::Byte(b'a') | LitKind::Char('a'), LitKind::Byte(b'z') | LitKind::Char('z'))
-            | (LitKind::Byte(b'A') | LitKind::Char('A'), LitKind::Byte(b'Z') | LitKind::Char('Z'))
+            (
+                LitKind::from_token_lit(start_token_lit),
+                LitKind::from_token_lit(end_token_lit),
+            ),
+            (
+                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+            )
+            | (
+                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+            )
         )
         && !in_external_macro(cx.sess(), span)
     {
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 33491da3fc5..f793abdfda3 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -2,7 +2,8 @@
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, Lit, LitKind};
+use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind};
+use rustc_ast::token;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -52,8 +53,8 @@ enum Side {
 
 impl IntPlusOne {
     #[expect(clippy::cast_sign_loss)]
-    fn check_lit(lit: &Lit, target_value: i128) -> bool {
-        if let LitKind::Int(value, ..) = lit.kind {
+    fn check_lit(token_lit: token::Lit, target_value: i128) -> bool {
+        if let Ok(LitKind::Int(value, ..)) = LitKind::from_token_lit(token_lit) {
             return value == (target_value as u128);
         }
         false
@@ -65,11 +66,11 @@ impl IntPlusOne {
             (BinOpKind::Ge, &ExprKind::Binary(ref lhskind, ref lhslhs, ref lhsrhs), _) => {
                 match (lhskind.node, &lhslhs.kind, &lhsrhs.kind) {
                     // `-1 + x`
-                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
+                    (BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
                         Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
                     },
                     // `x - 1`
-                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+                    (BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
                     },
                     _ => None,
@@ -81,10 +82,10 @@ impl IntPlusOne {
             {
                 match (&rhslhs.kind, &rhsrhs.kind) {
                     // `y + 1` and `1 + y`
-                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
+                    (&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
                     },
-                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+                    (_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
                     },
                     _ => None,
@@ -96,10 +97,10 @@ impl IntPlusOne {
             {
                 match (&lhslhs.kind, &lhsrhs.kind) {
                     // `1 + x` and `x + 1`
-                    (&ExprKind::Lit(ref lit), _) if Self::check_lit(lit, 1) => {
+                    (&ExprKind::Lit(lit), _) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, lhsrhs, rhs, Side::Lhs)
                     },
-                    (_, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+                    (_, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, lhslhs, rhs, Side::Lhs)
                     },
                     _ => None,
@@ -109,11 +110,11 @@ impl IntPlusOne {
             (BinOpKind::Le, _, &ExprKind::Binary(ref rhskind, ref rhslhs, ref rhsrhs)) => {
                 match (rhskind.node, &rhslhs.kind, &rhsrhs.kind) {
                     // `-1 + y`
-                    (BinOpKind::Add, &ExprKind::Lit(ref lit), _) if Self::check_lit(lit, -1) => {
+                    (BinOpKind::Add, &ExprKind::Lit(lit), _) if Self::check_lit(lit, -1) => {
                         Self::generate_recommendation(cx, binop, rhsrhs, lhs, Side::Rhs)
                     },
                     // `y - 1`
-                    (BinOpKind::Sub, _, &ExprKind::Lit(ref lit)) if Self::check_lit(lit, 1) => {
+                    (BinOpKind::Sub, _, &ExprKind::Lit(lit)) if Self::check_lit(lit, 1) => {
                         Self::generate_recommendation(cx, binop, rhslhs, lhs, Side::Rhs)
                     },
                     _ => None,
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 25f19b9c6e6..3a7b7835c99 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -5,11 +5,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::{NumericLiteral, Radix};
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
-use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
+use rustc_ast::ast::{Expr, ExprKind, LitKind};
+use rustc_ast::token;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
 use std::iter;
 
 declare_clippy_lint! {
@@ -236,8 +238,8 @@ impl EarlyLintPass for LiteralDigitGrouping {
             return;
         }
 
-        if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit);
+        if let ExprKind::Lit(lit) = expr.kind {
+            self.check_lit(cx, lit, expr.span);
         }
     }
 }
@@ -252,12 +254,13 @@ impl LiteralDigitGrouping {
         }
     }
 
-    fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
+    fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
         if_chain! {
-            if let Some(src) = snippet_opt(cx, lit.span);
-            if let Some(mut num_lit) = NumericLiteral::from_lit(&src, lit);
+            if let Some(src) = snippet_opt(cx, span);
+            if let Ok(lit_kind) = LitKind::from_token_lit(lit);
+            if let Some(mut num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
             then {
-                if !Self::check_for_mistyped_suffix(cx, lit.span, &mut num_lit) {
+                if !Self::check_for_mistyped_suffix(cx, span, &mut num_lit) {
                     return;
                 }
 
@@ -293,14 +296,14 @@ impl LiteralDigitGrouping {
                         | WarningType::InconsistentDigitGrouping
                         | WarningType::UnusualByteGroupings
                         | WarningType::LargeDigitGroups => {
-                            !lit.span.from_expansion()
+                            !span.from_expansion()
                         }
                         WarningType::DecimalRepresentation | WarningType::MistypedLiteralSuffix => {
                             true
                         }
                     };
                     if should_warn {
-                        warning_type.display(num_lit.format(), cx, lit.span);
+                        warning_type.display(num_lit.format(), cx, span);
                     }
                 }
             }
@@ -458,8 +461,8 @@ impl EarlyLintPass for DecimalLiteralRepresentation {
             return;
         }
 
-        if let ExprKind::Lit(ref lit) = expr.kind {
-            self.check_lit(cx, lit);
+        if let ExprKind::Lit(lit) = expr.kind {
+            self.check_lit(cx, lit, expr.span);
         }
     }
 }
@@ -469,19 +472,20 @@ impl DecimalLiteralRepresentation {
     pub fn new(threshold: u64) -> Self {
         Self { threshold }
     }
-    fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) {
+    fn check_lit(self, cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
         // Lint integral literals.
         if_chain! {
-            if let LitKind::Int(val, _) = lit.kind;
-            if let Some(src) = snippet_opt(cx, lit.span);
-            if let Some(num_lit) = NumericLiteral::from_lit(&src, lit);
+            if let Ok(lit_kind) = LitKind::from_token_lit(lit);
+            if let LitKind::Int(val, _) = lit_kind;
+            if let Some(src) = snippet_opt(cx, span);
+            if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit_kind);
             if num_lit.radix == Radix::Decimal;
             if val >= u128::from(self.threshold);
             then {
                 let hex = format!("{val:#X}");
                 let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false);
                 let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| {
-                    warning_type.display(num_lit.format(), cx, lit.span);
+                    warning_type.display(num_lit.format(), cx, span);
                 });
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
index 27e7f8505eb..eda4376f200 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/literal_suffix.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::Lit;
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
+use rustc_span::Span;
 
 use super::{SEPARATED_LITERAL_SUFFIX, UNSEPARATED_LITERAL_SUFFIX};
 
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &str, sugg_type: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str, suffix: &str, sugg_type: &str) {
     let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
         return; // It's useless so shouldn't lint.
     };
@@ -15,7 +15,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
             span_lint_and_sugg(
                 cx,
                 SEPARATED_LITERAL_SUFFIX,
-                lit.span,
+                lit_span,
                 &format!("{sugg_type} type suffix should not be separated by an underscore"),
                 "remove the underscore",
                 format!("{}{suffix}", &lit_snip[..maybe_last_sep_idx]),
@@ -25,7 +25,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str, suffix: &s
             span_lint_and_sugg(
                 cx,
                 UNSEPARATED_LITERAL_SUFFIX,
-                lit.span,
+                lit_span,
                 &format!("{sugg_type} type suffix should be separated by an underscore"),
                 "add an underscore",
                 format!("{}_{suffix}", &lit_snip[..=maybe_last_sep_idx]),
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
index 263ee1e945a..ddb8b9173a5 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast::Lit;
 use rustc_lint::EarlyContext;
+use rustc_span::Span;
 
 use super::MIXED_CASE_HEX_LITERALS;
 
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_snip: &str) {
     let Some(maybe_last_sep_idx) = lit_snip.len().checked_sub(suffix.len() + 1) else {
         return; // It's useless so shouldn't lint.
     };
@@ -23,7 +23,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, suffix: &str, lit_snip: &s
             span_lint(
                 cx,
                 MIXED_CASE_HEX_LITERALS,
-                lit.span,
+                lit_span,
                 "inconsistent casing in hexadecimal literal",
             );
             break;
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index c8227ca4450..78be6b9e23f 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -9,7 +9,8 @@ mod zero_prefixed_literal;
 
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::ast::{Expr, ExprKind, Generics, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
+use rustc_ast::token;
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -374,42 +375,43 @@ impl EarlyLintPass for MiscEarlyLints {
             return;
         }
 
-        if let ExprKind::Lit(ref lit) = expr.kind {
-            MiscEarlyLints::check_lit(cx, lit);
+        if let ExprKind::Lit(lit) = expr.kind {
+            MiscEarlyLints::check_lit(cx, lit, expr.span);
         }
         double_neg::check(cx, expr);
     }
 }
 
 impl MiscEarlyLints {
-    fn check_lit(cx: &EarlyContext<'_>, lit: &Lit) {
+    fn check_lit(cx: &EarlyContext<'_>, lit: token::Lit, span: Span) {
         // We test if first character in snippet is a number, because the snippet could be an expansion
         // from a built-in macro like `line!()` or a proc-macro like `#[wasm_bindgen]`.
         // Note that this check also covers special case that `line!()` is eagerly expanded by compiler.
         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
         // FIXME: Find a better way to detect those cases.
-        let lit_snip = match snippet_opt(cx, lit.span) {
+        let lit_snip = match snippet_opt(cx, span) {
             Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip,
             _ => return,
         };
 
-        if let LitKind::Int(value, lit_int_type) = lit.kind {
+        let lit_kind = LitKind::from_token_lit(lit);
+        if let Ok(LitKind::Int(value, lit_int_type)) = lit_kind {
             let suffix = match lit_int_type {
                 LitIntType::Signed(ty) => ty.name_str(),
                 LitIntType::Unsigned(ty) => ty.name_str(),
                 LitIntType::Unsuffixed => "",
             };
-            literal_suffix::check(cx, lit, &lit_snip, suffix, "integer");
+            literal_suffix::check(cx, span, &lit_snip, suffix, "integer");
             if lit_snip.starts_with("0x") {
-                mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip);
+                mixed_case_hex_literals::check(cx, span, suffix, &lit_snip);
             } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") {
                 // nothing to do
             } else if value != 0 && lit_snip.starts_with('0') {
-                zero_prefixed_literal::check(cx, lit, &lit_snip);
+                zero_prefixed_literal::check(cx, span, &lit_snip);
             }
-        } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind {
+        } else if let Ok(LitKind::Float(_, LitFloatType::Suffixed(float_ty))) = lit_kind {
             let suffix = float_ty.name_str();
-            literal_suffix::check(cx, lit, &lit_snip, suffix, "float");
+            literal_suffix::check(cx, span, &lit_snip, suffix, "float");
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
index 9ead43ea4a4..4f9578d1b25 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/zero_prefixed_literal.rs
@@ -1,20 +1,20 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use rustc_ast::ast::Lit;
 use rustc_errors::Applicability;
 use rustc_lint::EarlyContext;
+use rustc_span::Span;
 
 use super::ZERO_PREFIXED_LITERAL;
 
-pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
+pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, lit_snip: &str) {
     let trimmed_lit_snip = lit_snip.trim_start_matches(|c| c == '_' || c == '0');
     span_lint_and_then(
         cx,
         ZERO_PREFIXED_LITERAL,
-        lit.span,
+        lit_span,
         "this is a decimal constant",
         |diag| {
             diag.span_suggestion(
-                lit.span,
+                lit_span,
                 "if you mean to use a decimal constant, remove the `0` to avoid confusion",
                 trimmed_lit_snip.to_string(),
                 Applicability::MaybeIncorrect,
@@ -22,7 +22,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit: &Lit, lit_snip: &str) {
             // do not advise to use octal form if the literal cannot be expressed in base 8.
             if !lit_snip.contains(|c| c == '8' || c == '9') {
                 diag.span_suggestion(
-                    lit.span,
+                    lit_span,
                     "if you mean to use an octal constant, use `0o`",
                     format!("0o{trimmed_lit_snip}"),
                     Applicability::MaybeIncorrect,
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index f380a506582..2a7159764e4 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -56,11 +56,11 @@ impl EarlyLintPass for OctalEscapes {
             return;
         }
 
-        if let ExprKind::Lit(lit) = &expr.kind {
-            if matches!(lit.token_lit.kind, LitKind::Str) {
-                check_lit(cx, &lit.token_lit, lit.span, true);
-            } else if matches!(lit.token_lit.kind, LitKind::ByteStr) {
-                check_lit(cx, &lit.token_lit, lit.span, false);
+        if let ExprKind::Lit(token_lit) = &expr.kind {
+            if matches!(token_lit.kind, LitKind::Str) {
+                check_lit(cx, &token_lit, expr.span, true);
+            } else if matches!(token_lit.kind, LitKind::ByteStr) {
+                check_lit(cx, &token_lit, expr.span, false);
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index e6e3ad05ad7..bee4a33fb4a 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -1,7 +1,8 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use if_chain::if_chain;
-use rustc_ast::ast::{BinOpKind, Expr, ExprKind, LitKind, UnOp};
+use rustc_ast::ast::{BinOpKind, Expr, ExprKind, UnOp};
+use rustc_ast::token;
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -120,7 +121,7 @@ impl EarlyLintPass for Precedence {
             if_chain! {
                 if !all_odd;
                 if let ExprKind::Lit(lit) = &arg.kind;
-                if let LitKind::Int(..) | LitKind::Float(..) = &lit.kind;
+                if let token::LitKind::Integer | token::LitKind::Float = &lit.kind;
                 then {
                     let mut applicability = Applicability::MachineApplicable;
                     span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 3164937293b..3c1998d0237 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use rustc_ast::ast::{Expr, ExprKind, LitFloatType, LitKind};
+use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -33,14 +33,14 @@ fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
     if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
         && let method_name = name_ident.ident.name.as_str()
         && (method_name == "ceil" || method_name == "round" || method_name == "floor")
-        && let ExprKind::Lit(spanned) = &receiver.kind
-        && let LitKind::Float(symbol, ty) = spanned.kind {
-            let f = symbol.as_str().parse::<f64>().unwrap();
-            let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
-                ty.name_str()
-            } else {
-                ""
-            };
+        && let ExprKind::Lit(token_lit) = &receiver.kind
+        && token_lit.is_semantic_float() {
+            let f = token_lit.symbol.as_str().parse::<f64>().unwrap();
+            let mut f_str = token_lit.symbol.to_string();
+            match token_lit.suffix {
+                Some(suffix) => f_str.push_str(suffix.as_str()),
+                None => {}
+            }
             if f.fract() == 0.0 {
                 Some((method_name, f_str))
             } else {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 0133997560e..73d1ba727c8 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -152,7 +152,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         },
         (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
         (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
-        (Lit(l), Lit(r)) => l.kind == r.kind,
+        (Lit(l), Lit(r)) => l == r,
         (Cast(l, lt), Cast(r, rt)) | (Type(l, lt), Type(r, rt)) => eq_expr(l, r) && eq_ty(lt, rt),
         (Let(lp, le, _), Let(rp, re, _)) => eq_pat(lp, rp) && eq_expr(le, re),
         (If(lc, lt, le), If(rc, rt, re)) => eq_expr(lc, rc) && eq_block(lt, rt) && eq_expr_opt(le, re),
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index c5dcd7b31f5..42bdfd4827f 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -1,4 +1,4 @@
-use rustc_ast::ast::{Lit, LitFloatType, LitIntType, LitKind};
+use rustc_ast::ast::{LitFloatType, LitIntType, LitKind};
 use std::iter;
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
@@ -46,10 +46,6 @@ pub struct NumericLiteral<'a> {
 }
 
 impl<'a> NumericLiteral<'a> {
-    pub fn from_lit(src: &'a str, lit: &Lit) -> Option<NumericLiteral<'a>> {
-        NumericLiteral::from_lit_kind(src, &lit.kind)
-    }
-
     pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> {
         let unsigned_src = src.strip_prefix('-').map_or(src, |s| s);
         if lit_kind.is_numeric()
diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs
index f5c1ee5fdd1..ccc2fd0d5f5 100644
--- a/src/tools/rustfmt/src/attr.rs
+++ b/src/tools/rustfmt/src/attr.rs
@@ -260,7 +260,9 @@ impl Rewrite for ast::NestedMetaItem {
     fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
         match self {
             ast::NestedMetaItem::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
-            ast::NestedMetaItem::Literal(ref l) => rewrite_literal(context, l, shape),
+            ast::NestedMetaItem::Literal(ref l) => {
+                rewrite_literal(context, l.token_lit, l.span, shape)
+            }
         }
     }
 }
@@ -318,7 +320,7 @@ impl Rewrite for ast::MetaItem {
                 // we might be better off ignoring the fact that the attribute
                 // is longer than the max width and continue on formatting.
                 // See #2479 for example.
-                let value = rewrite_literal(context, literal, lit_shape)
+                let value = rewrite_literal(context, literal.token_lit, literal.span, lit_shape)
                     .unwrap_or_else(|| context.snippet(literal.span).to_owned());
                 format!("{} = {}", path, value)
             }
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 7750df0fff3..b4f1a178dbf 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -3,7 +3,7 @@ use std::cmp::min;
 
 use itertools::Itertools;
 use rustc_ast::token::{Delimiter, LitKind};
-use rustc_ast::{ast, ptr};
+use rustc_ast::{ast, ptr, token};
 use rustc_span::{BytePos, Span};
 
 use crate::chains::rewrite_chain;
@@ -75,12 +75,12 @@ pub(crate) fn format_expr(
             choose_separator_tactic(context, expr.span),
             None,
         ),
-        ast::ExprKind::Lit(ref l) => {
-            if let Some(expr_rw) = rewrite_literal(context, l, shape) {
+        ast::ExprKind::Lit(token_lit) => {
+            if let Some(expr_rw) = rewrite_literal(context, token_lit, expr.span, shape) {
                 Some(expr_rw)
             } else {
-                if let LitKind::StrRaw(_) = l.token_lit.kind {
-                    Some(context.snippet(l.span).trim().into())
+                if let LitKind::StrRaw(_) = token_lit.kind {
+                    Some(context.snippet(expr.span).trim().into())
                 } else {
                     None
                 }
@@ -274,9 +274,9 @@ pub(crate) fn format_expr(
 
             fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
                 match lhs.kind {
-                    ast::ExprKind::Lit(ref lit) => match lit.kind {
-                        ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
-                            context.snippet(lit.span).ends_with('.')
+                    ast::ExprKind::Lit(token_lit) => match token_lit.kind {
+                        token::LitKind::Float if token_lit.suffix.is_none() => {
+                            context.snippet(lhs.span).ends_with('.')
                         }
                         _ => false,
                     },
@@ -1185,14 +1185,15 @@ pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
 
 pub(crate) fn rewrite_literal(
     context: &RewriteContext<'_>,
-    l: &ast::Lit,
+    token_lit: token::Lit,
+    span: Span,
     shape: Shape,
 ) -> Option<String> {
-    match l.kind {
-        ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
-        ast::LitKind::Int(..) => rewrite_int_lit(context, l, shape),
+    match token_lit.kind {
+        token::LitKind::Str => rewrite_string_lit(context, span, shape),
+        token::LitKind::Integer => rewrite_int_lit(context, token_lit, span, shape),
         _ => wrap_str(
-            context.snippet(l.span).to_owned(),
+            context.snippet(span).to_owned(),
             context.config.max_width(),
             shape,
         ),
@@ -1225,9 +1226,13 @@ fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) ->
     )
 }
 
-fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -> Option<String> {
-    let span = lit.span;
-    let symbol = lit.token_lit.symbol.as_str();
+fn rewrite_int_lit(
+    context: &RewriteContext<'_>,
+    token_lit: token::Lit,
+    span: Span,
+    shape: Shape,
+) -> Option<String> {
+    let symbol = token_lit.symbol.as_str();
 
     if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
         let hex_lit = match context.config.hex_literal_case() {
@@ -1240,9 +1245,7 @@ fn rewrite_int_lit(context: &RewriteContext<'_>, lit: &ast::Lit, shape: Shape) -
                 format!(
                     "0x{}{}",
                     hex_lit,
-                    lit.token_lit
-                        .suffix
-                        .map_or(String::new(), |s| s.to_string())
+                    token_lit.suffix.map_or(String::new(), |s| s.to_string())
                 ),
                 context.config.max_width(),
                 shape,