Skip to content

Add ErrorGuaranteed to ast::LitKind::Err, token::LitKind::Err. #121120

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions compiler/rustc_ast/src/util/literal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ pub fn escape_byte_str_symbol(bytes: &[u8]) -> Symbol {

#[derive(Debug)]
pub enum LitError {
LexerError,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

InvalidSuffix,
InvalidIntSuffix,
InvalidFloatSuffix,
Expand Down Expand Up @@ -324,11 +323,7 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
};

let s = &s[if base != 10 { 2 } else { 0 }..];
u128::from_str_radix(s, base).map(|i| LitKind::Int(i.into(), ty)).map_err(|_| {
// Small bases are lexed as if they were base 10, e.g, the string
// might be `0b10201`. This will cause the conversion above to fail,
// but these kinds of errors are already reported by the lexer.
let from_lexer = base < 10 && s.chars().any(|c| c.to_digit(10).is_some_and(|d| d >= base));
if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) }
})
u128::from_str_radix(s, base)
.map(|i| LitKind::Int(i.into(), ty))
.map_err(|_| LitError::IntTooLarge(base))
}
30 changes: 15 additions & 15 deletions compiler/rustc_parse/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rustc_session::lint::builtin::{
};
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::ParseSess;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::symbol::Symbol;
use rustc_span::{edition::Edition, BytePos, Pos, Span};

mod diagnostics;
Expand Down Expand Up @@ -478,26 +478,26 @@ impl<'sess, 'src> StringReader<'sess, 'src> {
}
}
rustc_lexer::LiteralKind::Int { base, empty_int } => {
let mut kind = token::Integer;
if empty_int {
let span = self.mk_sp(start, end);
self.dcx().emit_err(errors::NoDigitsLiteral { span });
(token::Integer, sym::integer(0))
} else {
if matches!(base, Base::Binary | Base::Octal) {
let base = base as u32;
let s = self.str_from_to(start + BytePos(2), end);
for (idx, c) in s.char_indices() {
let span = self.mk_sp(
start + BytePos::from_usize(2 + idx),
start + BytePos::from_usize(2 + idx + c.len_utf8()),
);
if c != '_' && c.to_digit(base).is_none() {
self.dcx().emit_err(errors::InvalidDigitLiteral { span, base });
}
kind = token::Err;
} else if matches!(base, Base::Binary | Base::Octal) {
let base = base as u32;
let s = self.str_from_to(start + BytePos(2), end);
for (idx, c) in s.char_indices() {
let span = self.mk_sp(
start + BytePos::from_usize(2 + idx),
start + BytePos::from_usize(2 + idx + c.len_utf8()),
);
if c != '_' && c.to_digit(base).is_none() {
self.dcx().emit_err(errors::InvalidDigitLiteral { span, base });
kind = token::Err;
}
}
(token::Integer, self.symbol_from_to(start, end))
}
(kind, self.symbol_from_to(start, end))
}
rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
if empty_exponent {
Expand Down
46 changes: 23 additions & 23 deletions compiler/rustc_session/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::num::NonZeroU32;
use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::{
codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, IntoDiagnostic, Level, MultiSpan,
codes::*, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
Level, MultiSpan,
};
use rustc_macros::Diagnostic;
use rustc_span::{Span, Symbol};
Expand Down Expand Up @@ -344,7 +345,12 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
pub span: Span,
}

pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
pub fn report_lit_error(
sess: &ParseSess,
err: LitError,
lit: token::Lit,
span: Span,
) -> ErrorGuaranteed {
// 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())
Expand Down Expand Up @@ -372,47 +378,41 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
valid.then(|| format!("0{}{}", base_char.to_ascii_lowercase(), &suffix[1..]))
}

let token::Lit { kind, symbol, suffix, .. } = lit;
let token::Lit { kind, symbol, suffix } = lit;
let dcx = &sess.dcx;
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 => {
if let Some(suffix) = suffix {
dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix });
}
let suffix = suffix.unwrap();
dcx.emit_err(InvalidLiteralSuffix { span, kind: 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.
dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() })
} else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) {
dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed })
} else {
dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
dcx.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.
dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() })
} else {
dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() })
}
}
LitError::NonDecimalFloat(base) => {
match base {
16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }),
8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }),
2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }),
_ => unreachable!(),
};
}
LitError::NonDecimalFloat(base) => match base {
16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }),
8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }),
2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }),
_ => unreachable!(),
},
LitError::IntTooLarge(base) => {
let max = u128::MAX;
let limit = match base {
Expand All @@ -421,7 +421,7 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
16 => format!("{max:#x}"),
_ => format!("{max}"),
};
dcx.emit_err(IntLiteralTooLarge { span, limit });
dcx.emit_err(IntLiteralTooLarge { span, limit })
}
}
}
Expand Down