|
1 | 1 | use super::errors::{
|
2 | 2 | AsyncGeneratorsNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
3 | 3 | BaseExpressionDoubleDot, ClosureCannotBeStatic, FunctionalRecordUpdateDestructuringAssignemnt,
|
4 |
| - GeneratorTooManyParameters, InclusiveRangeWithNoEnd, NotSupportedForLifetimeBinderAsyncClosure, |
5 |
| - RustcBoxAttributeError, UnderscoreExprLhsAssign, |
| 4 | + GeneratorTooManyParameters, InclusiveRangeWithNoEnd, IntLiteralTooLarge, |
| 5 | + InvalidFloatLiteralSuffix, InvalidFloatLiteralWidth, InvalidIntLiteralWidth, |
| 6 | + InvalidNumLiteralBasePrefix, InvalidNumLiteralSuffix, |
| 7 | + NotSupportedForLifetimeBinderAsyncClosure, RustcBoxAttributeError, UnderscoreExprLhsAssign, |
6 | 8 | };
|
7 | 9 | use super::ResolverAstLoweringExt;
|
8 | 10 | use super::{ImplTraitContext, LoweringContext, ParamMode, ParenthesizedGenericArgs};
|
9 | 11 | use crate::{FnDeclKind, ImplTraitPosition};
|
10 | 12 | use rustc_ast::attr;
|
11 | 13 | use rustc_ast::ptr::P as AstP;
|
| 14 | +use rustc_ast::util::literal::LitError; |
12 | 15 | use rustc_ast::*;
|
13 | 16 | use rustc_data_structures::stack::ensure_sufficient_stack;
|
14 | 17 | use rustc_hir as hir;
|
@@ -84,8 +87,17 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
84 | 87 | let ohs = self.lower_expr(ohs);
|
85 | 88 | hir::ExprKind::Unary(op, ohs)
|
86 | 89 | }
|
87 |
| - ExprKind::Lit(ref l) => { |
88 |
| - hir::ExprKind::Lit(respan(self.lower_span(l.span), l.kind.clone())) |
| 90 | + ExprKind::Lit(ref lit) => { |
| 91 | + let token_lit = lit.token_lit; |
| 92 | + let lit_kind = match LitKind::from_token_lit(token_lit) { |
| 93 | + Ok(lit_kind) => lit_kind, |
| 94 | + Err(err) => { |
| 95 | + let span = lit.span; |
| 96 | + self.report_lit_error(err, token_lit, span); |
| 97 | + LitKind::Err |
| 98 | + } |
| 99 | + }; |
| 100 | + hir::ExprKind::Lit(respan(self.lower_span(lit.span), lit_kind)) |
89 | 101 | }
|
90 | 102 | ExprKind::Cast(ref expr, ref ty) => {
|
91 | 103 | let expr = self.lower_expr(expr);
|
@@ -306,6 +318,86 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
306 | 318 | })
|
307 | 319 | }
|
308 | 320 |
|
| 321 | + #[allow(rustc::diagnostic_outside_of_impl)] |
| 322 | + #[allow(rustc::untranslatable_diagnostic)] |
| 323 | + fn report_lit_error(&self, err: LitError, lit: token::Lit, span: Span) { |
| 324 | + // Checks if `s` looks like i32 or u1234 etc. |
| 325 | + fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool { |
| 326 | + s.len() > 1 && s.starts_with(first_chars) && s[1..].chars().all(|c| c.is_ascii_digit()) |
| 327 | + } |
| 328 | + |
| 329 | + // Try to lowercase the prefix if it's a valid base prefix. |
| 330 | + fn fix_base_capitalisation(s: &str) -> Option<String> { |
| 331 | + if let Some(stripped) = s.strip_prefix('B') { |
| 332 | + Some(format!("0b{stripped}")) |
| 333 | + } else if let Some(stripped) = s.strip_prefix('O') { |
| 334 | + Some(format!("0o{stripped}")) |
| 335 | + } else if let Some(stripped) = s.strip_prefix('X') { |
| 336 | + Some(format!("0x{stripped}")) |
| 337 | + } else { |
| 338 | + None |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + let token::Lit { kind, suffix, .. } = lit; |
| 343 | + match err { |
| 344 | + // `LexerError` *is* an error, but it was already reported |
| 345 | + // by lexer, so here we don't report it the second time. |
| 346 | + LitError::LexerError => {} |
| 347 | + LitError::InvalidSuffix => { |
| 348 | + self.tcx.sess.parse_sess.expect_no_suffix( |
| 349 | + span, |
| 350 | + &format!("{} {} literal", kind.article(), kind.descr()), |
| 351 | + suffix, |
| 352 | + ); |
| 353 | + } |
| 354 | + LitError::InvalidIntSuffix => { |
| 355 | + let suf = suffix.expect("suffix error with no suffix"); |
| 356 | + let suf = suf.as_str(); |
| 357 | + if looks_like_width_suffix(&['i', 'u'], &suf) { |
| 358 | + // If it looks like a width, try to be helpful. |
| 359 | + self.tcx.sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() }); |
| 360 | + } else if let Some(fixed) = fix_base_capitalisation(suf) { |
| 361 | + self.tcx.sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed }); |
| 362 | + } else { |
| 363 | + self.tcx |
| 364 | + .sess |
| 365 | + .emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() }); |
| 366 | + } |
| 367 | + } |
| 368 | + LitError::InvalidFloatSuffix => { |
| 369 | + let suf = suffix.expect("suffix error with no suffix"); |
| 370 | + let suf = suf.as_str(); |
| 371 | + if looks_like_width_suffix(&['f'], suf) { |
| 372 | + // If it looks like a width, try to be helpful. |
| 373 | + self.tcx |
| 374 | + .sess |
| 375 | + .emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() }); |
| 376 | + } else { |
| 377 | + self.tcx |
| 378 | + .sess |
| 379 | + .emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() }); |
| 380 | + } |
| 381 | + } |
| 382 | + LitError::NonDecimalFloat(base) => { |
| 383 | + let descr = match base { |
| 384 | + 16 => "hexadecimal", |
| 385 | + 8 => "octal", |
| 386 | + 2 => "binary", |
| 387 | + _ => unreachable!(), |
| 388 | + }; |
| 389 | + self.tcx |
| 390 | + .sess |
| 391 | + .struct_span_err(span, &format!("{descr} float literal is not supported")) |
| 392 | + .span_label(span, "not supported") |
| 393 | + .emit(); |
| 394 | + } |
| 395 | + LitError::IntTooLarge => { |
| 396 | + self.tcx.sess.emit_err(IntLiteralTooLarge { span }); |
| 397 | + } |
| 398 | + } |
| 399 | + } |
| 400 | + |
309 | 401 | fn lower_unop(&mut self, u: UnOp) -> hir::UnOp {
|
310 | 402 | match u {
|
311 | 403 | UnOp::Deref => hir::UnOp::Deref,
|
|
0 commit comments