move parse_lit to expr.rs
This commit is contained in:
parent
52d0e86b9a
commit
79d02867b8
3 changed files with 170 additions and 177 deletions
|
@ -1,14 +1,10 @@
|
||||||
//! Code related to parsing literals.
|
//! Code related to parsing literals.
|
||||||
|
|
||||||
use crate::ast::{self, Lit, LitKind};
|
use crate::ast::{self, Lit, LitKind};
|
||||||
use crate::parse::parser::Parser;
|
use crate::parse::token::{self, Token};
|
||||||
use crate::parse::PResult;
|
|
||||||
use crate::parse::token::{self, Token, TokenKind};
|
|
||||||
use crate::print::pprust;
|
|
||||||
use crate::symbol::{kw, sym, Symbol};
|
use crate::symbol::{kw, sym, Symbol};
|
||||||
use crate::tokenstream::{TokenStream, TokenTree};
|
use crate::tokenstream::{TokenStream, TokenTree};
|
||||||
|
|
||||||
use errors::{Applicability, Handler};
|
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rustc_data_structures::sync::Lrc;
|
use rustc_data_structures::sync::Lrc;
|
||||||
use syntax_pos::Span;
|
use syntax_pos::Span;
|
||||||
|
@ -28,72 +24,6 @@ crate enum LitError {
|
||||||
IntTooLarge,
|
IntTooLarge,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LitError {
|
|
||||||
fn report(&self, diag: &Handler, lit: token::Lit, span: Span) {
|
|
||||||
let token::Lit { kind, suffix, .. } = lit;
|
|
||||||
match *self {
|
|
||||||
// `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 => {
|
|
||||||
expect_no_suffix(
|
|
||||||
diag, span, &format!("{} {} literal", kind.article(), kind.descr()), suffix
|
|
||||||
);
|
|
||||||
}
|
|
||||||
LitError::InvalidIntSuffix => {
|
|
||||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
|
||||||
if looks_like_width_suffix(&['i', 'u'], &suf) {
|
|
||||||
// If it looks like a width, try to be helpful.
|
|
||||||
let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
|
|
||||||
diag.struct_span_err(span, &msg)
|
|
||||||
.help("valid widths are 8, 16, 32, 64 and 128")
|
|
||||||
.emit();
|
|
||||||
} else {
|
|
||||||
let msg = format!("invalid suffix `{}` for integer literal", suf);
|
|
||||||
diag.struct_span_err(span, &msg)
|
|
||||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
|
||||||
.help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LitError::InvalidFloatSuffix => {
|
|
||||||
let suf = suffix.expect("suffix error with no suffix").as_str();
|
|
||||||
if looks_like_width_suffix(&['f'], &suf) {
|
|
||||||
// If it looks like a width, try to be helpful.
|
|
||||||
let msg = format!("invalid width `{}` for float literal", &suf[1..]);
|
|
||||||
diag.struct_span_err(span, &msg)
|
|
||||||
.help("valid widths are 32 and 64")
|
|
||||||
.emit();
|
|
||||||
} else {
|
|
||||||
let msg = format!("invalid suffix `{}` for float literal", suf);
|
|
||||||
diag.struct_span_err(span, &msg)
|
|
||||||
.span_label(span, format!("invalid suffix `{}`", suf))
|
|
||||||
.help("valid suffixes are `f32` and `f64`")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
LitError::NonDecimalFloat(base) => {
|
|
||||||
let descr = match base {
|
|
||||||
16 => "hexadecimal",
|
|
||||||
8 => "octal",
|
|
||||||
2 => "binary",
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
diag.struct_span_err(span, &format!("{} float literal is not supported", descr))
|
|
||||||
.span_label(span, "not supported")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
LitError::IntTooLarge => {
|
|
||||||
diag.struct_span_err(span, "integer literal is too large")
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LitKind {
|
impl LitKind {
|
||||||
/// Converts literal token into a semantic literal.
|
/// Converts literal token into a semantic literal.
|
||||||
fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
fn from_lit_token(lit: token::Lit) -> Result<LitKind, LitError> {
|
||||||
|
@ -254,7 +184,7 @@ impl LitKind {
|
||||||
|
|
||||||
impl Lit {
|
impl Lit {
|
||||||
/// Converts literal token into an AST literal.
|
/// Converts literal token into an AST literal.
|
||||||
fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
|
crate fn from_lit_token(token: token::Lit, span: Span) -> Result<Lit, LitError> {
|
||||||
Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
|
Ok(Lit { token, kind: LitKind::from_lit_token(token)?, span })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -296,99 +226,6 @@ impl Lit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
|
||||||
/// Matches `lit = true | false | token_lit`.
|
|
||||||
crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
|
||||||
let mut recovered = None;
|
|
||||||
if self.token == token::Dot {
|
|
||||||
// Attempt to recover `.4` as `0.4`.
|
|
||||||
recovered = self.look_ahead(1, |next_token| {
|
|
||||||
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
|
|
||||||
= next_token.kind {
|
|
||||||
if self.token.span.hi() == next_token.span.lo() {
|
|
||||||
let s = String::from("0.") + &symbol.as_str();
|
|
||||||
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
|
|
||||||
return Some(Token::new(kind, self.token.span.to(next_token.span)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
});
|
|
||||||
if let Some(token) = &recovered {
|
|
||||||
self.bump();
|
|
||||||
self.diagnostic()
|
|
||||||
.struct_span_err(token.span, "float literals must have an integer part")
|
|
||||||
.span_suggestion(
|
|
||||||
token.span,
|
|
||||||
"must have an integer part",
|
|
||||||
pprust::token_to_string(token),
|
|
||||||
Applicability::MachineApplicable,
|
|
||||||
)
|
|
||||||
.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let token = recovered.as_ref().unwrap_or(&self.token);
|
|
||||||
match Lit::from_token(token) {
|
|
||||||
Ok(lit) => {
|
|
||||||
self.bump();
|
|
||||||
Ok(lit)
|
|
||||||
}
|
|
||||||
Err(LitError::NotLiteral) => {
|
|
||||||
let msg = format!("unexpected token: {}", self.this_token_descr());
|
|
||||||
Err(self.span_fatal(token.span, &msg))
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
let (lit, span) = (token.expect_lit(), token.span);
|
|
||||||
self.bump();
|
|
||||||
err.report(&self.sess.span_diagnostic, 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);
|
|
||||||
Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
crate fn expect_no_suffix(diag: &Handler, sp: Span, kind: &str, suffix: Option<Symbol>) {
|
|
||||||
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 = diag.struct_span_warn(
|
|
||||||
sp,
|
|
||||||
&format!("suffixes on {} are invalid", kind),
|
|
||||||
);
|
|
||||||
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(
|
|
||||||
"for more context, see https://github.com/rust-lang/rust/issues/60210",
|
|
||||||
);
|
|
||||||
err
|
|
||||||
} else {
|
|
||||||
diag.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
|
|
||||||
};
|
|
||||||
err.span_label(sp, format!("invalid suffix `{}`", suf));
|
|
||||||
err.emit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn strip_underscores(symbol: Symbol) -> Symbol {
|
fn strip_underscores(symbol: Symbol) -> Symbol {
|
||||||
// Do not allocate a new string unless necessary.
|
// Do not allocate a new string unless necessary.
|
||||||
let s = symbol.as_str();
|
let s = symbol.as_str();
|
||||||
|
|
|
@ -15,10 +15,10 @@ use crate::ast::{
|
||||||
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
|
self, DUMMY_NODE_ID, AttrStyle, Attribute, CrateSugar, Ident,
|
||||||
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
|
IsAsync, MacDelimiter, Mutability, StrStyle, Visibility, VisibilityKind, Unsafety,
|
||||||
};
|
};
|
||||||
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep, literal, token};
|
use crate::parse::{ParseSess, PResult, Directory, DirectoryOwnership, SeqSep};
|
||||||
use crate::parse::lexer::UnmatchedBrace;
|
use crate::parse::lexer::UnmatchedBrace;
|
||||||
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
use crate::parse::lexer::comments::{doc_comment_style, strip_doc_comment_decoration};
|
||||||
use crate::parse::token::{Token, TokenKind, DelimToken};
|
use crate::parse::token::{self, Token, TokenKind, DelimToken};
|
||||||
use crate::print::pprust;
|
use crate::print::pprust;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
use crate::source_map::respan;
|
use crate::source_map::respan;
|
||||||
|
@ -637,10 +637,6 @@ impl<'a> Parser<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
|
|
||||||
literal::expect_no_suffix(&self.sess.span_diagnostic, sp, kind, suffix)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
|
/// Attempts to consume a `<`. If `<<` is seen, replaces it with a single
|
||||||
/// `<` and continue. If `<-` is seen, replaces it with a single `<`
|
/// `<` and continue. If `<-` is seen, replaces it with a single `<`
|
||||||
/// and continue. If a `<` is not seen, returns false.
|
/// and continue. If a `<` is not seen, returns false.
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use super::{
|
use super::{Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode};
|
||||||
Parser, PResult, Restrictions, PrevTokenKind, TokenType, PathStyle, BlockMode, SemiColonMode,
|
use super::{SemiColonMode, SeqSep, TokenExpectType};
|
||||||
SeqSep, TokenExpectType,
|
|
||||||
};
|
|
||||||
use super::pat::{GateOr, PARAM_EXPECTED};
|
use super::pat::{GateOr, PARAM_EXPECTED};
|
||||||
|
|
||||||
|
use crate::parse::literal::LitError;
|
||||||
|
|
||||||
use crate::ast::{
|
use crate::ast::{
|
||||||
self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
|
self, DUMMY_NODE_ID, Attribute, AttrStyle, Ident, CaptureBy, BlockCheckMode,
|
||||||
Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
|
Expr, ExprKind, RangeLimits, Label, Movability, IsAsync, Arm, Ty, TyKind,
|
||||||
FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field,
|
FunctionRetTy, Param, FnDecl, BinOpKind, BinOp, UnOp, Mac, AnonConst, Field, Lit,
|
||||||
};
|
};
|
||||||
use crate::maybe_recover_from_interpolated_ty_qpath;
|
use crate::maybe_recover_from_interpolated_ty_qpath;
|
||||||
use crate::parse::classify;
|
use crate::parse::classify;
|
||||||
use crate::parse::token::{self, Token};
|
use crate::parse::token::{self, Token, TokenKind};
|
||||||
use crate::parse::diagnostics::Error;
|
use crate::parse::diagnostics::Error;
|
||||||
use crate::print::pprust;
|
use crate::print::pprust;
|
||||||
use crate::ptr::P;
|
use crate::ptr::P;
|
||||||
|
@ -20,6 +20,7 @@ use crate::symbol::{kw, sym};
|
||||||
use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
|
use crate::util::parser::{AssocOp, Fixity, prec_let_scrutinee_needs_par};
|
||||||
|
|
||||||
use errors::Applicability;
|
use errors::Applicability;
|
||||||
|
use syntax_pos::Symbol;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use rustc_data_structures::thin_vec::ThinVec;
|
use rustc_data_structures::thin_vec::ThinVec;
|
||||||
|
|
||||||
|
@ -1072,6 +1073,165 @@ impl<'a> Parser<'a> {
|
||||||
self.maybe_recover_from_bad_qpath(expr, true)
|
self.maybe_recover_from_bad_qpath(expr, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches `lit = true | false | token_lit`.
|
||||||
|
crate fn parse_lit(&mut self) -> PResult<'a, Lit> {
|
||||||
|
let mut recovered = None;
|
||||||
|
if self.token == token::Dot {
|
||||||
|
// Attempt to recover `.4` as `0.4`.
|
||||||
|
recovered = self.look_ahead(1, |next_token| {
|
||||||
|
if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix })
|
||||||
|
= next_token.kind {
|
||||||
|
if self.token.span.hi() == next_token.span.lo() {
|
||||||
|
let s = String::from("0.") + &symbol.as_str();
|
||||||
|
let kind = TokenKind::lit(token::Float, Symbol::intern(&s), suffix);
|
||||||
|
return Some(Token::new(kind, self.token.span.to(next_token.span)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
if let Some(token) = &recovered {
|
||||||
|
self.bump();
|
||||||
|
self.struct_span_err(token.span, "float literals must have an integer part")
|
||||||
|
.span_suggestion(
|
||||||
|
token.span,
|
||||||
|
"must have an integer part",
|
||||||
|
pprust::token_to_string(token),
|
||||||
|
Applicability::MachineApplicable,
|
||||||
|
)
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let token = recovered.as_ref().unwrap_or(&self.token);
|
||||||
|
match Lit::from_token(token) {
|
||||||
|
Ok(lit) => {
|
||||||
|
self.bump();
|
||||||
|
Ok(lit)
|
||||||
|
}
|
||||||
|
Err(LitError::NotLiteral) => {
|
||||||
|
let msg = format!("unexpected token: {}", self.this_token_descr());
|
||||||
|
Err(self.span_fatal(token.span, &msg))
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
let (lit, span) = (token.expect_lit(), token.span);
|
||||||
|
self.bump();
|
||||||
|
self.error_literal_from_token(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);
|
||||||
|
Lit::from_lit_token(lit, span).map_err(|_| unreachable!())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_literal_from_token(&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())
|
||||||
|
}
|
||||||
|
|
||||||
|
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").as_str();
|
||||||
|
if looks_like_width_suffix(&['i', 'u'], &suf) {
|
||||||
|
// If it looks like a width, try to be helpful.
|
||||||
|
let msg = format!("invalid width `{}` for integer literal", &suf[1..]);
|
||||||
|
self.struct_span_err(span, &msg)
|
||||||
|
.help("valid widths are 8, 16, 32, 64 and 128")
|
||||||
|
.emit();
|
||||||
|
} else {
|
||||||
|
let msg = format!("invalid suffix `{}` for integer literal", suf);
|
||||||
|
self.struct_span_err(span, &msg)
|
||||||
|
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||||
|
.help("the suffix must be one of the integral types (`u32`, `isize`, etc)")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LitError::InvalidFloatSuffix => {
|
||||||
|
let suf = suffix.expect("suffix error with no suffix").as_str();
|
||||||
|
if looks_like_width_suffix(&['f'], &suf) {
|
||||||
|
// If it looks like a width, try to be helpful.
|
||||||
|
let msg = format!("invalid width `{}` for float literal", &suf[1..]);
|
||||||
|
self.struct_span_err(span, &msg)
|
||||||
|
.help("valid widths are 32 and 64")
|
||||||
|
.emit();
|
||||||
|
} else {
|
||||||
|
let msg = format!("invalid suffix `{}` for float literal", suf);
|
||||||
|
self.struct_span_err(span, &msg)
|
||||||
|
.span_label(span, format!("invalid suffix `{}`", suf))
|
||||||
|
.help("valid suffixes are `f32` and `f64`")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LitError::NonDecimalFloat(base) => {
|
||||||
|
let descr = match base {
|
||||||
|
16 => "hexadecimal",
|
||||||
|
8 => "octal",
|
||||||
|
2 => "binary",
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
self.struct_span_err(span, &format!("{} float literal is not supported", descr))
|
||||||
|
.span_label(span, "not supported")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
LitError::IntTooLarge => {
|
||||||
|
self.struct_span_err(span, "integer literal is too large")
|
||||||
|
.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<Symbol>) {
|
||||||
|
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.sess.span_diagnostic.struct_span_warn(
|
||||||
|
sp,
|
||||||
|
&format!("suffixes on {} are invalid", kind),
|
||||||
|
);
|
||||||
|
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(
|
||||||
|
"for more context, see https://github.com/rust-lang/rust/issues/60210",
|
||||||
|
);
|
||||||
|
err
|
||||||
|
} else {
|
||||||
|
self.struct_span_err(sp, &format!("suffixes on {} are invalid", kind))
|
||||||
|
};
|
||||||
|
err.span_label(sp, format!("invalid suffix `{}`", suf));
|
||||||
|
err.emit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
|
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
|
||||||
crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
|
crate fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
|
||||||
maybe_whole_expr!(self);
|
maybe_whole_expr!(self);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue