diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:18:25 +0000 |
commit | 5363f350887b1e5b5dd21a86f88c8af9d7fea6da (patch) | |
tree | 35ca005eb6e0e9a1ba3bb5dbc033209ad445dc17 /compiler/rustc_parse/src/parser/mod.rs | |
parent | Adding debian version 1.66.0+dfsg1-1. (diff) | |
download | rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.tar.xz rustc-5363f350887b1e5b5dd21a86f88c8af9d7fea6da.zip |
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse/src/parser/mod.rs')
-rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 142 |
1 files changed, 95 insertions, 47 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 5fe29062b..bebb01266 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -22,10 +22,11 @@ use rustc_ast::token::{self, Delimiter, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::AttributesData; use rustc_ast::tokenstream::{self, DelimSpan, Spacing}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::util::case::Case; use rustc_ast::AttrId; use rustc_ast::DUMMY_NODE_ID; -use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, Extern}; -use rustc_ast::{Async, Expr, ExprKind, MacArgs, MacArgsEq, MacDelimiter, Mutability, StrLit}; +use rustc_ast::{self as ast, AnonConst, AttrStyle, AttrVec, Const, DelimArgs, Extern}; +use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutability, StrLit}; use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; @@ -104,6 +105,7 @@ macro_rules! maybe_whole { macro_rules! maybe_recover_from_interpolated_ty_qpath { ($self: expr, $allow_qpath_recovery: expr) => { if $allow_qpath_recovery + && $self.may_recover() && $self.look_ahead(1, |t| t == &token::ModSep) && let token::Interpolated(nt) = &$self.token.kind && let token::NtTy(ty) = &**nt @@ -382,8 +384,8 @@ enum TokenType { impl TokenType { fn to_string(&self) -> String { - match *self { - TokenType::Token(ref t) => format!("`{}`", pprust::token_kind_to_string(t)), + match self { + TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)), TokenType::Keyword(kw) => format!("`{}`", kw), TokenType::Operator => "an operator".to_string(), TokenType::Lifetime => "lifetime".to_string(), @@ -501,8 +503,8 @@ impl<'a> Parser<'a> { parser } - pub fn forbid_recovery(mut self) -> Self { - self.recovery = Recovery::Forbidden; + pub fn recovery(mut self, recovery: Recovery) -> Self { + self.recovery = recovery; self } @@ -635,6 +637,20 @@ impl<'a> Parser<'a> { self.token.is_keyword(kw) } + fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { + if self.check_keyword(kw) { + return true; + } + + if case == Case::Insensitive + && let Some((ident, /* is_raw */ false)) = self.token.ident() + && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { + true + } else { + false + } + } + /// If the next token is the given keyword, eats it and returns `true`. /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes. // Public for rustfmt usage. @@ -647,6 +663,33 @@ impl<'a> Parser<'a> { } } + /// Eats a keyword, optionally ignoring the case. + /// If the case differs (and is ignored) an error is issued. + /// This is useful for recovery. + fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool { + if self.eat_keyword(kw) { + return true; + } + + if case == Case::Insensitive + && let Some((ident, /* is_raw */ false)) = self.token.ident() + && ident.as_str().to_lowercase() == kw.as_str().to_lowercase() { + self + .struct_span_err(ident.span, format!("keyword `{kw}` is written in a wrong case")) + .span_suggestion( + ident.span, + "write it in the correct case", + kw, + Applicability::MachineApplicable + ).emit(); + + self.bump(); + return true; + } + + false + } + fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool { if self.token.is_keyword(kw) { self.bump(); @@ -695,8 +738,8 @@ impl<'a> Parser<'a> { fn check_inline_const(&self, dist: usize) -> bool { self.is_keyword_ahead(dist, &[kw::Const]) - && self.look_ahead(dist + 1, |t| match t.kind { - token::Interpolated(ref nt) => matches!(**nt, token::NtBlock(..)), + && self.look_ahead(dist + 1, |t| match &t.kind { + token::Interpolated(nt) => matches!(**nt, token::NtBlock(..)), token::OpenDelim(Delimiter::Brace) => true, _ => false, }) @@ -817,7 +860,7 @@ impl<'a> Parser<'a> { if let token::CloseDelim(..) | token::Eof = self.token.kind { break; } - if let Some(ref t) = sep.sep { + if let Some(t) = &sep.sep { if first { first = false; } else { @@ -852,7 +895,7 @@ impl<'a> Parser<'a> { _ => { // Attempt to keep parsing if it was a similar separator. - if let Some(ref tokens) = t.similar_tokens() { + if let Some(tokens) = t.similar_tokens() { if tokens.contains(&self.token.kind) && !unclosed_delims { self.bump(); } @@ -900,6 +943,10 @@ impl<'a> Parser<'a> { Err(e) => { // Parsing failed, therefore it must be something more serious // than just a missing separator. + for xx in &e.children { + // propagate the help message from sub error 'e' to main error 'expect_err; + expect_err.children.push(xx.clone()); + } expect_err.emit(); e.cancel(); @@ -1126,8 +1173,8 @@ impl<'a> Parser<'a> { } /// Parses asyncness: `async` or nothing. - fn parse_asyncness(&mut self) -> Async { - if self.eat_keyword(kw::Async) { + fn parse_asyncness(&mut self, case: Case) -> Async { + if self.eat_keyword_case(kw::Async, case) { let span = self.prev_token.uninterpolated_span(); Async::Yes { span, closure_id: DUMMY_NODE_ID, return_impl_trait_id: DUMMY_NODE_ID } } else { @@ -1136,8 +1183,8 @@ impl<'a> Parser<'a> { } /// Parses unsafety: `unsafe` or nothing. - fn parse_unsafety(&mut self) -> Unsafe { - if self.eat_keyword(kw::Unsafe) { + fn parse_unsafety(&mut self, case: Case) -> Unsafe { + if self.eat_keyword_case(kw::Unsafe, case) { Unsafe::Yes(self.prev_token.uninterpolated_span()) } else { Unsafe::No @@ -1145,10 +1192,10 @@ impl<'a> Parser<'a> { } /// Parses constness: `const` or nothing. - fn parse_constness(&mut self) -> Const { + fn parse_constness(&mut self, case: Case) -> Const { // Avoid const blocks to be parsed as const items if self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace)) - && self.eat_keyword(kw::Const) + && self.eat_keyword_case(kw::Const, case) { Const::Yes(self.prev_token.uninterpolated_span()) } else { @@ -1206,39 +1253,40 @@ impl<'a> Parser<'a> { } } - fn parse_mac_args(&mut self) -> PResult<'a, P<MacArgs>> { - self.parse_mac_args_common(true).map(P) + fn parse_delim_args(&mut self) -> PResult<'a, P<DelimArgs>> { + if let Some(args) = self.parse_delim_args_inner() { Ok(P(args)) } else { self.unexpected() } } - fn parse_attr_args(&mut self) -> PResult<'a, MacArgs> { - self.parse_mac_args_common(false) + fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> { + Ok(if let Some(args) = self.parse_delim_args_inner() { + AttrArgs::Delimited(args) + } else { + if self.eat(&token::Eq) { + let eq_span = self.prev_token.span; + AttrArgs::Eq(eq_span, AttrArgsEq::Ast(self.parse_expr_force_collect()?)) + } else { + AttrArgs::Empty + } + }) } - fn parse_mac_args_common(&mut self, delimited_only: bool) -> PResult<'a, MacArgs> { - Ok( - if self.check(&token::OpenDelim(Delimiter::Parenthesis)) - || self.check(&token::OpenDelim(Delimiter::Bracket)) - || self.check(&token::OpenDelim(Delimiter::Brace)) - { - match self.parse_token_tree() { - TokenTree::Delimited(dspan, delim, tokens) => - // We've confirmed above that there is a delimiter so unwrapping is OK. - { - MacArgs::Delimited(dspan, MacDelimiter::from_token(delim).unwrap(), tokens) - } - _ => unreachable!(), - } - } else if !delimited_only { - if self.eat(&token::Eq) { - let eq_span = self.prev_token.span; - MacArgs::Eq(eq_span, MacArgsEq::Ast(self.parse_expr_force_collect()?)) - } else { - MacArgs::Empty - } - } else { - return self.unexpected(); - }, - ) + fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> { + if self.check(&token::OpenDelim(Delimiter::Parenthesis)) + || self.check(&token::OpenDelim(Delimiter::Bracket)) + || self.check(&token::OpenDelim(Delimiter::Brace)) + { + match self.parse_token_tree() { + // We've confirmed above that there is a delimiter so unwrapping is OK. + TokenTree::Delimited(dspan, delim, tokens) => Some(DelimArgs { + dspan, + delim: MacDelimiter::from_token(delim).unwrap(), + tokens, + }), + _ => unreachable!(), + } + } else { + None + } } fn parse_or_use_outer_attributes( @@ -1403,8 +1451,8 @@ impl<'a> Parser<'a> { } /// Parses `extern string_literal?`. - fn parse_extern(&mut self) -> Extern { - if self.eat_keyword(kw::Extern) { + fn parse_extern(&mut self, case: Case) -> Extern { + if self.eat_keyword_case(kw::Extern, case) { let mut extern_span = self.prev_token.span; let abi = self.parse_abi(); if let Some(abi) = abi { |