diff options
| author | Nicholas Nethercote <n.nethercote@gmail.com> | 2022-10-10 13:40:56 +1100 |
|---|---|---|
| committer | Nicholas Nethercote <n.nethercote@gmail.com> | 2022-11-16 09:41:28 +1100 |
| commit | 358a603f110b0489d22f3929d3f232e684fd9ffb (patch) | |
| tree | e409967cbf3698809be84c84dbf25285dc154bdb /src | |
| parent | 01760265cbdc985af50e7046e7635d124b24e335 (diff) | |
Use `token::Lit` in `ast::ExprKind::Lit`.
Instead of `ast::Lit`. Literal lowering now happens at two different times. Expression literals are lowered when HIR is crated. Attribute literals are lowered during parsing. This commit changes the language very slightly. Some programs that used to not compile now will compile. This is because some invalid literals that are removed by `cfg` or attribute macros will no longer trigger errors. See this comment for more details: https://github.com/rust-lang/rust/pull/102944#issuecomment-1277476773
Diffstat (limited to 'src')
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, |
