diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:20:29 +0000 |
commit | 631cd5845e8de329d0e227aaa707d7ea228b8f8f (patch) | |
tree | a1b87c8f8cad01cf18f7c5f57a08f102771ed303 /compiler/rustc_parse | |
parent | Adding debian version 1.69.0+dfsg1-1. (diff) | |
download | rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.tar.xz rustc-631cd5845e8de329d0e227aaa707d7ea228b8f8f.zip |
Merging upstream version 1.70.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_parse')
-rw-r--r-- | compiler/rustc_parse/messages.ftl (renamed from compiler/rustc_parse/locales/en-US.ftl) | 18 | ||||
-rw-r--r-- | compiler/rustc_parse/src/errors.rs | 55 | ||||
-rw-r--r-- | compiler/rustc_parse/src/lexer/diagnostics.rs | 8 | ||||
-rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 6 | ||||
-rw-r--r-- | compiler/rustc_parse/src/lexer/tokentrees.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_parse/src/lexer/unicode_chars.rs | 4 | ||||
-rw-r--r-- | compiler/rustc_parse/src/lib.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 247 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 65 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 51 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 68 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 40 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 12 | ||||
-rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 9 |
16 files changed, 312 insertions, 289 deletions
diff --git a/compiler/rustc_parse/locales/en-US.ftl b/compiler/rustc_parse/messages.ftl index e76e91fc1..f11d0ed0f 100644 --- a/compiler/rustc_parse/locales/en-US.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -336,7 +336,7 @@ parse_expected_identifier_found_reserved_keyword = expected identifier, found re parse_expected_identifier_found_doc_comment = expected identifier, found doc comment parse_expected_identifier = expected identifier -parse_sugg_escape_to_use_as_identifier = escape `{$ident_name}` to use it as an identifier +parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma @@ -412,8 +412,7 @@ parse_fn_ptr_with_generics = function pointer types may not have generic paramet *[false] a } `for` parameter list -parse_invalid_identifier_with_leading_number = expected identifier, found number literal - .label = identifiers cannot start with a number +parse_invalid_identifier_with_leading_number = identifiers cannot start with a number parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn` .suggestion = replace `fn` with `impl` here @@ -710,7 +709,7 @@ parse_zero_chars = empty character literal parse_lone_slash = invalid trailing slash in literal .label = {parse_lone_slash} -parse_unskipped_whitespace = non-ASCII whitespace symbol '{$ch}' is not skipped +parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped .label = {parse_unskipped_whitespace} parse_multiple_skipped_lines = multiple lines skipped by escaped newline @@ -732,3 +731,14 @@ parse_unknown_start_of_token = unknown start of token: {$escaped} [one] once more *[other] {$repeats} more times } + +parse_box_syntax_removed = `box_syntax` has been removed + .suggestion = use `Box::new()` instead + +parse_bad_return_type_notation_output = + return type not allowed with return type notation + .suggestion = remove the return type + +parse_bad_return_type_notation_dotdot = + return type notation uses `()` instead of `(..)` for elided arguments + .suggestion = remove the `..` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 1662db36d..069217165 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -888,12 +888,12 @@ pub(crate) struct InvalidMetaItem { #[derive(Subdiagnostic)] #[suggestion( - parse_sugg_escape_to_use_as_identifier, + parse_sugg_escape_identifier, style = "verbose", applicability = "maybe-incorrect", code = "r#" )] -pub(crate) struct SuggEscapeToUseAsIdentifier { +pub(crate) struct SuggEscapeIdentifier { #[primary_span] pub span: Span, pub ident_name: String, @@ -937,8 +937,9 @@ impl ExpectedIdentifierFound { pub(crate) struct ExpectedIdentifier { pub span: Span, pub token: Token, - pub suggest_raw: Option<SuggEscapeToUseAsIdentifier>, + pub suggest_raw: Option<SuggEscapeIdentifier>, pub suggest_remove_comma: Option<SuggRemoveComma>, + pub help_cannot_start_number: Option<HelpIdentifierStartsWithNumber>, } impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { @@ -975,10 +976,21 @@ impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier { sugg.add_to_diagnostic(&mut diag); } + if let Some(help) = self.help_cannot_start_number { + help.add_to_diagnostic(&mut diag); + } + diag } } +#[derive(Subdiagnostic)] +#[help(parse_invalid_identifier_with_leading_number)] +pub(crate) struct HelpIdentifierStartsWithNumber { + #[primary_span] + pub num_span: Span, +} + pub(crate) struct ExpectedSemi { pub span: Span, pub token: Token, @@ -1208,14 +1220,6 @@ pub(crate) struct SelfParamNotFirst { } #[derive(Diagnostic)] -#[diag(parse_invalid_identifier_with_leading_number)] -pub(crate) struct InvalidIdentiferStartsWithNumber { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(parse_const_generic_without_braces)] pub(crate) struct ConstGenericWithoutBraces { #[primary_span] @@ -2299,3 +2303,32 @@ impl HelpUseLatestEdition { } } } + +#[derive(Diagnostic)] +#[diag(parse_box_syntax_removed)] +pub struct BoxSyntaxRemoved<'a> { + #[primary_span] + #[suggestion( + code = "Box::new({code})", + applicability = "machine-applicable", + style = "verbose" + )] + pub span: Span, + pub code: &'a str, +} + +#[derive(Diagnostic)] +#[diag(parse_bad_return_type_notation_output)] +pub(crate) struct BadReturnTypeNotationOutput { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(parse_bad_return_type_notation_dotdot)] +pub(crate) struct BadReturnTypeNotationDotDot { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 27f4428d3..9e6d27bf0 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -21,7 +21,7 @@ pub struct TokenTreeDiagInfo { pub matching_block_spans: Vec<(Span, Span)>, } -pub fn same_identation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { +pub fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Span) -> bool { match (sm.span_to_margin(open_sp), sm.span_to_margin(close_sp)) { (Some(open_padding), Some(close_padding)) => open_padding == close_padding, _ => false, @@ -67,13 +67,13 @@ pub fn report_suspicious_mismatch_block( let mut matched_spans: Vec<(Span, bool)> = diag_info .matching_block_spans .iter() - .map(|&(open, close)| (open.with_hi(close.lo()), same_identation_level(sm, open, close))) + .map(|&(open, close)| (open.with_hi(close.lo()), same_indentation_level(sm, open, close))) .collect(); // sort by `lo`, so the large block spans in the front - matched_spans.sort_by(|a, b| a.0.lo().cmp(&b.0.lo())); + matched_spans.sort_by_key(|(span, _)| span.lo()); - // We use larger block whose identation is well to cover those inner mismatched blocks + // We use larger block whose indentation is well to cover those inner mismatched blocks // O(N^2) here, but we are on error reporting path, so it is fine for i in 0..matched_spans.len() { let (block_span, same_ident) = matched_spans[i]; diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 59958a309..9e856c9f2 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -175,7 +175,7 @@ impl<'a> StringReader<'a> { if !sym.can_be_raw() { self.sess.emit_err(errors::CannotBeRawIdent { span, ident: sym }); } - self.sess.raw_identifier_spans.borrow_mut().push(span); + self.sess.raw_identifier_spans.push(span); token::Ident(sym, true) } rustc_lexer::TokenKind::UnknownPrefix => { @@ -553,8 +553,8 @@ impl<'a> StringReader<'a> { } if let Some(possible_offset) = possible_offset { - let lo = start + BytePos(possible_offset as u32); - let hi = lo + BytePos(found_terminators as u32); + let lo = start + BytePos(possible_offset); + let hi = lo + BytePos(found_terminators); let span = self.mk_sp(lo, hi); err.span_suggestion( span, diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 36fd1e37d..7c2c08951 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -1,5 +1,5 @@ use super::diagnostics::report_suspicious_mismatch_block; -use super::diagnostics::same_identation_level; +use super::diagnostics::same_indentation_level; use super::diagnostics::TokenTreeDiagInfo; use super::{StringReader, UnmatchedDelim}; use rustc_ast::token::{self, Delimiter, Token}; @@ -153,7 +153,7 @@ impl<'a> TokenTreesReader<'a> { unclosed_delimiter = Some(sp); }; for (brace, brace_span) in &self.diag_info.open_braces { - if same_identation_level(&sm, self.token.span, *brace_span) + if same_indentation_level(&sm, self.token.span, *brace_span) && brace == &close_delim { // high likelihood of these two corresponding diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs index d4f971d5b..1f027c08f 100644 --- a/compiler/rustc_parse/src/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -336,8 +336,8 @@ const ASCII_ARRAY: &[(&str, &str, Option<token::TokenKind>)] = &[ ("\"", "Quotation Mark", None), ]; -pub(super) fn check_for_substitution<'a>( - reader: &StringReader<'a>, +pub(super) fn check_for_substitution( + reader: &StringReader<'_>, pos: BytePos, ch: char, count: usize, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index d1c3fd0cd..17466cd0e 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -36,7 +36,7 @@ pub mod validate_attr; mod errors; -fluent_messages! { "../locales/en-US.ftl" } +fluent_messages! { "../messages.ftl" } // A bunch of utility functions of the form `parse_<thing>_from_<source>` // where <thing> includes crate, expr, item, stmt, tts, and one that diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a051dbe9f..e03ce5d71 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -6,20 +6,19 @@ use super::{ use crate::errors::{ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg, - ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentOnParamType, - DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, - GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, InInTypo, - IncorrectAwait, IncorrectSemicolon, IncorrectUseOfAwait, ParenthesesInForHead, - ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, - QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, - StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, StructLiteralNeedingParensSugg, - SuggEscapeToUseAsIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, - UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, - UseEqInstead, + ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything, + DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg, + GenericParamsWithoutAngleBrackets, GenericParamsWithoutAngleBracketsSugg, + HelpIdentifierStartsWithNumber, InInTypo, IncorrectAwait, IncorrectSemicolon, + IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, + PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, + StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, + StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, + UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, + UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; use crate::fluent_generated as fluent; -use crate::lexer::UnmatchedDelim; use crate::parser; use rustc_ast as ast; use rustc_ast::ptr::P; @@ -39,7 +38,7 @@ use rustc_errors::{ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{Span, SpanSnippetError, DUMMY_SP}; +use rustc_span::{Span, SpanSnippetError, Symbol, DUMMY_SP}; use std::mem::take; use std::ops::{Deref, DerefMut}; use thin_vec::{thin_vec, ThinVec}; @@ -220,7 +219,6 @@ impl MultiSugg { /// is dropped. pub struct SnapshotParser<'a> { parser: Parser<'a>, - unclosed_delims: Vec<UnmatchedDelim>, } impl<'a> Deref for SnapshotParser<'a> { @@ -255,34 +253,36 @@ impl<'a> Parser<'a> { &self.sess.span_diagnostic } - /// Replace `self` with `snapshot.parser` and extend `unclosed_delims` with `snapshot.unclosed_delims`. - /// This is to avoid losing unclosed delims errors `create_snapshot_for_diagnostic` clears. + /// Replace `self` with `snapshot.parser`. pub(super) fn restore_snapshot(&mut self, snapshot: SnapshotParser<'a>) { *self = snapshot.parser; - self.unclosed_delims.extend(snapshot.unclosed_delims); - } - - pub fn unclosed_delims(&self) -> &[UnmatchedDelim] { - &self.unclosed_delims } /// Create a snapshot of the `Parser`. pub fn create_snapshot_for_diagnostic(&self) -> SnapshotParser<'a> { - let mut snapshot = self.clone(); - let unclosed_delims = self.unclosed_delims.clone(); - // Clear `unclosed_delims` in snapshot to avoid - // duplicate errors being emitted when the `Parser` - // is dropped (which may or may not happen, depending - // if the parsing the snapshot is created for is successful) - snapshot.unclosed_delims.clear(); - SnapshotParser { parser: snapshot, unclosed_delims } + let snapshot = self.clone(); + SnapshotParser { parser: snapshot } } pub(super) fn span_to_snippet(&self, span: Span) -> Result<String, SpanSnippetError> { self.sess.source_map().span_to_snippet(span) } - pub(super) fn expected_ident_found(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + /// Emits an error with suggestions if an identifier was expected but not found. + /// + /// Returns a possibly recovered identifier. + pub(super) fn expected_ident_found( + &mut self, + recover: bool, + ) -> PResult<'a, (Ident, /* is_raw */ bool)> { + if let TokenKind::DocComment(..) = self.prev_token.kind { + return Err(DocCommentDoesNotDocumentAnything { + span: self.prev_token.span, + missing_comma: None, + } + .into_diagnostic(&self.sess.span_diagnostic)); + } + let valid_follow = &[ TokenKind::Eq, TokenKind::Colon, @@ -294,38 +294,61 @@ impl<'a> Parser<'a> { TokenKind::CloseDelim(Delimiter::Brace), TokenKind::CloseDelim(Delimiter::Parenthesis), ]; - let suggest_raw = match self.token.ident() { - Some((ident, false)) - if ident.is_raw_guess() - && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) => - { - Some(SuggEscapeToUseAsIdentifier { - span: ident.span.shrink_to_lo(), - // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, - // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` - ident_name: ident.name.to_string(), - }) - } - _ => None, - }; + + let mut recovered_ident = None; + // we take this here so that the correct original token is retained in + // the diagnostic, regardless of eager recovery. + let bad_token = self.token.clone(); + + // suggest prepending a keyword in identifier position with `r#` + let suggest_raw = if let Some((ident, false)) = self.token.ident() + && ident.is_raw_guess() + && self.look_ahead(1, |t| valid_follow.contains(&t.kind)) + { + recovered_ident = Some((ident, true)); + + // `Symbol::to_string()` is different from `Symbol::into_diagnostic_arg()`, + // which uses `Symbol::to_ident_string()` and "helpfully" adds an implicit `r#` + let ident_name = ident.name.to_string(); + + Some(SuggEscapeIdentifier { + span: ident.span.shrink_to_lo(), + ident_name + }) + } else { None }; let suggest_remove_comma = if self.token == token::Comma && self.look_ahead(1, |t| t.is_ident()) { - Some(SuggRemoveComma { span: self.token.span }) + if recover { + self.bump(); + recovered_ident = self.ident_or_err(false).ok(); + }; + + Some(SuggRemoveComma { span: bad_token.span }) } else { None }; + let help_cannot_start_number = self.is_lit_bad_ident().map(|(len, valid_portion)| { + let (invalid, valid) = self.token.span.split_at(len as u32); + + recovered_ident = Some((Ident::new(valid_portion, valid), false)); + + HelpIdentifierStartsWithNumber { num_span: invalid } + }); + let err = ExpectedIdentifier { - span: self.token.span, - token: self.token.clone(), + span: bad_token.span, + token: bad_token, suggest_raw, suggest_remove_comma, + help_cannot_start_number, }; let mut err = err.into_diagnostic(&self.sess.span_diagnostic); // if the token we have is a `<` // it *might* be a misplaced generic + // FIXME: could we recover with this? if self.token == token::Lt { // all keywords that could have generic applied let valid_prev_keywords = @@ -376,7 +399,38 @@ impl<'a> Parser<'a> { } } - err + if let Some(recovered_ident) = recovered_ident && recover { + err.emit(); + Ok(recovered_ident) + } else { + Err(err) + } + } + + pub(super) fn expected_ident_found_err(&mut self) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + self.expected_ident_found(false).unwrap_err() + } + + /// Checks if the current token is a integer or float literal and looks like + /// it could be a invalid identifier with digits at the start. + /// + /// Returns the number of characters (bytes) composing the invalid portion + /// of the identifier and the valid portion of the identifier. + pub(super) fn is_lit_bad_ident(&mut self) -> Option<(usize, Symbol)> { + // ensure that the integer literal is followed by a *invalid* + // suffix: this is how we know that it is a identifier with an + // invalid beginning. + if let token::Literal(Lit { + kind: token::LitKind::Integer | token::LitKind::Float, + symbol, + suffix: Some(suffix), // no suffix makes it a valid literal + }) = self.token.kind + && rustc_ast::MetaItemLit::from_token(&self.token).is_none() + { + Some((symbol.as_str().len(), suffix)) + } else { + None + } } pub(super) fn expected_one_of_not_found( @@ -579,21 +633,6 @@ impl<'a> Parser<'a> { } else { label_sp }; - match self.recover_closing_delimiter( - &expected - .iter() - .filter_map(|tt| match tt { - TokenType::Token(t) => Some(t.clone()), - _ => None, - }) - .collect::<Vec<_>>(), - err, - ) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } if self.check_too_many_raw_str_terminators(&mut err) { if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) { @@ -950,8 +989,7 @@ impl<'a> Parser<'a> { } if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) { // Recover from bad turbofish: `foo.collect::Vec<_>()`. - let args = AngleBracketedArgs { args, span }.into(); - segment.args = args; + segment.args = Some(AngleBracketedArgs { args, span }.into()); self.sess.emit_err(GenericParamsWithoutAngleBrackets { span, @@ -1573,12 +1611,6 @@ impl<'a> Parser<'a> { ); let mut err = self.struct_span_err(sp, &msg); let label_exp = format!("expected `{token_str}`"); - match self.recover_closing_delimiter(&[t.clone()], err) { - Err(e) => err = e, - Ok(recovered) => { - return Ok(recovered); - } - } let sm = self.sess.source_map(); if !sm.is_multiline(prev_sp.until(sp)) { // When the spans are in the same line, it means that the only content @@ -1795,81 +1827,6 @@ impl<'a> Parser<'a> { } } - pub(super) fn recover_closing_delimiter( - &mut self, - tokens: &[TokenKind], - mut err: DiagnosticBuilder<'a, ErrorGuaranteed>, - ) -> PResult<'a, bool> { - let mut pos = None; - // We want to use the last closing delim that would apply. - for (i, unmatched) in self.unclosed_delims.iter().enumerate().rev() { - if tokens.contains(&token::CloseDelim(unmatched.expected_delim)) - && Some(self.token.span) > unmatched.unclosed_span - { - pos = Some(i); - } - } - match pos { - Some(pos) => { - // Recover and assume that the detected unclosed delimiter was meant for - // this location. Emit the diagnostic and act as if the delimiter was - // present for the parser's sake. - - // Don't attempt to recover from this unclosed delimiter more than once. - let unmatched = self.unclosed_delims.remove(pos); - let delim = TokenType::Token(token::CloseDelim(unmatched.expected_delim)); - if unmatched.found_delim.is_none() { - // We encountered `Eof`, set this fact here to avoid complaining about missing - // `fn main()` when we found place to suggest the closing brace. - *self.sess.reached_eof.borrow_mut() = true; - } - - // We want to suggest the inclusion of the closing delimiter where it makes - // the most sense, which is immediately after the last token: - // - // {foo(bar {}} - // ^ ^ - // | | - // | help: `)` may belong here - // | - // unclosed delimiter - if let Some(sp) = unmatched.unclosed_span { - let mut primary_span: Vec<Span> = - err.span.primary_spans().iter().cloned().collect(); - primary_span.push(sp); - let mut primary_span: MultiSpan = primary_span.into(); - for span_label in err.span.span_labels() { - if let Some(label) = span_label.label { - primary_span.push_span_label(span_label.span, label); - } - } - err.set_span(primary_span); - err.span_label(sp, "unclosed delimiter"); - } - // Backticks should be removed to apply suggestions. - let mut delim = delim.to_string(); - delim.retain(|c| c != '`'); - err.span_suggestion_short( - self.prev_token.span.shrink_to_hi(), - &format!("`{delim}` may belong here"), - delim, - Applicability::MaybeIncorrect, - ); - if unmatched.found_delim.is_none() { - // Encountered `Eof` when lexing blocks. Do not recover here to avoid knockdown - // errors which would be emitted elsewhere in the parser and let other error - // recovery consume the rest of the file. - Err(err) - } else { - err.emit(); - self.expected_tokens.clear(); // Reduce the number of errors. - Ok(true) - } - } - _ => Err(err), - } - } - /// Eats tokens until we can be relatively sure we reached the end of the /// statement. This is something of a best-effort heuristic. /// diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 95a7ca80d..03c82fbd3 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -8,6 +8,7 @@ use super::{ use crate::errors; use crate::maybe_recover_from_interpolated_ty_qpath; +use ast::{Path, PathSegment}; use core::mem; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; @@ -29,6 +30,7 @@ use rustc_session::errors::{report_lit_error, ExprParenthesesNeeded}; use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::symbol::kw::PathRoot; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Pos}; use thin_vec::{thin_vec, ThinVec}; @@ -636,11 +638,27 @@ impl<'a> Parser<'a> { self.parse_expr_unary(lo, UnOp::Not) } - /// Parse `box expr`. + /// Parse `box expr` - this syntax has been removed, but we still parse this + /// for now to provide an automated way to fix usages of it fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> { let (span, expr) = self.parse_expr_prefix_common(lo)?; - self.sess.gated_spans.gate(sym::box_syntax, span); - Ok((span, ExprKind::Box(expr))) + let code = self.sess.source_map().span_to_snippet(span.with_lo(lo.hi())).unwrap(); + self.sess.emit_err(errors::BoxSyntaxRemoved { span, code: code.trim() }); + // So typechecking works, parse `box <expr>` as `::std::boxed::Box::new(expr)` + let path = Path { + span, + segments: [ + PathSegment::from_ident(Ident::with_dummy_span(PathRoot)), + PathSegment::from_ident(Ident::with_dummy_span(sym::std)), + PathSegment::from_ident(Ident::from_str("boxed")), + PathSegment::from_ident(Ident::from_str("Box")), + PathSegment::from_ident(Ident::with_dummy_span(sym::new)), + ] + .into(), + tokens: None, + }; + let path = self.mk_expr(span, ExprKind::Path(None, path)); + Ok((span, self.mk_call(path, ThinVec::from([expr])))) } fn is_mistaken_not_ident_negation(&self) -> bool { @@ -1394,19 +1412,6 @@ impl<'a> Parser<'a> { self.parse_expr_let() } else if self.eat_keyword(kw::Underscore) { Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore)) - } else if !self.unclosed_delims.is_empty() && self.check(&token::Semi) { - // Don't complain about bare semicolons after unclosed braces - // recovery in order to keep the error count down. Fixing the - // delimiters will possibly also fix the bare semicolon found in - // expression context. For example, silence the following error: - // - // error: expected expression, found `;` - // --> file.rs:2:13 - // | - // 2 | foo(bar(; - // | ^ expected expression - self.bump(); - Ok(self.mk_expr_err(self.token.span)) } else if self.token.uninterpolated_span().rust_2018() { // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { @@ -1838,20 +1843,14 @@ impl<'a> Parser<'a> { &mut self, mk_lit_char: impl FnOnce(Symbol, Span) -> L, ) -> PResult<'a, L> { - if let token::Interpolated(inner) = &self.token.kind { - let expr = match inner.as_ref() { - token::NtExpr(expr) => Some(expr), - token::NtLiteral(expr) => Some(expr), - _ => None, - }; - if let Some(expr) = expr { - if matches!(expr.kind, ExprKind::Err) { - let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } - .into_diagnostic(&self.sess.span_diagnostic); - err.downgrade_to_delayed_bug(); - return Err(err); - } - } + if let token::Interpolated(nt) = &self.token.kind + && let token::NtExpr(e) | token::NtLiteral(e) = &**nt + && matches!(e.kind, ExprKind::Err) + { + let mut err = errors::InvalidInterpolatedExpression { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + err.downgrade_to_delayed_bug(); + return Err(err); } let token = self.token.clone(); let err = |self_: &Self| { @@ -2118,7 +2117,7 @@ impl<'a> Parser<'a> { ClosureBinder::NotPresent }; - let constness = self.parse_closure_constness(Case::Sensitive); + let constness = self.parse_closure_constness(); let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; @@ -2768,7 +2767,7 @@ impl<'a> Parser<'a> { (token::DotDotEq, token::Gt) ) { // `error_inclusive_range_match_arrow` handles cases like `0..=> {}`, - // so we supress the error here + // so we suppress the error here err.delay_as_bug(); this.bump(); } else { @@ -2912,7 +2911,7 @@ impl<'a> Parser<'a> { self.expect_keyword(kw::Async)?; let capture_clause = self.parse_capture_clause()?; let (attrs, body) = self.parse_inner_attrs_and_block()?; - let kind = ExprKind::Async(capture_clause, DUMMY_NODE_ID, body); + let kind = ExprKind::Async(capture_clause, body); Ok(self.mk_expr_with_attrs(lo.to(self.prev_token.span), kind, attrs)) } diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index 8d0f168e0..f8ef1307c 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -53,7 +53,7 @@ impl<'a> Parser<'a> { let snapshot = self.create_snapshot_for_diagnostic(); match self.parse_ty() { Ok(p) => { - if let TyKind::ImplTrait(_, bounds) = &(*p).kind { + if let TyKind::ImplTrait(_, bounds) = &p.kind { let span = impl_span.to(self.token.span.shrink_to_lo()); let mut err = self.struct_span_err( span, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 9d9ae154a..6422b8ac1 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -3,6 +3,7 @@ use crate::errors; use super::diagnostics::{dummy_arg, ConsumeClosingDelim}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, TrailingToken}; +use ast::StaticItem; use rustc_ast::ast::*; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, TokenKind}; @@ -125,16 +126,13 @@ impl<'a> Parser<'a> { return Ok(Some(item.into_inner())); }; - let mut unclosed_delims = vec![]; let item = self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| { let item = this.parse_item_common_(attrs, mac_allowed, attrs_allowed, fn_parse_mode); - unclosed_delims.append(&mut this.unclosed_delims); Ok((item?, TrailingToken::None)) })?; - self.unclosed_delims.append(&mut unclosed_delims); Ok(item) } @@ -230,7 +228,7 @@ impl<'a> Parser<'a> { self.bump(); // `static` let m = self.parse_mutability(); let (ident, ty, expr) = self.parse_item_global(Some(m))?; - (ident, ItemKind::Static(ty, m, expr)) + (ident, ItemKind::Static(Box::new(StaticItem { ty, mutability: m, expr }))) } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -239,7 +237,7 @@ impl<'a> Parser<'a> { } else { self.recover_const_mut(const_span); let (ident, ty, expr) = self.parse_item_global(None)?; - (ident, ItemKind::Const(def_(), ty, expr)) + (ident, ItemKind::Const(Box::new(ConstItem { defaultness: def_(), ty, expr }))) } } else if self.check_keyword(kw::Trait) || self.check_auto_or_unsafe_trait_item() { // TRAIT ITEM @@ -865,9 +863,13 @@ impl<'a> Parser<'a> { let kind = match AssocItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Static(a, _, b) => { + ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => { self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span }); - AssocItemKind::Const(Defaultness::Final, a, b) + AssocItemKind::Const(Box::new(ConstItem { + defaultness: Defaultness::Final, + ty, + expr, + })) } _ => return self.error_bad_item_kind(span, &kind, "`trait`s or `impl`s"), }, @@ -1117,12 +1119,12 @@ impl<'a> Parser<'a> { let kind = match ForeignItemKind::try_from(kind) { Ok(kind) => kind, Err(kind) => match kind { - ItemKind::Const(_, a, b) => { + ItemKind::Const(box ConstItem { ty, expr, .. }) => { self.sess.emit_err(errors::ExternItemCannotBeConst { ident_span: ident.span, const_span: span.with_hi(ident.span.lo()), }); - ForeignItemKind::Static(a, Mutability::Not, b) + ForeignItemKind::Static(ty, Mutability::Not, expr) } _ => return self.error_bad_item_kind(span, &kind, "`extern` blocks"), }, @@ -1184,7 +1186,7 @@ impl<'a> Parser<'a> { defaultness: Defaultness, ) -> PResult<'a, ItemInfo> { let impl_span = self.token.span; - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); // Only try to recover if this is implementing a trait for a type let mut impl_info = match self.parse_item_impl(attrs, defaultness) { @@ -1747,7 +1749,7 @@ impl<'a> Parser<'a> { /// Parses a field identifier. Specialized version of `parse_ident_common` /// for better diagnostics and suggestions. fn parse_field_ident(&mut self, adt_ty: &str, lo: Span) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(true)?; if !is_raw && ident.is_reserved() { let snapshot = self.create_snapshot_for_diagnostic(); let err = if self.check_fn_front_matter(false, Case::Sensitive) { @@ -1779,7 +1781,7 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else if self.eat_keyword(kw::Struct) { @@ -1795,11 +1797,11 @@ impl<'a> Parser<'a> { Err(err) => { err.cancel(); self.restore_snapshot(snapshot); - self.expected_ident_found() + self.expected_ident_found_err() } } } else { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if self.eat_keyword_noexpect(kw::Let) && let removal_span = self.prev_token.span.until(self.token.span) && let Ok(ident) = self.parse_ident_common(false) @@ -1960,21 +1962,12 @@ impl<'a> Parser<'a> { // FIXME: This will make us not emit the help even for declarative // macros within the same crate (that we can fix), which is sad. if !span.from_expansion() { - if self.unclosed_delims.is_empty() { - let DelimSpan { open, close } = args.dspan; - err.multipart_suggestion( - "change the delimiters to curly braces", - vec![(open, "{".to_string()), (close, '}'.to_string())], - Applicability::MaybeIncorrect, - ); - } else { - err.span_suggestion( - span, - "change the delimiters to curly braces", - " { /* items */ }", - Applicability::HasPlaceholders, - ); - } + let DelimSpan { open, close } = args.dspan; + err.multipart_suggestion( + "change the delimiters to curly braces", + vec![(open, "{".to_string()), (close, '}'.to_string())], + Applicability::MaybeIncorrect, + ); err.span_suggestion( span.shrink_to_hi(), "add a semicolon", diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index da82e4724..aa57b8047 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -29,6 +29,7 @@ use rustc_ast::{Async, AttrArgs, AttrArgsEq, Expr, ExprKind, MacDelimiter, Mutab use rustc_ast::{HasAttrs, HasTokens, Unsafe, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::Ordering; use rustc_errors::PResult; use rustc_errors::{ Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, @@ -42,8 +43,7 @@ use thin_vec::ThinVec; use tracing::debug; use crate::errors::{ - DocCommentDoesNotDocumentAnything, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, - NonStringAbiLiteral, + IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral, }; bitflags::bitflags! { @@ -146,10 +146,7 @@ pub struct Parser<'a> { /// See the comments in the `parse_path_segment` function for more details. unmatched_angle_bracket_count: u32, max_angle_bracket_count: u32, - /// A list of all unclosed delimiters found by the lexer. If an entry is used for error recovery - /// it gets removed from here. Every entry left at the end gets emitted as an independent - /// error. - pub(super) unclosed_delims: Vec<UnmatchedDelim>, + last_unexpected_token_span: Option<Span>, /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it /// looked like it could have been a mistyped path or literal `Option:Some(42)`). @@ -168,7 +165,7 @@ pub struct Parser<'a> { // 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<'_>, 312); +rustc_data_structures::static_assert_size!(Parser<'_>, 288); /// Stores span information about a closure. #[derive(Clone)] @@ -215,12 +212,6 @@ struct CaptureState { inner_attr_ranges: FxHashMap<AttrId, ReplaceRange>, } -impl<'a> Drop for Parser<'a> { - fn drop(&mut self) { - emit_unclosed_delims(&mut self.unclosed_delims, &self.sess); - } -} - /// Iterator over a `TokenStream` that produces `Token`s. It's a bit odd that /// we (a) lex tokens into a nice tree structure (`TokenStream`), and then (b) /// use this type to emit them as a linear sequence. But a linear sequence is @@ -478,7 +469,6 @@ impl<'a> Parser<'a> { desugar_doc_comments, unmatched_angle_bracket_count: 0, max_angle_bracket_count: 0, - unclosed_delims: Vec::new(), last_unexpected_token_span: None, last_type_ascription: None, subparser_name, @@ -562,21 +552,11 @@ impl<'a> Parser<'a> { self.parse_ident_common(true) } - 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(..) => DocCommentDoesNotDocumentAnything { - span: self.prev_token.span, - missing_comma: None, - } - .into_diagnostic(&self.sess.span_diagnostic), - _ => self.expected_ident_found(), - }) - } - fn parse_ident_common(&mut self, recover: bool) -> PResult<'a, Ident> { - let (ident, is_raw) = self.ident_or_err()?; + let (ident, is_raw) = self.ident_or_err(recover)?; + if !is_raw && ident.is_reserved() { - let mut err = self.expected_ident_found(); + let mut err = self.expected_ident_found_err(); if recover { err.emit(); } else { @@ -587,6 +567,21 @@ impl<'a> Parser<'a> { Ok(ident) } + fn ident_or_err(&mut self, recover: bool) -> PResult<'a, (Ident, /* is_raw */ bool)> { + let result = self.token.ident().ok_or_else(|| self.expected_ident_found(recover)); + + let (ident, is_raw) = match result { + Ok(ident) => ident, + Err(err) => match err { + // we recovered! + Ok(ident) => ident, + Err(err) => return Err(err), + }, + }; + + Ok((ident, is_raw)) + } + /// Checks if the next token is `tok`, and returns `true` if so. /// /// This method will automatically add `tok` to `expected_tokens` if `tok` is not @@ -859,7 +854,6 @@ impl<'a> Parser<'a> { let mut recovered = false; let mut trailing = false; let mut v = ThinVec::new(); - let unclosed_delims = !self.unclosed_delims.is_empty(); while !self.expect_any_with_type(kets, expect) { if let token::CloseDelim(..) | token::Eof = self.token.kind { @@ -901,7 +895,7 @@ impl<'a> Parser<'a> { _ => { // Attempt to keep parsing if it was a similar separator. if let Some(tokens) = t.similar_tokens() { - if tokens.contains(&self.token.kind) && !unclosed_delims { + if tokens.contains(&self.token.kind) { self.bump(); } } @@ -1207,9 +1201,13 @@ impl<'a> Parser<'a> { self.parse_constness_(case, false) } - /// Parses constness for closures - fn parse_closure_constness(&mut self, case: Case) -> Const { - self.parse_constness_(case, true) + /// Parses constness for closures (case sensitive, feature-gated) + fn parse_closure_constness(&mut self) -> Const { + let constness = self.parse_constness_(Case::Sensitive, true); + if let Const::Yes(span) = constness { + self.sess.gated_spans.gate(sym::const_closures, span); + } + constness } fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const { @@ -1543,8 +1541,10 @@ pub(crate) fn make_unclosed_delims_error( } pub fn emit_unclosed_delims(unclosed_delims: &mut Vec<UnmatchedDelim>, sess: &ParseSess) { - *sess.reached_eof.borrow_mut() |= - unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()); + let _ = sess.reached_eof.fetch_or( + unclosed_delims.iter().any(|unmatched_delim| unmatched_delim.found_delim.is_none()), + Ordering::Relaxed, + ); for unmatched in unclosed_delims.drain(..) { if let Some(mut e) = make_unclosed_delims_error(unmatched, sess) { e.emit(); diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 8e920f1c4..2246002f5 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -391,7 +391,13 @@ impl<'a> Parser<'a> { } else { PatKind::Lit(const_expr) } - } else if self.can_be_ident_pat() { + // Don't eagerly error on semantically invalid tokens when matching + // declarative macros, as the input to those doesn't have to be + // semantically valid. For attribute/derive proc macros this is not the + // case, so doing the recovery for them is fine. + } else if self.can_be_ident_pat() + || (self.is_lit_bad_ident().is_some() && self.may_recover()) + { // Parse `ident @ pat` // This can give false positives and parse nullary enums, // they are dealt with later in resolve. @@ -590,7 +596,7 @@ impl<'a> Parser<'a> { // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`. if let token::Interpolated(nt) = &self.token.kind { if let token::NtPat(_) = **nt { - self.expected_ident_found().emit(); + self.expected_ident_found_err().emit(); } } diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index b50d2984a..c25c23d84 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -1,6 +1,6 @@ use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{Parser, Restrictions, TokenType}; -use crate::maybe_whole; +use crate::{errors, maybe_whole}; use rustc_ast::ptr::P; use rustc_ast::token::{self, Delimiter, Token, TokenKind}; use rustc_ast::{ @@ -290,6 +290,32 @@ impl<'a> Parser<'a> { })?; let span = lo.to(self.prev_token.span); AngleBracketedArgs { args, span }.into() + } else if self.may_recover() + && self.token.kind == token::OpenDelim(Delimiter::Parenthesis) + // FIXME(return_type_notation): Could also recover `...` here. + && self.look_ahead(1, |tok| tok.kind == token::DotDot) + { + self.bump(); + self.sess + .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span }); + self.bump(); + self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; + let span = lo.to(self.prev_token.span); + + if self.eat_noexpect(&token::RArrow) { + let lo = self.prev_token.span; + let ty = self.parse_ty()?; + self.sess + .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) }); + } + + ParenthesizedArgs { + span, + inputs: ThinVec::new(), + inputs_span: span, + output: ast::FnRetTy::Default(self.prev_token.span.shrink_to_hi()), + } + .into() } else { // `(T, U) -> R` let (inputs, _) = self.parse_paren_comma_seq(|p| p.parse_ty())?; @@ -300,7 +326,7 @@ impl<'a> Parser<'a> { ParenthesizedArgs { span, inputs, inputs_span, output }.into() }; - PathSegment { ident, args, id: ast::DUMMY_NODE_ID } + PathSegment { ident, args: Some(args), id: ast::DUMMY_NODE_ID } } else { // Generic arguments are not found. PathSegment::from_ident(ident) @@ -547,10 +573,16 @@ impl<'a> Parser<'a> { }; let span = lo.to(self.prev_token.span); - // Gate associated type bounds, e.g., `Iterator<Item: Ord>`. if let AssocConstraintKind::Bound { .. } = kind { - self.sess.gated_spans.gate(sym::associated_type_bounds, span); + if let Some(ast::GenericArgs::Parenthesized(args)) = &gen_args + && args.inputs.is_empty() + && matches!(args.output, ast::FnRetTy::Default(..)) + { + self.sess.gated_spans.gate(sym::return_type_notation, span); + } else { + self.sess.gated_spans.gate(sym::associated_type_bounds, span); + } } let constraint = AssocConstraint { id: ast::DUMMY_NODE_ID, ident, gen_args, kind, span }; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 92a22ffc2..fbe5b88c4 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -273,7 +273,6 @@ impl<'a> Parser<'a> { self.bump(); } - self.report_invalid_identifier_error()?; let (pat, colon) = self.parse_pat_before_ty(None, RecoverComma::Yes, PatternLocation::LetBinding)?; @@ -366,17 +365,6 @@ impl<'a> Parser<'a> { Ok(P(ast::Local { ty, pat, kind, id: DUMMY_NODE_ID, span: lo.to(hi), attrs, tokens: None })) } - /// report error for `let 1x = 123` - pub fn report_invalid_identifier_error(&mut self) -> PResult<'a, ()> { - if let token::Literal(lit) = self.token.uninterpolate().kind && - rustc_ast::MetaItemLit::from_token(&self.token).is_none() && - (lit.kind == token::LitKind::Integer || lit.kind == token::LitKind::Float) && - self.look_ahead(1, |t| matches!(t.kind, token::Eq) || matches!(t.kind, token::Colon ) ) { - return Err(self.sess.create_err(errors::InvalidIdentiferStartsWithNumber { span: self.token.span })); - } - Ok(()) - } - fn check_let_else_init_bool_expr(&self, init: &ast::Expr) { if let ast::ExprKind::Binary(op, ..) = init.kind { if op.node.lazy() { diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 6fe4da71f..400c8dbe9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -624,10 +624,12 @@ impl<'a> Parser<'a> { /// /// Note that this does *not* parse bare trait objects. fn parse_dyn_ty(&mut self, impl_dyn_multi: &mut bool) -> PResult<'a, TyKind> { + let lo = self.token.span; self.bump(); // `dyn` // parse dyn* types let syntax = if self.eat(&TokenKind::BinOp(token::Star)) { + self.sess.gated_spans.gate(sym::dyn_star, lo.to(self.prev_token.span)); TraitObjectSyntax::DynStar } else { TraitObjectSyntax::Dyn @@ -1057,8 +1059,11 @@ impl<'a> Parser<'a> { output, } .into(); - *fn_path_segment = - ast::PathSegment { ident: fn_path_segment.ident, args, id: ast::DUMMY_NODE_ID }; + *fn_path_segment = ast::PathSegment { + ident: fn_path_segment.ident, + args: Some(args), + id: ast::DUMMY_NODE_ID, + }; // Convert parsed `<'a>` in `Fn<'a>` into `for<'a>`. let mut generic_params = lifetimes |