diff options
Diffstat (limited to 'compiler/rustc_parse')
| -rw-r--r-- | compiler/rustc_parse/Cargo.toml | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/messages.ftl | 1 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/errors.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/diagnostics.rs | 20 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/lexer/tokentrees.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/cfg_select.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 28 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 59 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 2 |
9 files changed, 122 insertions, 23 deletions
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml index c4a0ae2ce9d..a92012f8329 100644 --- a/compiler/rustc_parse/Cargo.toml +++ b/compiler/rustc_parse/Cargo.toml @@ -6,7 +6,7 @@ edition = "2024" [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" -rustc-literal-escaper = "0.0.4" +rustc-literal-escaper = "0.0.5" rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index af9f8735549..859118a4ade 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -855,6 +855,7 @@ parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern .suggestion = remove the `{$token}` parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto` +parse_trait_alias_cannot_be_const = trait aliases cannot be `const` parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe` parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 7f1b0991f0c..4aaaba01fae 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1962,6 +1962,14 @@ pub(crate) struct TraitAliasCannotBeAuto { } #[derive(Diagnostic)] +#[diag(parse_trait_alias_cannot_be_const)] +pub(crate) struct TraitAliasCannotBeConst { + #[primary_span] + #[label(parse_trait_alias_cannot_be_const)] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_trait_alias_cannot_be_unsafe)] pub(crate) struct TraitAliasCannotBeUnsafe { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs index 0b97d4e6993..6de001fc998 100644 --- a/compiler/rustc_parse/src/lexer/diagnostics.rs +++ b/compiler/rustc_parse/src/lexer/diagnostics.rs @@ -34,9 +34,12 @@ pub(super) fn same_indentation_level(sm: &SourceMap, open_sp: Span, close_sp: Sp // When we get a `)` or `]` for `{`, we should emit help message here // it's more friendly compared to report `unmatched error` in later phase -fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDelim]) -> bool { +pub(super) fn report_missing_open_delim( + err: &mut Diag<'_>, + unmatched_delims: &mut Vec<UnmatchedDelim>, +) -> bool { let mut reported_missing_open = false; - for unmatch_brace in unmatched_delims.iter() { + unmatched_delims.retain(|unmatch_brace| { if let Some(delim) = unmatch_brace.found_delim && matches!(delim, Delimiter::Parenthesis | Delimiter::Bracket) { @@ -45,13 +48,20 @@ fn report_missing_open_delim(err: &mut Diag<'_>, unmatched_delims: &[UnmatchedDe Delimiter::Bracket => "[", _ => unreachable!(), }; + + if let Some(unclosed_span) = unmatch_brace.unclosed_span { + err.span_label(unclosed_span, "the nearest open delimiter"); + } err.span_label( unmatch_brace.found_span.shrink_to_lo(), format!("missing open `{missed_open}` for this delimiter"), ); reported_missing_open = true; + false + } else { + true } - } + }); reported_missing_open } @@ -61,10 +71,6 @@ pub(super) fn report_suspicious_mismatch_block( sm: &SourceMap, delim: Delimiter, ) { - if report_missing_open_delim(err, &diag_info.unmatched_delims) { - return; - } - let mut matched_spans: Vec<(Span, bool)> = diag_info .matching_block_spans .iter() diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index fbea958dcc5..64748199f28 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -3,7 +3,9 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast_pretty::pprust::token_to_string; use rustc_errors::Diag; -use super::diagnostics::{report_suspicious_mismatch_block, same_indentation_level}; +use super::diagnostics::{ + report_missing_open_delim, report_suspicious_mismatch_block, same_indentation_level, +}; use super::{Lexer, UnmatchedDelim}; impl<'psess, 'src> Lexer<'psess, 'src> { @@ -244,7 +246,16 @@ impl<'psess, 'src> Lexer<'psess, 'src> { let msg = format!("unexpected closing delimiter: `{token_str}`"); let mut err = self.dcx().struct_span_err(self.token.span, msg); - report_suspicious_mismatch_block(&mut err, &self.diag_info, self.psess.source_map(), delim); + // if there is no missing open delim, report suspicious mismatch block + if !report_missing_open_delim(&mut err, &mut self.diag_info.unmatched_delims) { + report_suspicious_mismatch_block( + &mut err, + &self.diag_info, + self.psess.source_map(), + delim, + ); + } + err.span_label(self.token.span, "unexpected closing delimiter"); err } diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 24a05afff4a..2c6fb224d70 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -7,7 +7,7 @@ use rustc_span::Span; use crate::exp; use crate::parser::Parser; -pub enum CfgSelectRule { +pub enum CfgSelectPredicate { Cfg(MetaItemInner), Wildcard(Token), } @@ -20,7 +20,7 @@ pub struct CfgSelectBranches { pub wildcard: Option<(Token, TokenStream, Span)>, /// All branches after the first wildcard, including further wildcards. /// These branches are kept for formatting. - pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>, + pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } /// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where @@ -52,7 +52,7 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.wildcard = Some((underscore, tts, span)), Some(_) => { - branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span)) + branches.unreachable.push((CfgSelectPredicate::Wildcard(underscore), tts, span)) } } } else { @@ -64,7 +64,9 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches match branches.wildcard { None => branches.reachable.push((meta_item, tts, span)), - Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span)) + } } } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index d6cc98d505c..b767b0fcf99 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -244,6 +244,9 @@ impl<'a> Parser<'a> { self.bump(); // `static` let mutability = self.parse_mutability(); self.parse_static_item(safety, mutability)? + } else if self.check_keyword(exp!(Trait)) || self.check_trait_front_matter() { + // TRAIT ITEM + self.parse_item_trait(attrs, lo)? } else if let Const::Yes(const_span) = self.parse_constness(Case::Sensitive) { // CONST ITEM if self.token.is_keyword(kw::Impl) { @@ -262,9 +265,6 @@ impl<'a> Parser<'a> { define_opaque: None, })) } - } else if self.check_keyword(exp!(Trait)) || self.check_auto_or_unsafe_trait_item() { - // TRAIT ITEM - self.parse_item_trait(attrs, lo)? } else if self.check_keyword(exp!(Impl)) || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Impl]) { @@ -373,7 +373,7 @@ impl<'a> Parser<'a> { pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` || self.is_reuse_path_item() - || self.check_auto_or_unsafe_trait_item() // no: `auto::b`, yes: `auto trait X { .. }` + || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } @@ -872,16 +872,19 @@ impl<'a> Parser<'a> { } } - /// Is this an `(unsafe auto? | auto) trait` item? - fn check_auto_or_unsafe_trait_item(&mut self) -> bool { + /// Is this an `(const unsafe? auto?| unsafe auto? | auto) trait` item? + fn check_trait_front_matter(&mut self) -> bool { // auto trait self.check_keyword(exp!(Auto)) && self.is_keyword_ahead(1, &[kw::Trait]) // unsafe auto trait || self.check_keyword(exp!(Unsafe)) && self.is_keyword_ahead(1, &[kw::Trait, kw::Auto]) + || self.check_keyword(exp!(Const)) && ((self.is_keyword_ahead(1, &[kw::Trait]) || self.is_keyword_ahead(1, &[kw::Auto]) && self.is_keyword_ahead(2, &[kw::Trait])) + || self.is_keyword_ahead(1, &[kw::Unsafe]) && self.is_keyword_ahead(2, &[kw::Trait, kw::Auto])) } /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`. fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemKind> { + let constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); // Parse optional `auto` prefix. let is_auto = if self.eat_keyword(exp!(Auto)) { @@ -913,6 +916,9 @@ impl<'a> Parser<'a> { self.expect_semi()?; let whole_span = lo.to(self.prev_token.span); + if let Const::Yes(_) = constness { + self.dcx().emit_err(errors::TraitAliasCannotBeConst { span: whole_span }); + } if is_auto == IsAuto::Yes { self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span }); } @@ -927,7 +933,15 @@ impl<'a> Parser<'a> { // It's a normal trait. generics.where_clause = self.parse_where_clause()?; let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?; - Ok(ItemKind::Trait(Box::new(Trait { is_auto, safety, ident, generics, bounds, items }))) + Ok(ItemKind::Trait(Box::new(Trait { + constness, + is_auto, + safety, + ident, + generics, + bounds, + items, + }))) } } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index a997be3405d..740dd10ea8b 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -575,14 +575,69 @@ impl<'a> Parser<'a> { self.expect(exp!(CloseBracket))?; } TyKind::Array(elt_ty, length) - } else { - self.expect(exp!(CloseBracket))?; + } else if self.eat(exp!(CloseBracket)) { TyKind::Slice(elt_ty) + } else { + self.maybe_recover_array_ty_without_semi(elt_ty)? }; Ok(ty) } + /// Recover from malformed array type syntax. + /// + /// This method attempts to recover from cases like: + /// - `[u8, 5]` → suggests using `;`, return a Array type + /// - `[u8 5]` → suggests using `;`, return a Array type + /// Consider to add more cases in the future. + fn maybe_recover_array_ty_without_semi(&mut self, elt_ty: P<Ty>) -> PResult<'a, TyKind> { + let span = self.token.span; + let token_descr = super::token_descr(&self.token); + let mut err = + self.dcx().struct_span_err(span, format!("expected `;` or `]`, found {}", token_descr)); + err.span_label(span, "expected `;` or `]`"); + err.note("you might have meant to write a slice or array type"); + + // If we cannot recover, return the error immediately. + if !self.may_recover() { + return Err(err); + } + + let snapshot = self.create_snapshot_for_diagnostic(); + + let suggestion_span = if self.eat(exp!(Comma)) || self.eat(exp!(Star)) { + // Consume common erroneous separators. + self.prev_token.span + } else { + self.token.span.shrink_to_lo() + }; + + // we first try to parse pattern like `[u8 5]` + let length = match self.parse_expr_anon_const() { + Ok(length) => length, + Err(e) => { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + }; + + if let Err(e) = self.expect(exp!(CloseBracket)) { + e.cancel(); + self.restore_snapshot(snapshot); + return Err(err); + } + + err.span_suggestion_verbose( + suggestion_span, + "you might have meant to use `;` as the separator", + ";", + Applicability::MaybeIncorrect, + ); + err.emit(); + Ok(TyKind::Array(elt_ty, length)) + } + fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index e000d61083d..a476f0db37e 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -297,6 +297,7 @@ pub fn check_builtin_meta_item( | sym::align | sym::deprecated | sym::optimize + | sym::pointee | sym::cold | sym::target_feature | sym::rustc_allow_const_fn_unstable @@ -317,6 +318,7 @@ pub fn check_builtin_meta_item( | sym::rustc_layout_scalar_valid_range_end | sym::no_implicit_prelude | sym::automatically_derived + | sym::coverage ) { return; } |
