diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:11:38 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:12:43 +0000 |
commit | cf94bdc0742c13e2a0cac864c478b8626b266e1b (patch) | |
tree | 044670aa50cc5e2b4229aa0b6b3df6676730c0a6 /compiler/rustc_parse/src/parser/mod.rs | |
parent | Adding debian version 1.65.0+dfsg1-2. (diff) | |
download | rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.tar.xz rustc-cf94bdc0742c13e2a0cac864c478b8626b266e1b.zip |
Merging upstream version 1.66.0+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 | 151 |
1 files changed, 88 insertions, 63 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 4cb198561..5fe29062b 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -13,7 +13,6 @@ mod ty; use crate::lexer::UnmatchedBrace; pub use attr_wrapper::AttrWrapper; pub use diagnostics::AttemptLocalParseRecovery; -use diagnostics::Error; pub(crate) use item::FnParseMode; pub use pat::{CommaRecoveryMode, RecoverColon, RecoverComma}; pub use path::PathStyle; @@ -32,7 +31,7 @@ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; use rustc_errors::PResult; use rustc_errors::{ - struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, + Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, }; use rustc_session::parse::ParseSess; use rustc_span::source_map::{Span, DUMMY_SP}; @@ -41,6 +40,11 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use std::ops::Range; use std::{cmp, mem, slice}; +use crate::errors::{ + DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, + NonStringAbiLiteral, +}; + bitflags::bitflags! { struct Restrictions: u8 { const STMT_EXPR = 1 << 0; @@ -75,6 +79,7 @@ pub enum ForceCollect { pub enum TrailingToken { None, Semi, + Gt, /// If the trailing token is a comma, then capture it /// Otherwise, ignore the trailing token MaybeComma, @@ -110,6 +115,12 @@ macro_rules! maybe_recover_from_interpolated_ty_qpath { }; } +#[derive(Clone, Copy)] +pub enum Recovery { + Allowed, + Forbidden, +} + #[derive(Clone)] pub struct Parser<'a> { pub sess: &'a ParseSess, @@ -147,12 +158,15 @@ pub struct Parser<'a> { /// This allows us to recover when the user forget to add braces around /// multiple statements in the closure body. pub current_closure: Option<ClosureSpans>, + /// Whether the parser is allowed to do recovery. + /// This is disabled when parsing macro arguments, see #103534 + pub recovery: Recovery, } -// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure +// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure // it doesn't unintentionally get bigger. #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Parser<'_>, 328); +rustc_data_structures::static_assert_size!(Parser<'_>, 336); /// Stores span information about a closure. #[derive(Clone)] @@ -298,7 +312,10 @@ impl TokenCursor { fn desugar(&mut self, attr_style: AttrStyle, data: Symbol, span: Span) -> (Token, Spacing) { // Searches for the occurrences of `"#*` and returns the minimum number of `#`s - // required to wrap the text. + // required to wrap the text. E.g. + // - `abc d` is wrapped as `r"abc d"` (num_of_hashes = 0) + // - `abc "d"` is wrapped as `r#"abc "d""#` (num_of_hashes = 1) + // - `abc "##d##"` is wrapped as `r###"abc "d""###` (num_of_hashes = 3) let mut num_of_hashes = 0; let mut count = 0; for ch in data.as_str().chars() { @@ -310,6 +327,7 @@ impl TokenCursor { num_of_hashes = cmp::max(num_of_hashes, count); } + // `/// foo` becomes `doc = r"foo". let delim_span = DelimSpan::from_single(span); let body = TokenTree::Delimited( delim_span, @@ -406,24 +424,39 @@ pub enum FollowedByType { No, } -fn token_descr_opt(token: &Token) -> Option<&'static str> { - Some(match token.kind { - _ if token.is_special_ident() => "reserved identifier", - _ if token.is_used_keyword() => "keyword", - _ if token.is_unused_keyword() => "reserved keyword", - token::DocComment(..) => "doc comment", - _ => return None, - }) +#[derive(Clone, Copy, PartialEq, Eq)] +pub enum TokenDescription { + ReservedIdentifier, + Keyword, + ReservedKeyword, + DocComment, } -pub(super) fn token_descr(token: &Token) -> String { - let token_str = pprust::token_to_string(token); - match token_descr_opt(token) { - Some(prefix) => format!("{} `{}`", prefix, token_str), - _ => format!("`{}`", token_str), +impl TokenDescription { + pub fn from_token(token: &Token) -> Option<Self> { + match token.kind { + _ if token.is_special_ident() => Some(TokenDescription::ReservedIdentifier), + _ if token.is_used_keyword() => Some(TokenDescription::Keyword), + _ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword), + token::DocComment(..) => Some(TokenDescription::DocComment), + _ => None, + } } } +pub(super) fn token_descr(token: &Token) -> String { + let name = pprust::token_to_string(token).to_string(); + + let kind = TokenDescription::from_token(token).map(|kind| match kind { + TokenDescription::ReservedIdentifier => "reserved identifier", + TokenDescription::Keyword => "keyword", + TokenDescription::ReservedKeyword => "reserved keyword", + TokenDescription::DocComment => "doc comment", + }); + + if let Some(kind) = kind { format!("{} `{}`", kind, name) } else { format!("`{}`", name) } +} + impl<'a> Parser<'a> { pub fn new( sess: &'a ParseSess, @@ -459,6 +492,7 @@ impl<'a> Parser<'a> { inner_attr_ranges: Default::default(), }, current_closure: None, + recovery: Recovery::Allowed, }; // Make parser point to the first token. @@ -467,6 +501,22 @@ impl<'a> Parser<'a> { parser } + pub fn forbid_recovery(mut self) -> Self { + self.recovery = Recovery::Forbidden; + self + } + + /// Whether the parser is allowed to recover from broken code. + /// + /// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead) + /// is not allowed. All recovery done by the parser must be gated behind this check. + /// + /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens. + /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold. + fn may_recover(&self) -> bool { + matches!(self.recovery, Recovery::Allowed) + } + pub fn unexpected<T>(&mut self) -> PResult<'a, T> { match self.expect_one_of(&[], &[]) { Err(e) => Err(e), @@ -518,9 +568,11 @@ impl<'a> Parser<'a> { fn ident_or_err(&mut self) -> PResult<'a, (Ident, /* is_raw */ bool)> { self.token.ident().ok_or_else(|| match self.prev_token.kind { - TokenKind::DocComment(..) => { - self.span_err(self.prev_token.span, Error::UselessDocComment) + TokenKind::DocComment(..) => DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, } + .into_diagnostic(&self.sess.span_diagnostic), _ => self.expected_ident_found(), }) } @@ -1144,7 +1196,9 @@ impl<'a> Parser<'a> { fn parse_field_name(&mut self) -> PResult<'a, Ident> { if let token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) = self.token.kind { - self.expect_no_suffix(self.token.span, "a tuple index", suffix); + if let Some(suffix) = suffix { + self.expect_no_tuple_index_suffix(self.token.span, suffix); + } self.bump(); Ok(Ident::new(symbol, self.prev_token.span)) } else { @@ -1342,23 +1396,8 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let msg = "incorrect visibility restriction"; - let suggestion = r##"some possible visibility restrictions are: -`pub(crate)`: visible only on the current crate -`pub(super)`: visible only in the current module's parent -`pub(in path::to::module)`: visible only on the specified path"##; - let path_str = pprust::path_to_string(&path); - - struct_span_err!(self.sess.span_diagnostic, path.span, E0704, "{}", msg) - .help(suggestion) - .span_suggestion( - path.span, - &format!("make this visible only to module `{}` with `in`", path_str), - format!("in {}", path_str), - Applicability::MachineApplicable, - ) - .emit(); + self.sess.emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str }); Ok(()) } @@ -1384,14 +1423,7 @@ impl<'a> Parser<'a> { Err(Some(lit)) => match lit.kind { ast::LitKind::Err => None, _ => { - self.struct_span_err(lit.span, "non-string ABI literal") - .span_suggestion( - lit.span, - "specify the ABI with a string literal", - "\"C\"", - Applicability::MaybeIncorrect, - ) - .emit(); + self.sess.emit_err(NonStringAbiLiteral { span: lit.span }); None } }, @@ -1432,25 +1464,18 @@ pub(crate) fn make_unclosed_delims_error( // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to // `unmatched_braces` only for error recovery in the `Parser`. let found_delim = unmatched.found_delim?; - let span: MultiSpan = if let Some(sp) = unmatched.unclosed_span { - vec![unmatched.found_span, sp].into() - } else { - unmatched.found_span.into() - }; - let mut err = sess.span_diagnostic.struct_span_err( - span, - &format!( - "mismatched closing delimiter: `{}`", - pprust::token_kind_to_string(&token::CloseDelim(found_delim)), - ), - ); - err.span_label(unmatched.found_span, "mismatched closing delimiter"); - if let Some(sp) = unmatched.candidate_span { - err.span_label(sp, "closing delimiter possibly meant for this"); - } + let mut spans = vec![unmatched.found_span]; if let Some(sp) = unmatched.unclosed_span { - err.span_label(sp, "unclosed delimiter"); - } + spans.push(sp); + }; + let err = MismatchedClosingDelimiter { + spans, + delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(), + unmatched: unmatched.found_span, + opening_candidate: unmatched.candidate_span, + unclosed: unmatched.unclosed_span, + } + .into_diagnostic(&sess.span_diagnostic); Some(err) } |