From 0bed23bf2f2eafb2adb217e647fbf3855d9b2891 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Sep 2022 14:55:55 +1000 Subject: [PATCH 1/3] Inline `integer_lit` and `float_lit`. Because they are sometimes hot and each have a single call site. --- compiler/rustc_ast/src/util/literal.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 536b385606c69..be45494ef0d50 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -281,11 +281,13 @@ fn filtered_float_lit( }) } +#[inline] fn float_lit(symbol: Symbol, suffix: Option) -> Result { debug!("float_lit: {:?}, {:?}", symbol, suffix); filtered_float_lit(strip_underscores(symbol), suffix, 10) } +#[inline] fn integer_lit(symbol: Symbol, suffix: Option) -> Result { debug!("integer_lit: {:?}, {:?}", symbol, suffix); let symbol = strip_underscores(symbol); From ca00cfb082ac6af1f7b11bade333da62f93277f6 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 19 Sep 2022 16:13:57 +1000 Subject: [PATCH 2/3] Add a test. This will become interesting in the next commit. --- src/test/ui/lowering/literals.rs | 34 +++++++++++++ src/test/ui/lowering/literals.stderr | 74 ++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/test/ui/lowering/literals.rs create mode 100644 src/test/ui/lowering/literals.stderr diff --git a/src/test/ui/lowering/literals.rs b/src/test/ui/lowering/literals.rs new file mode 100644 index 0000000000000..7600a4aab4fc8 --- /dev/null +++ b/src/test/ui/lowering/literals.rs @@ -0,0 +1,34 @@ +// check-fail + +// A variety of code features that require the value of a literal prior to AST +// lowering. + +#![feature(concat_bytes)] + +#[repr(align(340282366920938463463374607431768211456))] +//~^ ERROR integer literal is too large +struct S1(u32); + +#[repr(align(4u7))] //~ ERROR invalid width `7` for integer literal +struct S2(u32); + +#[doc = "documentation"suffix] +//~^ ERROR suffixes on a string literal are invalid +//~^^ ERROR attribute must be of the form +//~^^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct D; + +#[doc(alias = 0u7)] //~ ERROR invalid width `7` for integer literal +struct E; + +fn main() { + println!(concat!( + "abc"suffix, //~ ERROR suffixes on a string literal are invalid + "blah"foo, //~ ERROR suffixes on a string literal are invalid + 3u33, //~ ERROR invalid width `33` for integer literal + )); + + let x = concat_bytes!("foo"blah, 3u33); + //~^ ERROR suffixes on a string literal are invalid + //~^^ ERROR invalid width `33` for integer literal +} diff --git a/src/test/ui/lowering/literals.stderr b/src/test/ui/lowering/literals.stderr new file mode 100644 index 0000000000000..467073ef09adb --- /dev/null +++ b/src/test/ui/lowering/literals.stderr @@ -0,0 +1,74 @@ +error: suffixes on a string literal are invalid + --> $DIR/literals.rs:15:9 + | +LL | #[doc = "documentation"suffix] + | ^^^^^^^^^^^^^^^^^^^^^ invalid suffix `suffix` + +error: suffixes on a string literal are invalid + --> $DIR/literals.rs:26:9 + | +LL | "abc"suffix, + | ^^^^^^^^^^^ invalid suffix `suffix` + +error: suffixes on a string literal are invalid + --> $DIR/literals.rs:27:9 + | +LL | "blah"foo, + | ^^^^^^^^^ invalid suffix `foo` + +error: invalid width `33` for integer literal + --> $DIR/literals.rs:28:9 + | +LL | 3u33, + | ^^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error: suffixes on a string literal are invalid + --> $DIR/literals.rs:31:27 + | +LL | let x = concat_bytes!("foo"blah, 3u33); + | ^^^^^^^^^ invalid suffix `blah` + +error: invalid width `33` for integer literal + --> $DIR/literals.rs:31:38 + | +LL | let x = concat_bytes!("foo"blah, 3u33); + | ^^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error: integer literal is too large + --> $DIR/literals.rs:8:14 + | +LL | #[repr(align(340282366920938463463374607431768211456))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid width `7` for integer literal + --> $DIR/literals.rs:12:14 + | +LL | #[repr(align(4u7))] + | ^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error: invalid width `7` for integer literal + --> $DIR/literals.rs:21:15 + | +LL | #[doc(alias = 0u7)] + | ^^^ + | + = help: valid widths are 8, 16, 32, 64 and 128 + +error: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]` + --> $DIR/literals.rs:15:1 + | +LL | #[doc = "documentation"suffix] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(ill_formed_attribute_input)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + +error: aborting due to 10 previous errors + From 434b81e199519c1ced4b566881f99d674e3ac033 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 16 Sep 2022 10:44:06 +1000 Subject: [PATCH 3/3] Remove `ast::Lit::kind`. This shrinks `ast::Lit` kind considerably. The conversion to semantic literals now happens at AST lowering time, with a few exceptions where the literal values are needed before that. --- compiler/rustc_ast/src/ast.rs | 23 +--- compiler/rustc_ast/src/attr/mod.rs | 12 +- compiler/rustc_ast/src/token.rs | 22 ++++ compiler/rustc_ast/src/util/literal.rs | 35 ++---- compiler/rustc_ast_lowering/src/errors.rs | 55 +++++++++ compiler/rustc_ast_lowering/src/expr.rs | 100 ++++++++++++++++- compiler/rustc_ast_lowering/src/lib.rs | 1 - compiler/rustc_attr/src/builtin.rs | 27 +++-- compiler/rustc_attr/src/lib.rs | 1 + .../rustc_attr/src/session_diagnostics.rs | 8 +- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_builtin_macros/src/concat.rs | 51 +++++---- .../rustc_builtin_macros/src/concat_bytes.rs | 82 +++++++------- compiler/rustc_expand/src/base.rs | 9 +- compiler/rustc_expand/src/build.rs | 2 +- compiler/rustc_interface/src/interface.rs | 7 +- compiler/rustc_lint/src/builtin.rs | 2 +- .../src/hidden_unicode_codepoints.rs | 8 +- compiler/rustc_lint/src/internal.rs | 3 +- compiler/rustc_lint/src/levels.rs | 4 +- compiler/rustc_lint/src/nonstandard_style.rs | 4 +- compiler/rustc_middle/src/ty/context.rs | 10 +- compiler/rustc_parse/src/parser/attr.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 55 --------- compiler/rustc_parse/src/parser/expr.rs | 104 +----------------- compiler/rustc_parse/src/parser/mod.rs | 4 +- compiler/rustc_parse/src/validate_attr.rs | 4 +- compiler/rustc_passes/src/check_attr.rs | 20 +++- compiler/rustc_resolve/src/lib.rs | 4 +- compiler/rustc_session/src/parse.rs | 39 ++++++- compiler/rustc_typeck/src/collect.rs | 13 ++- src/librustdoc/clean/cfg.rs | 24 ++-- src/librustdoc/clean/mod.rs | 4 +- src/librustdoc/clean/types.rs | 4 +- src/test/ui/codemap_tests/unicode_2.stderr | 12 +- src/test/ui/extenv/issue-55897.rs | 2 +- src/test/ui/extenv/issue-55897.stderr | 4 +- src/test/ui/lowering/literals.rs | 25 +++-- src/test/ui/lowering/literals.stderr | 97 ++++++++-------- src/test/ui/parser/bad-lit-suffixes.rs | 4 +- src/test/ui/parser/bad-lit-suffixes.stderr | 8 +- .../src/almost_complete_letter_range.rs | 15 ++- src/tools/clippy/clippy_lints/src/attrs.rs | 2 +- .../clippy/clippy_lints/src/int_plus_one.rs | 2 +- .../src/literal_representation.rs | 2 +- .../clippy/clippy_lints/src/misc_early/mod.rs | 5 +- .../clippy/clippy_lints/src/precedence.rs | 5 +- .../clippy_lints/src/unused_rounding.rs | 2 +- .../clippy/clippy_utils/src/ast_utils.rs | 4 +- .../clippy_utils/src/numeric_literal.rs | 3 +- src/tools/rustfmt/src/expr.rs | 18 +-- src/tools/rustfmt/src/modules/visitor.rs | 21 ++-- 52 files changed, 522 insertions(+), 454 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 6c514c75a500c..d4f48fe40d9cf 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1691,10 +1691,6 @@ pub enum StrStyle { pub struct Lit { /// The original literal token as written in source code. pub token_lit: token::Lit, - /// The "semantic" representation of the literal lowered from the original tokens. - /// Strings are unescaped, hexadecimal forms are eliminated, etc. - /// FIXME: Remove this and only create the semantic representation during lowering to HIR. - pub kind: LitKind, pub span: Span, } @@ -1717,11 +1713,7 @@ impl StrLit { StrStyle::Cooked => token::Str, StrStyle::Raw(n) => token::StrRaw(n), }; - Lit { - token_lit: token::Lit::new(token_kind, self.symbol, self.suffix), - span: self.span, - kind: LitKind::Str(self.symbol_unescaped, self.style), - } + Lit { token_lit: token::Lit::new(token_kind, self.symbol, self.suffix), span: self.span } } } @@ -1778,22 +1770,11 @@ impl LitKind { matches!(self, LitKind::Str(..)) } - /// Returns `true` if this literal is byte literal string. - pub fn is_bytestr(&self) -> bool { - matches!(self, LitKind::ByteStr(_)) - } - /// Returns `true` if this is a numeric literal. pub fn is_numeric(&self) -> bool { matches!(self, LitKind::Int(..) | LitKind::Float(..)) } - /// Returns `true` if this literal has no suffix. - /// Note: this will return true for literals with prefixes such as raw strings and byte strings. - pub fn is_unsuffixed(&self) -> bool { - !self.is_suffixed() - } - /// Returns `true` if this literal has a suffix. pub fn is_suffixed(&self) -> bool { match *self { @@ -3056,7 +3037,7 @@ mod size_asserts { static_assert_size!(Impl, 200); static_assert_size!(Item, 184); static_assert_size!(ItemKind, 112); - static_assert_size!(Lit, 48); + static_assert_size!(Lit, 20); static_assert_size!(LitKind, 24); static_assert_size!(Local, 72); static_assert_size!(Param, 40); diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 990f4f8f1329f..0b4dabbf91226 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -335,7 +335,7 @@ pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> Meta } pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem { - let lit = Lit::from_lit_kind(lit_kind, lit_span); + let lit = Lit { token_lit: lit_kind.to_token_lit(), span: lit_span }; let span = ident.span.to(lit_span); MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) } } @@ -519,8 +519,8 @@ impl MetaItem { impl MetaItemKind { pub fn value_str(&self) -> Option { match self { - MetaItemKind::NameValue(ref v) => match v.kind { - LitKind::Str(ref s, _) => Some(*s), + MetaItemKind::NameValue(ref v) => match LitKind::from_token_lit(v.token_lit) { + Ok(LitKind::Str(ref s, _)) => Some(*s), _ => None, }, _ => None, @@ -605,7 +605,7 @@ impl MetaItemKind { MetaItemKind::name_value_from_tokens(&mut inner_tokens.into_trees()) } Some(TokenTree::Token(token, _)) => { - Lit::from_token(&token).ok().map(MetaItemKind::NameValue) + Lit::from_token(&token).map(MetaItemKind::NameValue) } _ => None, } @@ -667,9 +667,7 @@ impl NestedMetaItem { I: Iterator, { match tokens.peek() { - Some(TokenTree::Token(token, _)) - if let Ok(lit) = Lit::from_token(token) => - { + Some(TokenTree::Token(token, _)) if let Some(lit) = Lit::from_token(token) => { tokens.next(); return Some(NestedMetaItem::Literal(lit)); } diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 97dfb7837674f..e81710eddae12 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -80,6 +80,28 @@ pub struct Lit { pub suffix: Option, } +impl Lit { + pub fn is_bool_true(&self) -> bool { + matches!(self.kind, LitKind::Bool) && self.symbol == kw::True + } + + /// Returns `true` if this literal is a string. + pub fn is_str(&self) -> bool { + matches!(self.kind, LitKind::Str | LitKind::StrRaw(_)) + } + + /// Returns `true` if this literal is byte literal string. + pub fn is_bytestr(&self) -> bool { + matches!(self.kind, LitKind::ByteStr | LitKind::ByteStrRaw(_)) + } + + /// Returns `true` if this literal has no suffix. + /// Note: this will return true for literals with prefixes such as raw strings and byte strings. + pub fn is_unsuffixed(&self) -> bool { + self.suffix.is_none() + } +} + impl fmt::Display for Lit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let Lit { kind, symbol, suffix } = *self; diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index be45494ef0d50..43a6344e9d283 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -6,12 +6,10 @@ use crate::token::{self, Token}; use rustc_lexer::unescape::{unescape_byte, unescape_char}; use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode}; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::Span; use std::ascii; pub enum LitError { - NotLiteral, LexerError, InvalidSuffix, InvalidIntSuffix, @@ -149,7 +147,7 @@ impl LitKind { }) } - /// Attempts to recover a token from semantic literal. + /// Creates a token literal from a semantic literal kind. /// This function is used when the original token doesn't exist (e.g. the literal is created /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). pub fn to_token_lit(&self) -> token::Lit { @@ -203,39 +201,30 @@ impl LitKind { } impl Lit { - /// Converts literal token into an AST literal. - pub fn from_token_lit(token_lit: token::Lit, span: Span) -> Result { - Ok(Lit { token_lit, kind: LitKind::from_token_lit(token_lit)?, span }) - } - - /// Converts arbitrary token into an AST literal. + /// Converts an arbitrary token into an AST literal. Returns `None` if the + /// token is not a literal. The literal may be invalid in some fashion + /// (e.g. invalid suffix, too-large int, etc.); this will be caught during + /// lowering to HIR. /// /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation. - pub fn from_token(token: &Token) -> Result { - let lit = match token.uninterpolate().kind { + pub fn from_token(token: &Token) -> Option { + let token_lit = match token.uninterpolate().kind { token::Ident(name, false) if name.is_bool_lit() => { token::Lit::new(token::Bool, name, None) } - token::Literal(lit) => lit, + token::Literal(token_lit) => token_lit, token::Interpolated(ref nt) => { if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt && let ast::ExprKind::Lit(lit) = &expr.kind { - return Ok(lit.clone()); + return Some(lit.clone()); } - return Err(LitError::NotLiteral); + return None; } - _ => return Err(LitError::NotLiteral), + _ => return None, }; - Lit::from_token_lit(lit, token.span) - } - - /// Attempts to recover an AST literal from semantic literal. - /// This function is used when the original token doesn't exist (e.g. the literal is created - /// by an AST-based macro) or unavailable (e.g. from HIR pretty-printing). - pub fn from_lit_kind(kind: LitKind, span: Span) -> Lit { - Lit { token_lit: kind.to_token_lit(), kind, span } + Some(Lit { token_lit, span: token.span }) } /// Losslessly convert an AST literal into a token. diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index c87d0ca96570e..180b1f4afb90c 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -2,6 +2,61 @@ use rustc_errors::{fluent, AddSubdiagnostic, Applicability, Diagnostic, Diagnost use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::{symbol::Ident, Span, Symbol}; +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_int_literal_width)] +#[help] +pub(crate) struct InvalidIntLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_base_prefix)] +#[note] +pub(crate) struct InvalidNumLiteralBasePrefix { + #[primary_span] + #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")] + pub span: Span, + pub fixed: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_num_literal_suffix)] +#[help] +pub(crate) struct InvalidNumLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_width)] +#[help] +pub(crate) struct InvalidFloatLiteralWidth { + #[primary_span] + pub span: Span, + pub width: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::invalid_float_literal_suffix)] +#[help] +pub(crate) struct InvalidFloatLiteralSuffix { + #[primary_span] + #[label] + pub span: Span, + pub suffix: String, +} + +#[derive(SessionDiagnostic)] +#[diag(parser::int_literal_too_large)] +pub(crate) struct IntLiteralTooLarge { + #[primary_span] + pub span: Span, +} + #[derive(SessionDiagnostic, Clone, Copy)] #[diag(ast_lowering::generic_type_with_parentheses, code = "E0214")] pub struct GenericTypeWithParentheses { diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 6c09269352cf2..1a7b567aada46 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1,14 +1,17 @@ use super::errors::{ AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt, - GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, - RustcBoxAttributeError, UnderscoreExprLhsAssign, + GeneratorTooManyParameters, InclusiveRangeWithNoEnd, IntLiteralTooLarge, + InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth, + InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, + NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError, UnderscoreExprLhsAssign, }; use super::ResolverAstLoweringExt; use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs}; use crate::{FnDeclKind, ImplTraitPosition}; use rustc_ast::attr; use rustc_ast::ptr::P as AstP; +use rustc_ast::util::literal::LitError; use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; @@ -84,8 +87,17 @@ impl<'hir> LoweringContext<'_, 'hir> { let ohs = self.lower_expr(ohs); hir::ExprKind::Unary(op, ohs) } - ExprKind::Lit(ref l) => { - hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone())) + ExprKind::Lit(ref lit) => { + let token_lit = lit.token_lit; + let lit_kind = match LitKind::from_token_lit(token_lit) { + Ok(lit_kind) => lit_kind, + Err(err) => { + let span = lit.span; + self.report_lit_error(err, token_lit, span); + LitKind::Err + } + }; + hir::ExprKind::Lit(respan(self.lower_span(lit.span), lit_kind)) } ExprKind::Cast(ref expr, ref ty) => { let expr = self.lower_expr(expr); @@ -306,6 +318,86 @@ impl<'hir> LoweringContext<'_, 'hir> { }) } + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { + // Checks if `s` looks like i32 or u1234 etc. + fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { + s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) + } + + // Try to lowercase the prefix if it's a valid base prefix. + fn fix_base_capitalisation(s: &str) -> Option { + if let Some(stripped) = s.strip_prefix('B') { + Some(format!("0b{stripped}")) + } else if let Some(stripped) = s.strip_prefix('O') { + Some(format!("0o{stripped}")) + } else if let Some(stripped) = s.strip_prefix('X') { + Some(format!("0x{stripped}")) + } else { + None + } + } + + let token::Lit { kind, suffix, .. } = lit; + match err { + // `LexerError` *is* an error, but it was already reported + // by lexer, so here we don't report it the second time. + LitError::LexerError => {} + LitError::InvalidSuffix => { + self.tcx.sess.parse_sess.expect_no_suffix( + span, + &format!("{} {} literal", kind.article(), kind.descr()), + suffix, + ); + } + LitError::InvalidIntSuffix => { + let suf = suffix.expect("suffix error with no suffix"); + let suf = suf.as_str(); + if looks_like_width_suffix(&['i', 'u'], &suf) { + // If it looks like a width, try to be helpful. + self.tcx.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); + } else if let Some(fixed) = fix_base_capitalisation(suf) { + self.tcx.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); + } else { + self.tcx + .sess + .emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); + } + } + LitError::InvalidFloatSuffix => { + let suf = suffix.expect("suffix error with no suffix"); + let suf = suf.as_str(); + if looks_like_width_suffix(&['f'], suf) { + // If it looks like a width, try to be helpful. + self.tcx + .sess + .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); + } else { + self.tcx + .sess + .emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); + } + } + LitError::NonDecimalFloat(base) => { + let descr = match base { + 16 => "hexadecimal", + 8 => "octal", + 2 => "binary", + _ => unreachable!(), + }; + self.tcx + .sess + .struct_span_err(span, &format!("{descr} float literal is not supported")) + .span_label(span, "not supported") + .emit(); + } + LitError::IntTooLarge => { + self.tcx.sess.emit_err(IntLiteralTooLarge { span }); + } + } + } + fn lower_unop(&mut self, u: UnOp) -> hir::UnOp { match u { UnOp::Deref => hir::UnOp::Deref, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index e9c05eb5f455f..96dfe9a9c8dbe 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -952,7 +952,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } else { Lit { token_lit: token::Lit::new(token::LitKind::Err, kw::Empty, None), - kind: LitKind::Err, span: DUMMY_SP, } }; diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 753f62dd589d0..3838bd40318ba 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -1,7 +1,7 @@ //! Parsing and validation of builtin attributes use rustc_ast as ast; -use rustc_ast::{Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; +use rustc_ast::{token, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem, NodeId}; use rustc_ast_pretty::pprust; use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg}; use rustc_macros::HashStable_Generic; @@ -658,7 +658,8 @@ pub fn eval_condition( ast::MetaItemKind::List(ref mis) if cfg.name_or_empty() == sym::version => { try_gate_cfg(sym::version, cfg.span, sess, features); let (min_version, span) = match &mis[..] { - [NestedMetaItem::Literal(Lit { kind: LitKind::Str(sym, ..), span, .. })] => { + [NestedMetaItem::Literal(Lit { token_lit, span, .. })] + if let Ok(LitKind::Str(sym, ..)) = LitKind::from_token_lit(*token_lit) => { (sym, span) } [ @@ -759,13 +760,13 @@ pub fn eval_condition( sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span }); true } - MetaItemKind::NameValue(ref lit) if !lit.kind.is_str() => { + MetaItemKind::NameValue(ref lit) if !lit.token_lit.is_str() => { handle_errors( sess, lit.span, AttrError::UnsupportedLiteral( UnsupportedLiteralReason::CfgString, - lit.kind.is_bytestr(), + lit.token_lit.is_bytestr(), ), ); true @@ -844,7 +845,7 @@ where lit.span, AttrError::UnsupportedLiteral( UnsupportedLiteralReason::DeprecatedString, - lit.kind.is_bytestr(), + lit.token_lit.is_bytestr(), ), ); } else { @@ -1009,13 +1010,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { let mut literal_error = None; if name == sym::align { recognised = true; - match parse_alignment(&value.kind) { + match parse_alignment(value.token_lit) { Ok(literal) => acc.push(ReprAlign(literal)), Err(message) => literal_error = Some(message), }; } else if name == sym::packed { recognised = true; - match parse_alignment(&value.kind) { + match parse_alignment(value.token_lit) { Ok(literal) => acc.push(ReprPacked(literal)), Err(message) => literal_error = Some(message), }; @@ -1045,7 +1046,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec { repr_arg: &name, cause: IncorrectReprFormatGenericCause::from_lit_kind( item.span(), - &value.kind, + LitKind::from_token_lit(value.token_lit).ok(), &name, ), }); @@ -1198,11 +1199,13 @@ fn allow_unstable<'a>( }) } -pub fn parse_alignment(node: &ast::LitKind) -> Result { - if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node { - if literal.is_power_of_two() { +pub fn parse_alignment(token_lit: token::Lit) -> Result { + if let Ok(ast::LitKind::Int(n, ast::LitIntType::Unsuffixed)) = + ast::LitKind::from_token_lit(token_lit) + { + if n.is_power_of_two() { // rustc_middle::ty::layout::Align restricts align to <= 2^29 - if *literal <= 1 << 29 { Ok(*literal as u32) } else { Err("larger than 2^29") } + if n <= 1 << 29 { Ok(n as u32) } else { Err("larger than 2^29") } } else { Err("not a power of two") } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 52e65a9c7743d..d5252ab503cd7 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,6 +4,7 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. +#![feature(if_let_guard)] #![feature(let_chains)] #![cfg_attr(bootstrap, feature(let_else))] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs index 085175d4bed1f..19e00805fab92 100644 --- a/compiler/rustc_attr/src/session_diagnostics.rs +++ b/compiler/rustc_attr/src/session_diagnostics.rs @@ -306,12 +306,12 @@ pub(crate) enum IncorrectReprFormatGenericCause<'a> { } impl<'a> IncorrectReprFormatGenericCause<'a> { - pub fn from_lit_kind(span: Span, kind: &ast::LitKind, name: &'a str) -> Option { + pub fn from_lit_kind(span: Span, kind: Option, name: &'a str) -> Option { match kind { - ast::LitKind::Int(int, ast::LitIntType::Unsuffixed) => { - Some(Self::Int { span, name, int: *int }) + Some(ast::LitKind::Int(int, ast::LitIntType::Unsuffixed)) => { + Some(Self::Int { span, name, int }) } - ast::LitKind::Str(symbol, _) => Some(Self::Symbol { span, name, symbol: *symbol }), + Some(ast::LitKind::Str(symbol, _)) => Some(Self::Symbol { span, name, symbol }), _ => None, } } diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index a1051d990b14b..618270bae7dd6 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -172,7 +172,7 @@ pub fn parse_asm_args<'a>( // If it can't possibly expand to a string, provide diagnostics here to include other // things it could have been. match template.kind { - ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} + ast::ExprKind::Lit(ast::Lit { token_lit, .. }) if token_lit.is_str() => {} ast::ExprKind::MacCall(..) => {} _ => { let errstr = if is_global_asm { diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 41f4e8c234d5a..33c67ed6bd937 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -18,31 +18,34 @@ pub fn expand_concat( let mut has_errors = false; for e in es { match e.kind { - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _) => { - accumulator.push_str(s.as_str()); + ast::ExprKind::Lit(ref lit) => { + match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Str(ref s, _) | ast::LitKind::Float(ref s, _)) => { + accumulator.push_str(s.as_str()); + } + Ok(ast::LitKind::Char(c)) => { + accumulator.push(c); + } + Ok(ast::LitKind::Int(i, _)) => { + accumulator.push_str(&i.to_string()); + } + Ok(ast::LitKind::Bool(b)) => { + accumulator.push_str(&b.to_string()); + } + Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { + cx.span_err(e.span, "cannot concatenate a byte string literal"); + has_errors = true; + } + Ok(ast::LitKind::Err) => { + has_errors = true; + } + Err(_) => { + // "invalid literal" is not very helpful. + cx.span_err(e.span, "cannot concatenate an invalid literal"); + has_errors = true; + } } - ast::LitKind::Char(c) => { - accumulator.push(c); - } - ast::LitKind::Int( - i, - ast::LitIntType::Unsigned(_) - | ast::LitIntType::Signed(_) - | ast::LitIntType::Unsuffixed, - ) => { - accumulator.push_str(&i.to_string()); - } - ast::LitKind::Bool(b) => { - accumulator.push_str(&b.to_string()); - } - ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..) => { - cx.span_err(e.span, "cannot concatenate a byte string literal"); - } - ast::LitKind::Err => { - has_errors = true; - } - }, + } ast::ExprKind::Err => { has_errors = true; } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 66e86bf218267..4c252327467ac 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -4,16 +4,13 @@ use rustc_errors::Applicability; use rustc_expand::base::{self, DummyResult}; /// Emits errors for literal expressions that are invalid inside and outside of an array. -fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_nested: bool) { - let ast::ExprKind::Lit(lit) = &expr.kind else { - unreachable!(); - }; - match lit.kind { - ast::LitKind::Char(_) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate character literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { +fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, lit: &ast::Lit, is_nested: bool) { + match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Char(_)) => { + let mut err = cx.struct_span_err(lit.span, "cannot concatenate character literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(lit.span) { err.span_suggestion( - expr.span, + lit.span, "try using a byte character", format!("b{}", snippet), Applicability::MachineApplicable, @@ -21,13 +18,13 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne .emit(); } } - ast::LitKind::Str(_, _) => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate string literals"); + Ok(ast::LitKind::Str(_, _)) => { + let mut err = cx.struct_span_err(lit.span, "cannot concatenate string literals"); // suggestion would be invalid if we are nested if !is_nested { - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(lit.span) { err.span_suggestion( - expr.span, + lit.span, "try using a byte string", format!("b{}", snippet), Applicability::MachineApplicable, @@ -36,18 +33,18 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne } err.emit(); } - ast::LitKind::Float(_, _) => { - cx.span_err(expr.span, "cannot concatenate float literals"); + Ok(ast::LitKind::Float(_, _)) => { + cx.span_err(lit.span, "cannot concatenate float literals"); } - ast::LitKind::Bool(_) => { - cx.span_err(expr.span, "cannot concatenate boolean literals"); + Ok(ast::LitKind::Bool(_)) => { + cx.span_err(lit.span, "cannot concatenate boolean literals"); } - ast::LitKind::Err => {} - ast::LitKind::Int(_, _) if !is_nested => { - let mut err = cx.struct_span_err(expr.span, "cannot concatenate numeric literals"); - if let Ok(snippet) = cx.sess.source_map().span_to_snippet(expr.span) { + Ok(ast::LitKind::Err) => {} + Ok(ast::LitKind::Int(_, _)) if !is_nested => { + let mut err = cx.struct_span_err(lit.span, "cannot concatenate numeric literals"); + if let Ok(snippet) = cx.sess.source_map().span_to_snippet(lit.span) { err.span_suggestion( - expr.span, + lit.span, "try wrapping the number in an array", format!("[{}]", snippet), Applicability::MachineApplicable, @@ -55,17 +52,20 @@ fn invalid_type_err(cx: &mut base::ExtCtxt<'_>, expr: &P, is_ne } err.emit(); } - ast::LitKind::Int( + Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - ) => { + )) => { assert!(val > u8::MAX.into()); // must be an error - cx.span_err(expr.span, "numeric literal is out of bounds"); + cx.span_err(lit.span, "numeric literal is out of bounds"); + } + Ok(ast::LitKind::Int(_, _)) => { + cx.span_err(lit.span, "numeric literal is not a `u8`"); } - ast::LitKind::Int(_, _) => { - cx.span_err(expr.span, "numeric literal is not a `u8`"); + Ok(ast::LitKind::Byte(_) | ast::LitKind::ByteStr(_)) => unreachable!(), + Err(_) => { + cx.span_err(lit.span, "cannot concatenate invalid literals"); } - _ => unreachable!(), } } @@ -83,14 +83,14 @@ fn handle_array_element( *has_errors = true; None } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Int( + ast::ExprKind::Lit(ref lit) => match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - ) if val <= u8::MAX.into() => Some(val as u8), + )) if val <= u8::MAX.into() => Some(val as u8), - ast::LitKind::Byte(val) => Some(val), - ast::LitKind::ByteStr(_) => { + Ok(ast::LitKind::Byte(val)) => Some(val), + Ok(ast::LitKind::ByteStr(_)) => { if !*has_errors { cx.struct_span_err(expr.span, "cannot concatenate doubly nested array") .note("byte strings are treated as arrays of bytes") @@ -102,7 +102,7 @@ fn handle_array_element( } _ => { if !*has_errors { - invalid_type_err(cx, expr, true); + invalid_type_err(cx, lit, true); } *has_errors = true; None @@ -138,9 +138,9 @@ pub fn expand_concat_bytes( } } ast::ExprKind::Repeat(ref expr, ref count) => { - if let ast::ExprKind::Lit(ast::Lit { - kind: ast::LitKind::Int(count_val, _), .. - }) = count.value.kind + if let ast::ExprKind::Lit(lit) = &count.value.kind + && let Ok(ast::LitKind::Int(count_val, _)) = + ast::LitKind::from_token_lit(lit.token_lit) { if let Some(elem) = handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) @@ -153,16 +153,16 @@ pub fn expand_concat_bytes( cx.span_err(count.value.span, "repeat count is not a positive number"); } } - ast::ExprKind::Lit(ref lit) => match lit.kind { - ast::LitKind::Byte(val) => { + ast::ExprKind::Lit(ref lit) => match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Byte(val)) => { accumulator.push(val); } - ast::LitKind::ByteStr(ref bytes) => { + Ok(ast::LitKind::ByteStr(ref bytes)) => { accumulator.extend_from_slice(&bytes); } _ => { if !has_errors { - invalid_type_err(cx, &e, false); + invalid_type_err(cx, lit, false); } has_errors = true; } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index e1da3ecdec7f4..04ab728c6189d 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1222,9 +1222,9 @@ pub fn expr_to_spanned_string<'a>( let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); Err(match expr.kind { - ast::ExprKind::Lit(ref l) => match l.kind { - ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)), - ast::LitKind::ByteStr(_) => { + ast::ExprKind::Lit(ref l) => match ast::LitKind::from_token_lit(l.token_lit) { + Ok(ast::LitKind::Str(s, style)) => return Ok((s, style, expr.span)), + Ok(ast::LitKind::ByteStr(_)) => { let mut err = cx.struct_span_err(l.span, err_msg); err.span_suggestion( expr.span.shrink_to_lo(), @@ -1234,7 +1234,8 @@ pub fn expr_to_spanned_string<'a>( ); Some((err, true)) } - ast::LitKind::Err => None, + Ok(ast::LitKind::Err) => None, + Err(_) => None, _ => Some((cx.struct_span_err(l.span, err_msg), false)), }, ast::ExprKind::Err => None, diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index 50d2be3cee5e0..12c162eb23482 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -330,7 +330,7 @@ impl<'a> ExtCtxt<'a> { } fn expr_lit(&self, span: Span, lit_kind: ast::LitKind) -> P { - let lit = ast::Lit::from_lit_kind(lit_kind, span); + let lit = ast::Lit { token_lit: lit_kind.to_token_lit(), span }; self.expr(span, ast::ExprKind::Lit(lit)) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 949bd02ad6839..9288b00bfe53a 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -109,7 +109,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option {} - MetaItemKind::NameValue(lit) if !lit.kind.is_str() => { + MetaItemKind::NameValue(lit) if !lit.token_lit.is_str() => { error!("argument value must be a string"); } MetaItemKind::NameValue(..) | MetaItemKind::Word => { @@ -190,8 +190,9 @@ pub fn parse_check_cfg(specs: Vec) -> CheckCfg { .or_insert_with(|| FxHashSet::default()); for val in values { - if let Some(LitKind::Str(s, _)) = - val.literal().map(|lit| &lit.kind) + if let Some(Ok(LitKind::Str(s, _))) = val + .literal() + .map(|lit| LitKind::from_token_lit(lit.token_lit)) { ident_values.insert(s.to_string()); } else { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 0ff2ef5cda391..e91f97ed1471d 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -100,7 +100,7 @@ impl EarlyLintPass for WhileTrue { fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) { if let ast::ExprKind::While(cond, _, label) = &e.kind { if let ast::ExprKind::Lit(ref lit) = pierce_parens(cond).kind { - if let ast::LitKind::Bool(true) = lit.kind { + if lit.token_lit.is_bool_true() { if !lit.span.from_expansion() { let condition_span = e.span.with_hi(cond.span.hi()); cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| { diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 8f22221324a6e..4afb3323228df 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -120,16 +120,16 @@ impl EarlyLintPass for HiddenUnicodeCodepoints { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { // byte strings are already handled well enough by `EscapeError::NonAsciiCharInByteString` let (text, span, padding) = match &expr.kind { - ast::ExprKind::Lit(ast::Lit { token_lit, kind, span }) => { + ast::ExprKind::Lit(ast::Lit { token_lit, span, .. }) => { let text = token_lit.symbol; if !contains_text_flow_control_chars(text.as_str()) { return; } - let padding = match kind { + let padding = match token_lit.kind { // account for `"` or `'` - ast::LitKind::Str(_, ast::StrStyle::Cooked) | ast::LitKind::Char(_) => 1, + ast::token::LitKind::Str | ast::token::LitKind::Char => 1, // account for `r###"` - ast::LitKind::Str(_, ast::StrStyle::Raw(val)) => *val as u32 + 2, + ast::token::LitKind::StrRaw(n) => n as u32 + 2, _ => return, }; (text, span, padding) diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index dd1fc5916dbff..84a52528943eb 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -462,7 +462,8 @@ impl LateLintPass<'_> for BadOptAccess { let Some(items) = attr.meta_item_list() && let Some(item) = items.first() && let Some(literal) = item.literal() && - let ast::LitKind::Str(val, _) = literal.kind + let Ok(ast::LitKind::Str(val, _)) = + ast::LitKind::from_token_lit(literal.token_lit) { cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| { lint.build(val.as_str()).emit(); } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a9ba2ad1d101d..cb68344c9ae18 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -593,7 +593,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { ast::MetaItemKind::Word => {} // actual lint names handled later ast::MetaItemKind::NameValue(ref name_value) => { if item.path == sym::reason { - if let ast::LitKind::Str(rationale, _) = name_value.kind { + if let Ok(ast::LitKind::Str(rationale, _)) = + ast::LitKind::from_token_lit(name_value.token_lit) + { if !self.sess.features_untracked().lint_reasons { feature_err( &self.sess.parse_sess, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 768ad84838b15..c563b2bd7f782 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -340,7 +340,9 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { .and_then(|attr| attr.meta()) .and_then(|meta| { meta.name_value_literal().and_then(|lit| { - if let ast::LitKind::Str(name, ..) = lit.kind { + if let Ok(ast::LitKind::Str(name, ..)) = + ast::LitKind::from_token_lit(lit.token_lit) + { // Discard the double quotes surrounding the literal. let sp = cx .sess() diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 10c5933574ffa..fa11914b35bcc 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1198,13 +1198,9 @@ impl<'tcx> TyCtxt<'tcx> { return Bound::Unbounded; }; debug!("layout_scalar_valid_range: attr={:?}", attr); - if let Some( - &[ - ast::NestedMetaItem::Literal(ast::Lit { - kind: ast::LitKind::Int(a, _), .. - }), - ], - ) = attr.meta_item_list().as_deref() + if let Some(&[ast::NestedMetaItem::Literal(ast::Lit { token_lit, .. })]) = + attr.meta_item_list().as_deref() + && let Ok(ast::LitKind::Int(a, _)) = ast::LitKind::from_token_lit(token_lit) { Bound::Included(a) } else { diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 5fd69b15ecc04..e96ce5c3870d6 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -336,7 +336,7 @@ impl<'a> Parser<'a> { let lit = self.parse_lit()?; debug!("checking if {:?} is unusuffixed", lit); - if !lit.kind.is_unsuffixed() { + if lit.token_lit.suffix.is_some() { self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes") .help( "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \ diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index be524db785bc0..43af63bfe5f91 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -499,61 +499,6 @@ pub(crate) struct FloatLiteralRequiresIntegerPart { pub correct: String, } -#[derive(SessionDiagnostic)] -#[diag(parser::invalid_int_literal_width)] -#[help] -pub(crate) struct InvalidIntLiteralWidth { - #[primary_span] - pub span: Span, - pub width: String, -} - -#[derive(SessionDiagnostic)] -#[diag(parser::invalid_num_literal_base_prefix)] -#[note] -pub(crate) struct InvalidNumLiteralBasePrefix { - #[primary_span] - #[suggestion(applicability = "maybe-incorrect", code = "{fixed}")] - pub span: Span, - pub fixed: String, -} - -#[derive(SessionDiagnostic)] -#[diag(parser::invalid_num_literal_suffix)] -#[help] -pub(crate) struct InvalidNumLiteralSuffix { - #[primary_span] - #[label] - pub span: Span, - pub suffix: String, -} - -#[derive(SessionDiagnostic)] -#[diag(parser::invalid_float_literal_width)] -#[help] -pub(crate) struct InvalidFloatLiteralWidth { - #[primary_span] - pub span: Span, - pub width: String, -} - -#[derive(SessionDiagnostic)] -#[diag(parser::invalid_float_literal_suffix)] -#[help] -pub(crate) struct InvalidFloatLiteralSuffix { - #[primary_span] - #[label] - pub span: Span, - pub suffix: String, -} - -#[derive(SessionDiagnostic)] -#[diag(parser::int_literal_too_large)] -pub(crate) struct IntLiteralTooLarge { - #[primary_span] - pub span: Span, -} - #[derive(SessionDiagnostic)] #[diag(parser::missing_semicolon_before_array)] pub(crate) struct MissingSemicolonBeforeArray { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index ed37ede65d514..39f33def0df87 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -16,18 +16,12 @@ use super::{ SemiColonMode, SeqSep, TokenExpectType, TokenType, TrailingToken, }; use crate::maybe_recover_from_interpolated_ty_qpath; -use crate::parser::diagnostics::{ - IntLiteralTooLarge, InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, - InvalidIntLiteralWidth, InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, - MissingCommaAfterMatchArm, -}; - +use crate::parser::diagnostics::MissingCommaAfterMatchArm; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::tokenstream::Spacing; use rustc_ast::util::classify; -use rustc_ast::util::literal::LitError; use rustc_ast::util::parser::{prec_let_scrutinee_needs_par, AssocOp, Fixity}; use rustc_ast::visit::Visitor; use rustc_ast::{self as ast, AttrStyle, AttrVec, CaptureBy, ExprField, Lit, UnOp, DUMMY_NODE_ID}; @@ -1720,8 +1714,8 @@ impl<'a> Parser<'a> { /// and returns `None` if the next token is not literal at all. pub fn parse_str_lit(&mut self) -> Result> { match self.parse_opt_lit() { - Some(lit) => match lit.kind { - ast::LitKind::Str(symbol_unescaped, style) => Ok(ast::StrLit { + Some(lit) => match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Str(symbol_unescaped, style)) => Ok(ast::StrLit { style, symbol: lit.token_lit.symbol, suffix: lit.token_lit.suffix, @@ -1784,25 +1778,11 @@ impl<'a> Parser<'a> { let token = recovered.as_ref().unwrap_or(&self.token); match Lit::from_token(token) { - Ok(lit) => { + Some(lit) => { self.bump(); Some(lit) } - Err(LitError::NotLiteral) => None, - Err(err) => { - let span = token.span; - let token::Literal(lit) = token.kind else { - unreachable!(); - }; - self.bump(); - self.report_lit_error(err, lit, span); - // Pack possible quotes and prefixes from the original literal into - // the error literal's symbol so they can be pretty-printed faithfully. - let suffixless_lit = token::Lit::new(lit.kind, lit.symbol, None); - let symbol = Symbol::intern(&suffixless_lit.to_string()); - let lit = token::Lit::new(token::Err, symbol, lit.suffix); - Some(Lit::from_token_lit(lit, span).unwrap_or_else(|_| unreachable!())) - } + None => None, } } @@ -1813,80 +1793,6 @@ impl<'a> Parser<'a> { }); } - fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { - // Checks if `s` looks like i32 or u1234 etc. - fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { - s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) - } - - // Try to lowercase the prefix if it's a valid base prefix. - fn fix_base_capitalisation(s: &str) -> Option { - if let Some(stripped) = s.strip_prefix('B') { - Some(format!("0b{stripped}")) - } else if let Some(stripped) = s.strip_prefix('O') { - Some(format!("0o{stripped}")) - } else if let Some(stripped) = s.strip_prefix('X') { - Some(format!("0x{stripped}")) - } else { - None - } - } - - let token::Lit { kind, suffix, .. } = lit; - match err { - // `NotLiteral` is not an error by itself, so we don't report - // it and give the parser opportunity to try something else. - LitError::NotLiteral => {} - // `LexerError` *is* an error, but it was already reported - // by lexer, so here we don't report it the second time. - LitError::LexerError => {} - LitError::InvalidSuffix => { - self.expect_no_suffix( - span, - &format!("{} {} literal", kind.article(), kind.descr()), - suffix, - ); - } - LitError::InvalidIntSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); - if looks_like_width_suffix(&['i', 'u'], &suf) { - // If it looks like a width, try to be helpful. - self.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); - } else if let Some(fixed) = fix_base_capitalisation(suf) { - self.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); - } else { - self.sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); - } - } - LitError::InvalidFloatSuffix => { - let suf = suffix.expect("suffix error with no suffix"); - let suf = suf.as_str(); - if looks_like_width_suffix(&['f'], suf) { - // If it looks like a width, try to be helpful. - self.sess - .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); - } else { - self.sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); - } - } - LitError::NonDecimalFloat(base) => { - let descr = match base { - 16 => "hexadecimal", - 8 => "octal", - 2 => "binary", - _ => unreachable!(), - }; - self.struct_span_err(span, &format!("{descr} float literal is not supported")) - .span_label(span, "not supported") - .emit(); - } - LitError::IntTooLarge => { - self.sess.emit_err(IntLiteralTooLarge { span }); - } - } - } - pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { if let Some(suf) = suffix { let mut err = if kind == "a tuple index" diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4cb198561e0ad..6e1212e963ebc 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1381,8 +1381,8 @@ impl<'a> Parser<'a> { fn parse_abi(&mut self) -> Option { match self.parse_str_lit() { Ok(str_lit) => Some(str_lit), - Err(Some(lit)) => match lit.kind { - ast::LitKind::Err => None, + Err(Some(lit)) => match lit.token_lit.kind { + token::LitKind::Err => None, _ => { self.struct_span_err(lit.span, "non-string ABI literal") .span_suggestion( diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 47477898b240e..3f0ed753acad8 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -50,7 +50,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta } MacArgs::Eq(_, MacArgsEq::Ast(expr)) => { if let ast::ExprKind::Lit(lit) = &expr.kind { - if !lit.kind.is_unsuffixed() { + if lit.token_lit.suffix.is_some() { let mut err = sess.span_diagnostic.struct_span_err( lit.span, "suffixed literals are not allowed in attributes", @@ -101,7 +101,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte match meta { MetaItemKind::Word => template.word, MetaItemKind::List(..) => template.list.is_some(), - MetaItemKind::NameValue(lit) if lit.kind.is_str() => template.name_value_str.is_some(), + MetaItemKind::NameValue(lit) if lit.token_lit.is_str() => template.name_value_str.is_some(), MetaItemKind::NameValue(..) => false, } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index b3f15ba7cbf25..d08988a6d4310 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -5,7 +5,7 @@ //! item. use crate::errors; -use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; +use rustc_ast::{ast, token, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; use rustc_expand::base::resolve_path; @@ -722,8 +722,8 @@ impl CheckAttrVisitor<'_> { let mut errors = 0; for v in values { match v.literal() { - Some(l) => match l.kind { - LitKind::Str(s, _) => { + Some(l) => match LitKind::from_token_lit(l.token_lit) { + Ok(LitKind::Str(s, _)) => { if !self.check_doc_alias_value(v, s, hir_id, target, true, aliases) { errors += 1; } @@ -1342,7 +1342,13 @@ impl CheckAttrVisitor<'_> { return false; }; - if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) { + if matches!( + &list[..], + &[NestedMetaItem::Literal(Lit { + token_lit: token::Lit { kind: token::LitKind::Integer, .. }, + .. + })] + ) { true } else { self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span }); @@ -1403,8 +1409,10 @@ impl CheckAttrVisitor<'_> { let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128; let mut invalid_args = vec![]; for meta in list { - if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { - if *val >= arg_count { + if let Some(Ok(LitKind::Int(val, _))) = + meta.literal().map(|lit| LitKind::from_token_lit(lit.token_lit)) + { + if val >= arg_count { let span = meta.span(); self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed { span, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 54a7f416ce64c..d6dd219a4e77f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1960,8 +1960,8 @@ impl<'a> Resolver<'a> { .find(|a| a.has_name(sym::rustc_legacy_const_generics))?; let mut ret = Vec::new(); for meta in attr.meta_item_list()? { - match meta.literal()?.kind { - LitKind::Int(a, _) => ret.push(a as usize), + match LitKind::from_token_lit(meta.literal()?.token_lit) { + Ok(LitKind::Int(a, _)) => ret.push(a as usize), _ => panic!("invalid arg index"), } } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 0389b2a06a340..ee9d4b5e4ef6e 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -19,7 +19,7 @@ use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; use rustc_span::hygiene::ExpnId; use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::{Span, Symbol}; +use rustc_span::{sym, Span, Symbol}; use rustc_ast::attr::AttrIdGenerator; use std::str; @@ -333,6 +333,43 @@ impl ParseSess { ); } + #[allow(rustc::diagnostic_outside_of_impl)] + #[allow(rustc::untranslatable_diagnostic)] + pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option) { + if let Some(suf) = suffix { + let mut err = if kind == "a tuple index" + && [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suf) + { + // #59553: warn instead of reject out of hand to allow the fix to percolate + // through the ecosystem when people fix their macros + let mut err = self + .span_diagnostic + .struct_span_warn(sp, &format!("suffixes on {kind} are invalid")); + err.note(&format!( + "`{}` is *temporarily* accepted on tuple index fields as it was \ + incorrectly accepted on stable for a few releases", + suf, + )); + err.help( + "on proc macros, you'll want to use `syn::Index::from` or \ + `proc_macro::Literal::*_unsuffixed` for code that will desugar \ + to tuple field access", + ); + err.note( + "see issue #60210 \ + for more information", + ); + err + } else { + self.span_diagnostic + .struct_span_err(sp, &format!("suffixes on {kind} are invalid")) + .forget_guarantee() + }; + err.span_label(sp, format!("invalid suffix `{suf}`")); + err.emit(); + } + } + pub fn save_proc_macro_span(&self, span: Span) -> usize { let mut spans = self.proc_macro_quoted_spans.lock(); spans.push(span); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index afc8a9600ad48..31910dd4dbd8a 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -3098,7 +3098,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { Some(items) => match items.as_slice() { [item] => match item.name_value_literal() { Some((sym::align, literal)) => { - let alignment = rustc_attr::parse_alignment(&literal.kind); + let alignment = rustc_attr::parse_alignment(literal.token_lit); match alignment { Ok(align) => Some(align), @@ -3309,7 +3309,7 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { - use rustc_ast::{Lit, LitIntType, LitKind}; + use rustc_ast::{LitIntType, LitKind}; if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" { feature_err( &tcx.sess.parse_sess, @@ -3332,7 +3332,10 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { } _ => None, }; - if let Some(Lit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) = sole_meta_list { + if let Some(lit) = sole_meta_list + && let Ok(LitKind::Int(ordinal, LitIntType::Unsuffixed)) = + LitKind::from_token_lit(lit.token_lit) + { // According to the table at https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, // the ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import information @@ -3345,8 +3348,8 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option { // library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I don't know yet // if the resulting EXE runs, as I haven't yet built the necessary DLL -- see earlier comment // about LINK.EXE failing.) - if *ordinal <= u16::MAX as u128 { - Some(*ordinal as u16) + if ordinal <= u16::MAX as u128 { + Some(ordinal as u16) } else { let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal); tcx.sess diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index f33f5d27d1a9f..3ed643b4c95b8 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -74,18 +74,20 @@ impl Cfg { let cfg = Cfg::Cfg(name, None); if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } } - MetaItemKind::NameValue(ref lit) => match lit.kind { - LitKind::Str(value, _) => { - let cfg = Cfg::Cfg(name, Some(value)); - if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } + MetaItemKind::NameValue(ref lit) => { + match LitKind::from_token_lit(lit.token_lit) { + Ok(LitKind::Str(value, _)) => { + let cfg = Cfg::Cfg(name, Some(value)); + if exclude.contains(&cfg) { Ok(None) } else { Ok(Some(cfg)) } + } + _ => Err(InvalidCfgError { + // FIXME: if the main #[cfg] syntax decided to support non-string literals, + // this should be changed as well. + msg: "value of cfg option should be a string literal", + span: lit.span, + }), } - _ => Err(InvalidCfgError { - // FIXME: if the main #[cfg] syntax decided to support non-string literals, - // this should be changed as well. - msg: "value of cfg option should be a string literal", - span: lit.span, - }), - }, + } MetaItemKind::List(ref items) => { let orig_len = items.len(); let sub_cfgs = diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 375737e9bc4ea..56a9fa2eb241c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -857,8 +857,8 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[ast::Attrib .filter_map(|a| a.meta_item_list()) { for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.literal()).enumerate() { - match literal.kind { - ast::LitKind::Int(a, _) => { + match ast::LitKind::from_token_lit(literal.token_lit) { + Ok(ast::LitKind::Int(a, _)) => { let gen = func.generics.params.remove(0); if let GenericParamDef { name, kind: GenericParamDefKind::Const { ty, .. } } = gen diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index f973fd0889ebc..fd212c3a2cfc2 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1268,8 +1268,8 @@ impl Attributes { for attr in self.other_attrs.lists(sym::doc).filter(|a| a.has_name(sym::alias)) { if let Some(values) = attr.meta_item_list() { for l in values { - match l.literal().unwrap().kind { - ast::LitKind::Str(s, _) => { + match ast::LitKind::from_token_lit(l.literal().unwrap().token_lit) { + Ok(ast::LitKind::Str(s, _)) => { aliases.insert(s); } _ => unreachable!(), diff --git a/src/test/ui/codemap_tests/unicode_2.stderr b/src/test/ui/codemap_tests/unicode_2.stderr index a776a4a1e7e13..19aae1d3c9511 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/extenv/issue-55897.rs b/src/test/ui/extenv/issue-55897.rs index 64c4107e89875..67f774e2e6ccb 100644 --- a/src/test/ui/extenv/issue-55897.rs +++ b/src/test/ui/extenv/issue-55897.rs @@ -14,7 +14,7 @@ mod nonexistent_env { mod erroneous_literal { include!(concat!("NON_EXISTENT"suffix, "/data.rs")); - //~^ ERROR suffixes on a string literal are invalid + //~^ ERROR cannot concatenate an invalid literal } fn main() {} diff --git a/src/test/ui/extenv/issue-55897.stderr b/src/test/ui/extenv/issue-55897.stderr index d2ac0b83016f2..026ea9454850b 100644 --- a/src/test/ui/extenv/issue-55897.stderr +++ b/src/test/ui/extenv/issue-55897.stderr @@ -6,11 +6,11 @@ LL | include!(concat!(env!("NON_EXISTENT"), "/data.rs")); | = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) -error: suffixes on a string literal are invalid +error: cannot concatenate an invalid literal --> $DIR/issue-55897.rs:16:22 | LL | include!(concat!("NON_EXISTENT"suffix, "/data.rs")); - | ^^^^^^^^^^^^^^^^^^^^ invalid suffix `suffix` + | ^^^^^^^^^^^^^^^^^^^^ error[E0432]: unresolved import `prelude` --> $DIR/issue-55897.rs:1:5 diff --git a/src/test/ui/lowering/literals.rs b/src/test/ui/lowering/literals.rs index 7600a4aab4fc8..c3123f224e7f1 100644 --- a/src/test/ui/lowering/literals.rs +++ b/src/test/ui/lowering/literals.rs @@ -6,29 +6,32 @@ #![feature(concat_bytes)] #[repr(align(340282366920938463463374607431768211456))] -//~^ ERROR integer literal is too large +//~^ ERROR invalid `repr(align)` attribute: not an unsuffixed integer [E0589] +//~^^ ERROR invalid `repr(align)` attribute: not an unsuffixed integer [E0589] struct S1(u32); -#[repr(align(4u7))] //~ ERROR invalid width `7` for integer literal +#[repr(align(4u7))] +//~^ ERROR suffixed literals are not allowed in attributes +//~^^ ERROR invalid `repr(align)` attribute: not an unsuffixed integer [E0589] +//~^^^ ERROR invalid `repr(align)` attribute: not an unsuffixed integer [E0589] struct S2(u32); #[doc = "documentation"suffix] -//~^ ERROR suffixes on a string literal are invalid -//~^^ ERROR attribute must be of the form -//~^^^ WARNING this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~^ ERROR suffixed literals are not allowed in attributes struct D; -#[doc(alias = 0u7)] //~ ERROR invalid width `7` for integer literal +#[doc(alias = 0u7)] +//~^ ERROR doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` +//~^^ ERROR suffixed literals are not allowed in attributes struct E; fn main() { println!(concat!( - "abc"suffix, //~ ERROR suffixes on a string literal are invalid - "blah"foo, //~ ERROR suffixes on a string literal are invalid - 3u33, //~ ERROR invalid width `33` for integer literal + "abc"suffix, //~ ERROR cannot concatenate an invalid literal + "blah"foo, //~ ERROR cannot concatenate an invalid literal + 3u33, //~ ERROR cannot concatenate an invalid literal )); let x = concat_bytes!("foo"blah, 3u33); - //~^ ERROR suffixes on a string literal are invalid - //~^^ ERROR invalid width `33` for integer literal + //~^ ERROR cannot concatenate invalid literals } diff --git a/src/test/ui/lowering/literals.stderr b/src/test/ui/lowering/literals.stderr index 467073ef09adb..7ebeb4a742f43 100644 --- a/src/test/ui/lowering/literals.stderr +++ b/src/test/ui/lowering/literals.stderr @@ -1,74 +1,81 @@ -error: suffixes on a string literal are invalid - --> $DIR/literals.rs:15:9 - | -LL | #[doc = "documentation"suffix] - | ^^^^^^^^^^^^^^^^^^^^^ invalid suffix `suffix` - -error: suffixes on a string literal are invalid - --> $DIR/literals.rs:26:9 +error: cannot concatenate an invalid literal + --> $DIR/literals.rs:30:9 | LL | "abc"suffix, - | ^^^^^^^^^^^ invalid suffix `suffix` + | ^^^^^^^^^^^ -error: suffixes on a string literal are invalid - --> $DIR/literals.rs:27:9 +error: cannot concatenate an invalid literal + --> $DIR/literals.rs:31:9 | LL | "blah"foo, - | ^^^^^^^^^ invalid suffix `foo` + | ^^^^^^^^^ -error: invalid width `33` for integer literal - --> $DIR/literals.rs:28:9 +error: cannot concatenate an invalid literal + --> $DIR/literals.rs:32:9 | LL | 3u33, | ^^^^ - | - = help: valid widths are 8, 16, 32, 64 and 128 -error: suffixes on a string literal are invalid - --> $DIR/literals.rs:31:27 +error: cannot concatenate invalid literals + --> $DIR/literals.rs:35:27 | LL | let x = concat_bytes!("foo"blah, 3u33); - | ^^^^^^^^^ invalid suffix `blah` + | ^^^^^^^^^ -error: invalid width `33` for integer literal - --> $DIR/literals.rs:31:38 +error: suffixed literals are not allowed in attributes + --> $DIR/literals.rs:13:14 | -LL | let x = concat_bytes!("foo"blah, 3u33); - | ^^^^ +LL | #[repr(align(4u7))] + | ^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +error: suffixed literals are not allowed in attributes + --> $DIR/literals.rs:19:9 + | +LL | #[doc = "documentation"suffix] + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +error: suffixed literals are not allowed in attributes + --> $DIR/literals.rs:23:15 + | +LL | #[doc(alias = 0u7)] + | ^^^ | - = help: valid widths are 8, 16, 32, 64 and 128 + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) -error: integer literal is too large - --> $DIR/literals.rs:8:14 +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/literals.rs:8:8 | LL | #[repr(align(340282366920938463463374607431768211456))] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: invalid width `7` for integer literal - --> $DIR/literals.rs:12:14 +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/literals.rs:13:8 | LL | #[repr(align(4u7))] - | ^^^ - | - = help: valid widths are 8, 16, 32, 64 and 128 + | ^^^^^^^^^^ -error: invalid width `7` for integer literal - --> $DIR/literals.rs:21:15 +error: doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` + --> $DIR/literals.rs:23:7 | LL | #[doc(alias = 0u7)] - | ^^^ - | - = help: valid widths are 8, 16, 32, 64 and 128 + | ^^^^^^^^^^^ -error: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]` - --> $DIR/literals.rs:15:1 +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/literals.rs:8:8 | -LL | #[doc = "documentation"suffix] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[repr(align(340282366920938463463374607431768211456))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer + --> $DIR/literals.rs:13:8 | - = note: `#[deny(ill_formed_attribute_input)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 +LL | #[repr(align(4u7))] + | ^^^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 12 previous errors +For more information about this error, try `rustc --explain E0589`. diff --git a/src/test/ui/parser/bad-lit-suffixes.rs b/src/test/ui/parser/bad-lit-suffixes.rs index 446a0940559b3..5129544c77f65 100644 --- a/src/test/ui/parser/bad-lit-suffixes.rs +++ b/src/test/ui/parser/bad-lit-suffixes.rs @@ -1,9 +1,9 @@ extern - "C"suffix //~ ERROR suffixes on a string literal are invalid + "C"suffix //~ ERROR non-string ABI literal fn foo() {} extern - "C"suffix //~ ERROR suffixes on a string literal are invalid + "C"suffix //~ ERROR non-string ABI literal {} fn main() { diff --git a/src/test/ui/parser/bad-lit-suffixes.stderr b/src/test/ui/parser/bad-lit-suffixes.stderr index 9b596571481b9..5b8dfd4836634 100644 --- a/src/test/ui/parser/bad-lit-suffixes.stderr +++ b/src/test/ui/parser/bad-lit-suffixes.stderr @@ -1,14 +1,14 @@ -error: suffixes on a string literal are invalid +error: non-string ABI literal --> $DIR/bad-lit-suffixes.rs:2:5 | LL | "C"suffix - | ^^^^^^^^^ invalid suffix `suffix` + | ^^^^^^^^^ help: specify the ABI with a string literal: `"C"` -error: suffixes on a string literal are invalid +error: non-string ABI literal --> $DIR/bad-lit-suffixes.rs:6:5 | LL | "C"suffix - | ^^^^^^^^^ invalid suffix `suffix` + | ^^^^^^^^^ help: specify the ABI with a string literal: `"C"` error: suffixes on a string literal are invalid --> $DIR/bad-lit-suffixes.rs:10:5 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 59a7c53540069..f62446885f347 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 @@ -75,9 +75,18 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg if let ExprKind::Lit(start_lit) = &start.peel_parens().kind && let ExprKind::Lit(end_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_lit.token_lit), + LitKind::from_token_lit(end_lit.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')), + ) ) { span_lint_and_then( diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 732dc2b433091..8eda5a504d782 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -552,7 +552,7 @@ fn check_attrs(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribut } fn check_semver(cx: &LateContext<'_>, span: Span, lit: &Lit) { - if let LitKind::Str(is, _) = lit.kind { + if let Ok(LitKind::Str(is, _)) = LitKind::from_token_lit(lit.token_lit) { if Version::parse(is.as_str()).is_ok() { return; } 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 9a944def3eb22..83ece9281cd6b 100644 --- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs +++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs @@ -53,7 +53,7 @@ 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 { + if let Ok(LitKind::Int(value, ..)) = LitKind::from_token_lit(lit.token_lit) { return value == (target_value as u128); } false diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index fb2104861c87f..8d5f66fc0fcea 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -472,7 +472,7 @@ impl DecimalLiteralRepresentation { fn check_lit(self, cx: &EarlyContext<'_>, lit: &Lit) { // Lint integral literals. if_chain! { - if let LitKind::Int(val, _) = lit.kind; + if let Ok(LitKind::Int(val, _)) = LitKind::from_token_lit(lit.token_lit); if let Some(src) = snippet_opt(cx, lit.span); if let Some(num_lit) = NumericLiteral::from_lit(&src, lit); if num_lit.radix == Radix::Decimal; 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 704918c0b979b..cd1cfb77d273f 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -394,7 +394,8 @@ impl MiscEarlyLints { _ => return, }; - if let LitKind::Int(value, lit_int_type) = lit.kind { + let lit_kind = LitKind::from_token_lit(lit.token_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(), @@ -408,7 +409,7 @@ impl MiscEarlyLints { } else if value != 0 && lit_snip.starts_with('0') { zero_prefixed_literal::check(cx, lit, &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"); } diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index e6e3ad05ad70a..59290f8051b73 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.token_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 b8a5d4ea8c9fb..36dc7a4274fe6 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -34,7 +34,7 @@ fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> { && 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 Ok(LitKind::Float(symbol, ty)) = LitKind::from_token_lit(spanned.token_lit) { let f = symbol.as_str().parse::().unwrap(); let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty { ty.name_str() diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 493991f30e872..19f9fc49f3bc2 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.token_lit == r.token_lit, (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), @@ -706,7 +706,7 @@ pub fn eq_mac_args(l: &MacArgs, r: &MacArgs) -> bool { (Empty, Empty) => true, (Delimited(_, ld, lts), Delimited(_, rd, rts)) => ld == rd && lts.eq_unspanned(rts), (Eq(_, MacArgsEq::Ast(le)), Eq(_, MacArgsEq::Ast(re))) => eq_expr(le, re), - (Eq(_, MacArgsEq::Hir(ll)), Eq(_, MacArgsEq::Hir(rl))) => ll.kind == rl.kind, + (Eq(_, MacArgsEq::Hir(ll)), Eq(_, MacArgsEq::Hir(rl))) => ll.token_lit == rl.token_lit, _ => false, } } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 80098d9766c67..3aca9d017e12e 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -47,7 +47,8 @@ pub struct NumericLiteral<'a> { impl<'a> NumericLiteral<'a> { pub fn from_lit(src: &'a str, lit: &Lit) -> Option> { - NumericLiteral::from_lit_kind(src, &lit.kind) + let lit_kind = LitKind::from_token_lit(lit.token_lit).ok()?; + NumericLiteral::from_lit_kind(src, &lit_kind) } pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option> { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 3105882e2d308..14d043e58ce9e 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -2,7 +2,7 @@ use std::borrow::Cow; use std::cmp::min; use itertools::Itertools; -use rustc_ast::token::{Delimiter, LitKind}; +use rustc_ast::token::{Delimiter, Lit, LitKind}; use rustc_ast::{ast, ptr}; use rustc_span::{BytePos, Span}; @@ -274,10 +274,12 @@ 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(ref lit) => match lit.token_lit { + Lit { + kind: LitKind::Float, + suffix: None, + .. + } => context.snippet(lit.span).ends_with('.'), _ => false, }, ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr), @@ -1187,9 +1189,9 @@ pub(crate) fn rewrite_literal( l: &ast::Lit, shape: Shape, ) -> Option { - 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 l.token_lit.kind { + LitKind::Str => rewrite_string_lit(context, l.span, shape), + LitKind::Integer => rewrite_int_lit(context, l, shape), _ => wrap_str( context.snippet(l.span).to_owned(), context.config.max_width(), diff --git a/src/tools/rustfmt/src/modules/visitor.rs b/src/tools/rustfmt/src/modules/visitor.rs index ea67977c17a2b..8b19e7856ce35 100644 --- a/src/tools/rustfmt/src/modules/visitor.rs +++ b/src/tools/rustfmt/src/modules/visitor.rs @@ -85,24 +85,21 @@ impl PathVisitor { impl<'ast> MetaVisitor<'ast> for PathVisitor { fn visit_meta_name_value(&mut self, meta_item: &'ast ast::MetaItem, lit: &'ast ast::Lit) { - if meta_item.has_name(Symbol::intern("path")) && lit.kind.is_str() { + if meta_item.has_name(Symbol::intern("path")) && lit.token_lit.is_str() { self.paths.push(lit_to_str(lit)); } } } -#[cfg(not(windows))] fn lit_to_str(lit: &ast::Lit) -> String { - match lit.kind { - ast::LitKind::Str(symbol, ..) => symbol.to_string(), - _ => unreachable!(), - } -} - -#[cfg(windows)] -fn lit_to_str(lit: &ast::Lit) -> String { - match lit.kind { - ast::LitKind::Str(symbol, ..) => symbol.as_str().replace("/", "\\"), + match ast::LitKind::from_token_lit(lit.token_lit) { + Ok(ast::LitKind::Str(symbol, ..)) => { + if cfg!(windows) { + symbol.as_str().replace("/", "\\") + } else { + symbol.to_string() + } + } _ => unreachable!(), } }