diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 11 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr.rs | 17 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/attr_wrapper.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 45 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 49 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 2 |
9 files changed, 102 insertions, 68 deletions
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 84494eab855..96e1c0e3c6d 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -333,6 +333,17 @@ pub(crate) struct InvalidBlockMacroSegment { pub span: Span, #[label] pub context: Span, + #[subdiagnostic] + pub wrap: WrapInExplicitBlock, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")] +pub(crate) struct WrapInExplicitBlock { + #[suggestion_part(code = "{{ ")] + pub lo: Span, + #[suggestion_part(code = " }}")] + pub hi: Span, } #[derive(Diagnostic)] diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index e1db19557cf..ee0abba1c17 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -422,15 +422,12 @@ impl<'a> Parser<'a> { } } -pub fn maybe_needs_tokens(attrs: &[ast::Attribute]) -> bool { - // One of the attributes may either itself be a macro, - // or expand to macro attributes (`cfg_attr`). - attrs.iter().any(|attr| { - if attr.is_doc_comment() { - return false; - } - attr.ident().map_or(true, |ident| { - ident.name == sym::cfg_attr || !rustc_feature::is_builtin_attr_name(ident.name) - }) +/// The attributes are complete if all attributes are either a doc comment or a builtin attribute other than `cfg_attr` +pub fn is_complete(attrs: &[ast::Attribute]) -> bool { + attrs.iter().all(|attr| { + attr.is_doc_comment() + || attr.ident().is_some_and(|ident| { + ident.name != sym::cfg_attr && rustc_feature::is_builtin_attr_name(ident.name) + }) }) } diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs index 1e6ac54964f..b579da098d8 100644 --- a/compiler/rustc_parse/src/parser/attr_wrapper.rs +++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs @@ -61,8 +61,8 @@ impl AttrWrapper { self.attrs.is_empty() } - pub fn maybe_needs_tokens(&self) -> bool { - crate::parser::attr::maybe_needs_tokens(&self.attrs) + pub fn is_complete(&self) -> bool { + crate::parser::attr::is_complete(&self.attrs) } } @@ -201,7 +201,7 @@ impl<'a> Parser<'a> { // by definition if matches!(force_collect, ForceCollect::No) // None of our outer attributes can require tokens (e.g. a proc-macro) - && !attrs.maybe_needs_tokens() + && attrs.is_complete() // If our target supports custom inner attributes, then we cannot bail // out early, since we may need to capture tokens for a custom inner attribute // invocation. @@ -244,9 +244,9 @@ impl<'a> Parser<'a> { // Now that we've parsed an AST node, we have more information available. if matches!(force_collect, ForceCollect::No) // We now have inner attributes available, so this check is more precise - // than `attrs.maybe_needs_tokens()` at the start of the function. + // than `attrs.is_complete()` at the start of the function. // As a result, we don't need to check `R::SUPPORTS_CUSTOM_INNER_ATTRS` - && !crate::parser::attr::maybe_needs_tokens(ret.attrs()) + && crate::parser::attr::is_complete(ret.attrs()) // Subtle: We call `has_cfg_or_cfg_attr` with the attrs from `ret`. // This ensures that we consider inner attributes (e.g. `#![cfg]`), // which require us to have tokens available diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 228eff1269f..c3cf6437afa 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -247,7 +247,7 @@ impl<'a> Parser<'a> { self.sess.span_diagnostic.struct_span_err(sp, m) } - pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: impl Into<DiagnosticMessage>) -> ! { + pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, m: impl Into<String>) -> ! { self.sess.span_diagnostic.span_bug(sp, m) } @@ -605,6 +605,22 @@ impl<'a> Parser<'a> { } } + if let TokenKind::Ident(prev, _) = &self.prev_token.kind + && let TokenKind::Ident(cur, _) = &self.token.kind + { + let concat = Symbol::intern(&format!("{}{}", prev, cur)); + let ident = Ident::new(concat, DUMMY_SP); + if ident.is_used_keyword() || ident.is_reserved() || ident.is_raw_guess() { + let span = self.prev_token.span.to(self.token.span); + err.span_suggestion_verbose( + span, + format!("consider removing the space to spell keyword `{}`", concat), + concat, + Applicability::MachineApplicable, + ); + } + } + // `pub` may be used for an item or `pub(crate)` if self.prev_token.is_ident_named(sym::public) && (self.token.can_begin_item() @@ -1418,8 +1434,9 @@ impl<'a> Parser<'a> { self.inc_dec_standalone_suggest(kind, spans).emit_verbose(&mut err) } IsStandalone::Subexpr => { - let Ok(base_src) = self.span_to_snippet(base.span) - else { return help_base_case(err, base) }; + let Ok(base_src) = self.span_to_snippet(base.span) else { + return help_base_case(err, base); + }; match kind.fixity { UnaryFixity::Pre => { self.prefix_inc_dec_suggest(base_src, kind, spans).emit(&mut err) diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index cea2a71c988..3ecdbc36248 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1013,9 +1013,15 @@ impl<'a> Parser<'a> { } fn error_unexpected_after_dot(&self) { - // FIXME Could factor this out into non_fatal_unexpected or something. let actual = pprust::token_to_string(&self.token); - self.sess.emit_err(errors::UnexpectedTokenAfterDot { span: self.token.span, actual }); + let span = self.token.span; + let sm = self.sess.source_map(); + let (span, actual) = match (&self.token.kind, self.subparser_name) { + (token::Eof, Some(_)) if let Ok(actual) = sm.span_to_snippet(sm.next_point(span)) => + (span.shrink_to_hi(), actual.into()), + _ => (span, actual), + }; + self.sess.emit_err(errors::UnexpectedTokenAfterDot { span, actual }); } // We need an identifier or integer, but the next token is a float. @@ -1303,7 +1309,7 @@ impl<'a> Parser<'a> { /// Assuming we have just parsed `.`, continue parsing into an expression. fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> { - if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) { + if self.token.uninterpolated_span().at_least_rust_2018() && self.eat_keyword(kw::Await) { return Ok(self.mk_await_expr(self_arg, lo)); } @@ -1430,12 +1436,14 @@ impl<'a> Parser<'a> { self.parse_expr_yield() } else if self.is_do_yeet() { self.parse_expr_yeet() + } else if self.eat_keyword(kw::Become) { + self.parse_expr_become() } else if self.check_keyword(kw::Let) { self.parse_expr_let() } else if self.eat_keyword(kw::Underscore) { Ok(self.mk_expr(self.prev_token.span, ExprKind::Underscore)) - } else if self.token.uninterpolated_span().rust_2018() { - // `Span::rust_2018()` is somewhat expensive; don't get it repeatedly. + } else if self.token.uninterpolated_span().at_least_rust_2018() { + // `Span:.at_least_rust_2018()` is somewhat expensive; don't get it repeatedly. if self.check_keyword(kw::Async) { if self.is_async_block() { // Check for `async {` and `async move {`. @@ -1746,6 +1754,16 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `"become" expr`, with `"become"` token already eaten. + fn parse_expr_become(&mut self) -> PResult<'a, P<Expr>> { + let lo = self.prev_token.span; + let kind = ExprKind::Become(self.parse_expr()?); + let span = lo.to(self.prev_token.span); + self.sess.gated_spans.gate(sym::explicit_tail_calls, span); + let expr = self.mk_expr(span, kind); + self.maybe_recover_from_bad_qpath(expr) + } + /// Parse `"break" (('label (:? expr)?) | expr?)` with `"break"` token already eaten. /// If the label is followed immediately by a `:` token, the label and `:` are /// parsed as part of the expression (i.e. a labeled loop). The language team has @@ -2023,17 +2041,14 @@ impl<'a> Parser<'a> { let recovered = self.recover_after_dot(); let token = recovered.as_ref().unwrap_or(&self.token); match token::Lit::from_token(token) { - Some(token_lit) => { - match MetaItemLit::from_token_lit(token_lit, token.span) { + Some(lit) => { + match MetaItemLit::from_token_lit(lit, token.span) { Ok(lit) => { self.bump(); Some(lit) } Err(err) => { - let span = token.span; - let token::Literal(lit) = token.kind else { - unreachable!(); - }; + let span = token.uninterpolated_span(); self.bump(); report_lit_error(&self.sess, err, lit, span); // Pack possible quotes and prefixes from the original literal into @@ -2177,6 +2192,10 @@ impl<'a> Parser<'a> { self.sess.emit_err(errors::InvalidBlockMacroSegment { span: self.token.span, context: lo.to(self.token.span), + wrap: errors::WrapInExplicitBlock { + lo: self.token.span.shrink_to_lo(), + hi: self.token.span.shrink_to_hi(), + }, }); } @@ -2211,7 +2230,7 @@ impl<'a> Parser<'a> { let movability = if self.eat_keyword(kw::Static) { Movability::Static } else { Movability::Movable }; - let asyncness = if self.token.uninterpolated_span().rust_2018() { + let asyncness = if self.token.uninterpolated_span().at_least_rust_2018() { self.parse_asyncness(Case::Sensitive) } else { Async::No @@ -2995,7 +3014,7 @@ impl<'a> Parser<'a> { fn is_try_block(&self) -> bool { self.token.is_keyword(kw::Try) && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace)) - && self.token.uninterpolated_span().rust_2018() + && self.token.uninterpolated_span().at_least_rust_2018() } /// Parses an `async move? {...}` expression. diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 3783ec41b7e..1470180dea7 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2182,7 +2182,11 @@ impl<'a> Parser<'a> { // `extern ABI fn` || self.check_keyword_case(kw::Extern, case) && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus()) - && self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) + && (self.look_ahead(2, |t| t.is_keyword_case(kw::Fn, case)) || + // this branch is only for better diagnostic in later, `pub` is not allowed here + (self.may_recover() + && self.look_ahead(2, |t| t.is_keyword(kw::Pub)) + && self.look_ahead(3, |t| t.is_keyword_case(kw::Fn, case)))) } /// Parses all the "front matter" (or "qualifiers") for a `fn` declaration, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index c23420661fa..2e1a61e634e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1210,7 +1210,8 @@ impl<'a> Parser<'a> { fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const { // Avoid const blocks and const closures to be parsed as const items if (self.check_const_closure() == is_closure) - && self.look_ahead(1, |t| t != &token::OpenDelim(Delimiter::Brace)) + && !self + .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()) && self.eat_keyword_case(kw::Const, case) { Const::Yes(self.prev_token.uninterpolated_span()) @@ -1289,7 +1290,9 @@ impl<'a> Parser<'a> { delimited.then(|| { // We've confirmed above that there is a delimiter so unwrapping is OK. - let TokenTree::Delimited(dspan, delim, tokens) = self.parse_token_tree() else { unreachable!() }; + let TokenTree::Delimited(dspan, delim, tokens) = self.parse_token_tree() else { + unreachable!() + }; DelimArgs { dspan, delim: MacDelimiter::from_token(delim).unwrap(), tokens } }) diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index fdf36517847..14891c45d81 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -8,7 +8,6 @@ use crate::errors::{ TrailingVertNotAllowed, UnexpectedLifetimeInPattern, UnexpectedVertVertBeforeFunctionParam, UnexpectedVertVertInPattern, }; -use crate::fluent_generated as fluent; use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole}; use rustc_ast::mut_visit::{noop_visit_pat, MutVisitor}; use rustc_ast::ptr::P; @@ -214,41 +213,25 @@ impl<'a> Parser<'a> { if let PatKind::Or(pats) = &pat.kind { let span = pat.span; - - if trailing_vert { - // We already emitted an error and suggestion to remove the trailing vert. Don't - // emit again. - - // FIXME(#100717): pass `TopLevelOrPatternNotAllowed::* { sub: None }` to - // `delay_span_bug()` instead of fluent message - self.sess.span_diagnostic.delay_span_bug( - span, - match syntax_loc { - PatternLocation::LetBinding => { - fluent::parse_or_pattern_not_allowed_in_let_binding - } - PatternLocation::FunctionParameter => { - fluent::parse_or_pattern_not_allowed_in_fn_parameters - } - }, - ); + let pat = pprust::pat_to_string(&pat); + let sub = if pats.len() == 1 { + Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat }) } else { - let pat = pprust::pat_to_string(&pat); - let sub = if pats.len() == 1 { - Some(TopLevelOrPatternNotAllowedSugg::RemoveLeadingVert { span, pat }) - } else { - Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) - }; + Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat }) + }; - self.sess.emit_err(match syntax_loc { - PatternLocation::LetBinding => { - TopLevelOrPatternNotAllowed::LetBinding { span, sub } - } - PatternLocation::FunctionParameter => { - TopLevelOrPatternNotAllowed::FunctionParameter { span, sub } - } - }); + let mut err = self.sess.create_err(match syntax_loc { + PatternLocation::LetBinding => { + TopLevelOrPatternNotAllowed::LetBinding { span, sub } + } + PatternLocation::FunctionParameter => { + TopLevelOrPatternNotAllowed::FunctionParameter { span, sub } + } + }); + if trailing_vert { + err.delay_as_bug(); } + err.emit(); } Ok((pat, colon)) diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a29b696aea8..3bb50b05aa3 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -608,7 +608,7 @@ impl<'a> Parser<'a> { /// Is a `dyn B0 + ... + Bn` type allowed here? fn is_explicit_dyn_type(&mut self) -> bool { self.check_keyword(kw::Dyn) - && (self.token.uninterpolated_span().rust_2018() + && (self.token.uninterpolated_span().at_least_rust_2018() || self.look_ahead(1, |t| { (t.can_begin_bound() || t.kind == TokenKind::BinOp(token::Star)) && !can_continue_type_after_non_fn_ident(t) |
