diff options
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/lexer/mod.rs | 94 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/diagnostics.rs | 74 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/generics.rs | 14 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 54 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/pat.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/path.rs | 8 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 2 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/tests.rs | 6 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 50 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/validate_attr.rs | 30 |
12 files changed, 187 insertions, 161 deletions
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 2845bbed1c0..60d275bf2b4 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,5 +1,3 @@ -use std::ops::Range; - use diagnostics::make_unclosed_delims_error; use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind}; @@ -10,7 +8,7 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey}; use rustc_lexer::{ Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_whitespace, }; -use rustc_literal_escaper::{EscapeError, Mode, unescape_mixed, unescape_unicode}; +use rustc_literal_escaper::{EscapeError, Mode, check_for_errors}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX, @@ -702,7 +700,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { } err.emit() } - self.cook_unicode(token::Char, Mode::Char, start, end, 1, 1) // ' ' + self.cook_quoted(token::Char, Mode::Char, start, end, 1, 1) // ' ' } rustc_lexer::LiteralKind::Byte { terminated } => { if !terminated { @@ -714,7 +712,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0763) .emit() } - self.cook_unicode(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' + self.cook_quoted(token::Byte, Mode::Byte, start, end, 2, 1) // b' ' } rustc_lexer::LiteralKind::Str { terminated } => { if !terminated { @@ -726,7 +724,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0765) .emit() } - self.cook_unicode(token::Str, Mode::Str, start, end, 1, 1) // " " + self.cook_quoted(token::Str, Mode::Str, start, end, 1, 1) // " " } rustc_lexer::LiteralKind::ByteStr { terminated } => { if !terminated { @@ -738,7 +736,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0766) .emit() } - self.cook_unicode(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" " + self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) + // b" " } rustc_lexer::LiteralKind::CStr { terminated } => { if !terminated { @@ -750,13 +749,14 @@ impl<'psess, 'src> Lexer<'psess, 'src> { .with_code(E0767) .emit() } - self.cook_mixed(token::CStr, Mode::CStr, start, end, 2, 1) // c" " + self.cook_quoted(token::CStr, Mode::CStr, start, end, 2, 1) // c" " } rustc_lexer::LiteralKind::RawStr { n_hashes } => { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::StrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawStr, start, end, 2 + n, 1 + n) // r##" "## + self.cook_quoted(kind, Mode::RawStr, start, end, 2 + n, 1 + n) + // r##" "## } else { self.report_raw_str_error(start, 1); } @@ -765,7 +765,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::ByteStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) // br##" "## + self.cook_quoted(kind, Mode::RawByteStr, start, end, 3 + n, 1 + n) + // br##" "## } else { self.report_raw_str_error(start, 2); } @@ -774,7 +775,8 @@ impl<'psess, 'src> Lexer<'psess, 'src> { if let Some(n_hashes) = n_hashes { let n = u32::from(n_hashes); let kind = token::CStrRaw(n_hashes); - self.cook_unicode(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "## + self.cook_quoted(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) + // cr##" "## } else { self.report_raw_str_error(start, 2); } @@ -1091,7 +1093,7 @@ impl<'psess, 'src> Lexer<'psess, 'src> { self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num }); } - fn cook_common( + fn cook_quoted( &self, mut kind: token::LitKind, mode: Mode, @@ -1099,32 +1101,28 @@ impl<'psess, 'src> Lexer<'psess, 'src> { end: BytePos, prefix_len: u32, postfix_len: u32, - unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)), ) -> (token::LitKind, Symbol) { let content_start = start + BytePos(prefix_len); let content_end = end - BytePos(postfix_len); let lit_content = self.str_from_to(content_start, content_end); - unescape(lit_content, mode, &mut |range, result| { - // Here we only check for errors. The actual unescaping is done later. - if let Err(err) = result { - let span_with_quotes = self.mk_sp(start, end); - let (start, end) = (range.start as u32, range.end as u32); - let lo = content_start + BytePos(start); - let hi = lo + BytePos(end - start); - let span = self.mk_sp(lo, hi); - let is_fatal = err.is_fatal(); - if let Some(guar) = emit_unescape_error( - self.dcx(), - lit_content, - span_with_quotes, - span, - mode, - range, - err, - ) { - assert!(is_fatal); - kind = token::Err(guar); - } + check_for_errors(lit_content, mode, |range, err| { + let span_with_quotes = self.mk_sp(start, end); + let (start, end) = (range.start as u32, range.end as u32); + let lo = content_start + BytePos(start); + let hi = lo + BytePos(end - start); + let span = self.mk_sp(lo, hi); + let is_fatal = err.is_fatal(); + if let Some(guar) = emit_unescape_error( + self.dcx(), + lit_content, + span_with_quotes, + span, + mode, + range, + err, + ) { + assert!(is_fatal); + kind = token::Err(guar); } }); @@ -1137,34 +1135,6 @@ impl<'psess, 'src> Lexer<'psess, 'src> { }; (kind, sym) } - - fn cook_unicode( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_unicode(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } - - fn cook_mixed( - &self, - kind: token::LitKind, - mode: Mode, - start: BytePos, - end: BytePos, - prefix_len: u32, - postfix_len: u32, - ) -> (token::LitKind, Symbol) { - self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| { - unescape_mixed(src, mode, &mut |span, result| callback(span, result.map(drop))) - }) - } } pub fn nfc_normalize(string: &str) -> Symbol { diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b49a13ce584..1df0ccbd8af 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -686,23 +686,34 @@ impl<'a> Parser<'a> { } if let token::DocComment(kind, style, _) = self.token.kind { - // We have something like `expr //!val` where the user likely meant `expr // !val` - let pos = self.token.span.lo() + BytePos(2); - let span = self.token.span.with_lo(pos).with_hi(pos); - err.span_suggestion_verbose( - span, - format!( - "add a space before {} to write a regular comment", - match (kind, style) { - (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", - (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", - (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", - }, - ), - " ".to_string(), - Applicability::MachineApplicable, - ); + // This is to avoid suggesting converting a doc comment to a regular comment + // when missing a comma before the doc comment in lists (#142311): + // + // ``` + // enum Foo{ + // A /// xxxxxxx + // B, + // } + // ``` + if !expected.contains(&TokenType::Comma) { + // We have something like `expr //!val` where the user likely meant `expr // !val` + let pos = self.token.span.lo() + BytePos(2); + let span = self.token.span.with_lo(pos).with_hi(pos); + err.span_suggestion_verbose( + span, + format!( + "add a space before {} to write a regular comment", + match (kind, style) { + (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`", + (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`", + (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`", + }, + ), + " ".to_string(), + Applicability::MaybeIncorrect, + ); + } } let sp = if self.token == token::Eof { @@ -2273,23 +2284,18 @@ impl<'a> Parser<'a> { ), // Also catches `fn foo(&a)`. PatKind::Ref(ref inner_pat, mutab) - if matches!(inner_pat.clone().kind, PatKind::Ident(..)) => + if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind => { - match inner_pat.clone().kind { - PatKind::Ident(_, ident, _) => { - let mutab = mutab.prefix_str(); - ( - ident, - "self: ", - format!("{ident}: &{mutab}TypeName"), - "_: ", - pat.span.shrink_to_lo(), - pat.span, - pat.span.shrink_to_lo(), - ) - } - _ => unreachable!(), - } + let mutab = mutab.prefix_str(); + ( + ident, + "self: ", + format!("{ident}: &{mutab}TypeName"), + "_: ", + pat.span.shrink_to_lo(), + pat.span, + pat.span.shrink_to_lo(), + ) } _ => { // Otherwise, try to get a type and emit a suggestion. @@ -2725,7 +2731,7 @@ impl<'a> Parser<'a> { return first_pat; } if !matches!(first_pat.kind, PatKind::Ident(_, _, None) | PatKind::Path(..)) - || !self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + || !self.look_ahead(1, |token| token.is_non_reserved_ident()) { let mut snapshot_type = self.create_snapshot_for_diagnostic(); snapshot_type.bump(); // `:` diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 93489aa8ee9..3cedc86dc0d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -847,7 +847,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span }); } - /// Parse `mut?` or `raw [ const | mut ]`. + /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`. fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) { if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) { // `raw [ const | mut ]`. @@ -855,6 +855,11 @@ impl<'a> Parser<'a> { assert!(found_raw); let mutability = self.parse_const_or_mut().unwrap(); (ast::BorrowKind::Raw, mutability) + } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() { + // `pin [ const | mut ]`. + // `pin` has been gated in `self.parse_pin_and_mut()` so we don't + // need to gate it here. + (ast::BorrowKind::Pin, mutbl) } else { // `mut?` (ast::BorrowKind::Ref, self.parse_mutability()) @@ -3870,8 +3875,7 @@ impl<'a> Parser<'a> { // Check if a colon exists one ahead. This means we're parsing a fieldname. let is_shorthand = !this.look_ahead(1, |t| t == &token::Colon || t == &token::Eq); // Proactively check whether parsing the field will be incorrect. - let is_wrong = this.token.is_ident() - && !this.token.is_reserved_ident() + let is_wrong = this.token.is_non_reserved_ident() && !this.look_ahead(1, |t| { t == &token::Colon || t == &token::Eq @@ -4087,7 +4091,7 @@ impl<'a> CondChecker<'a> { } impl MutVisitor for CondChecker<'_> { - fn visit_expr(&mut self, e: &mut P<Expr>) { + fn visit_expr(&mut self, e: &mut Expr) { self.depth += 1; use ForbiddenLetReason::*; diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index c05479feb61..af1d1a1ec66 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -353,6 +353,20 @@ impl<'a> Parser<'a> { if !self.eat_keyword(exp!(Where)) { return Ok((where_clause, None)); } + + if self.eat_noexpect(&token::Colon) { + let colon_span = self.prev_token.span; + self.dcx() + .struct_span_err(colon_span, "unexpected colon after `where`") + .with_span_suggestion_short( + colon_span, + "remove the colon", + "", + Applicability::MachineApplicable, + ) + .emit(); + } + where_clause.has_where_token = true; let where_lo = self.prev_token.span; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 658ed4bd41c..9ed7124a11c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1552,7 +1552,8 @@ impl<'a> Parser<'a> { }) .map_err(|mut err| { err.span_label(ident.span, "while parsing this enum"); - if self.token == token::Colon { + // Try to recover `enum Foo { ident : Ty }`. + if self.prev_token.is_non_reserved_ident() && self.token == token::Colon { let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); match self.parse_ty() { @@ -1781,7 +1782,7 @@ impl<'a> Parser<'a> { let mut recovered = Recovered::No; if self.eat(exp!(OpenBrace)) { while self.token != token::CloseBrace { - match self.parse_field_def(adt_ty) { + match self.parse_field_def(adt_ty, ident_span) { Ok(field) => { fields.push(field); } @@ -1894,7 +1895,7 @@ impl<'a> Parser<'a> { } /// Parses an element of a struct declaration. - fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> { + fn parse_field_def(&mut self, adt_ty: &str, ident_span: Span) -> PResult<'a, FieldDef> { self.recover_vcs_conflict_marker(); let attrs = self.parse_outer_attributes()?; self.recover_vcs_conflict_marker(); @@ -1902,7 +1903,7 @@ impl<'a> Parser<'a> { let lo = this.token.span; let vis = this.parse_visibility(FollowedByType::No)?; let safety = this.parse_unsafe_field(); - this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs) + this.parse_single_struct_field(adt_ty, lo, vis, safety, attrs, ident_span) .map(|field| (field, Trailing::No, UsePreAttrPos::No)) }) } @@ -1915,28 +1916,27 @@ impl<'a> Parser<'a> { vis: Visibility, safety: Safety, attrs: AttrVec, + ident_span: Span, ) -> PResult<'a, FieldDef> { - let mut seen_comma: bool = false; let a_var = self.parse_name_and_ty(adt_ty, lo, vis, safety, attrs)?; - if self.token == token::Comma { - seen_comma = true; - } - if self.eat(exp!(Semi)) { - let sp = self.prev_token.span; - let mut err = - self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); - err.span_suggestion_short( - sp, - "replace `;` with `,`", - ",", - Applicability::MachineApplicable, - ); - return Err(err); - } match self.token.kind { token::Comma => { self.bump(); } + token::Semi => { + self.bump(); + let sp = self.prev_token.span; + let mut err = + self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`")); + err.span_suggestion_short( + sp, + "replace `;` with `,`", + ",", + Applicability::MachineApplicable, + ); + err.span_label(ident_span, format!("while parsing this {adt_ty}")); + err.emit(); + } token::CloseBrace => {} token::DocComment(..) => { let previous_span = self.prev_token.span; @@ -1945,19 +1945,11 @@ impl<'a> Parser<'a> { missing_comma: None, }; self.bump(); // consume the doc comment - let comma_after_doc_seen = self.eat(exp!(Comma)); - // `seen_comma` is always false, because we are inside doc block - // condition is here to make code more readable - if !seen_comma && comma_after_doc_seen { - seen_comma = true; - } - if comma_after_doc_seen || self.token == token::CloseBrace { + if self.eat(exp!(Comma)) || self.token == token::CloseBrace { self.dcx().emit_err(err); } else { - if !seen_comma { - let sp = previous_span.shrink_to_hi(); - err.missing_comma = Some(sp); - } + let sp = previous_span.shrink_to_hi(); + err.missing_comma = Some(sp); return Err(self.dcx().create_err(err)); } } diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index b2e90251367..cfc0399b0ca 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -685,7 +685,7 @@ impl<'a> Parser<'a> { /// Is the given keyword `kw` followed by a non-reserved identifier? fn is_kw_followed_by_ident(&self, kw: Symbol) -> bool { - self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()) + self.token.is_keyword(kw) && self.look_ahead(1, |t| t.is_non_reserved_ident()) } #[inline] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 7a226136e23..64653ee2a04 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> { fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool { struct AddMut(bool); impl MutVisitor for AddMut { - fn visit_pat(&mut self, pat: &mut P<Pat>) { + fn visit_pat(&mut self, pat: &mut Pat) { if let PatKind::Ident(BindingMode(ByRef::No, m @ Mutability::Not), ..) = &mut pat.kind { diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs index 9bce2fa74ca..1f4049f197f 100644 --- a/compiler/rustc_parse/src/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -126,7 +126,7 @@ impl<'a> Parser<'a> { /// ``` fn recover_colon_before_qpath_proj(&mut self) -> bool { if !self.check_noexpect(&TokenKind::Colon) - || self.look_ahead(1, |t| !t.is_ident() || t.is_reserved_ident()) + || self.look_ahead(1, |t| !t.is_non_reserved_ident()) { return false; } @@ -260,7 +260,7 @@ impl<'a> Parser<'a> { if self.may_recover() && style == PathStyle::Expr // (!) && self.token == token::Colon - && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident()) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { // Emit a special error message for `a::b:c` to help users // otherwise, `a: c` might have meant to introduce a new binding @@ -334,9 +334,7 @@ impl<'a> Parser<'a> { self.expect_gt().map_err(|mut err| { // Try to recover a `:` into a `::` if self.token == token::Colon - && self.look_ahead(1, |token| { - token.is_ident() && !token.is_reserved_ident() - }) + && self.look_ahead(1, |token| token.is_non_reserved_ident()) { err.cancel(); err = self.dcx().create_err(PathSingleColon { diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index c37cb0881c3..2fa6520f2a4 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -798,7 +798,7 @@ impl<'a> Parser<'a> { } if self.prev_token.is_reserved_ident() && self.prev_token.is_ident_named(kw::Await) { // Likely `foo.await bar` - } else if !self.prev_token.is_reserved_ident() && self.prev_token.is_ident() { + } else if self.prev_token.is_non_reserved_ident() { // Likely `foo bar` } else if self.prev_token.kind == token::Question { // `foo? bar` diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs index 2a44c90abc1..15679d23bc5 100644 --- a/compiler/rustc_parse/src/parser/tests.rs +++ b/compiler/rustc_parse/src/parser/tests.rs @@ -14,6 +14,7 @@ use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, Toke use rustc_ast::{self as ast, PatKind, visit}; use rustc_ast_pretty::pprust::item_to_string; use rustc_errors::emitter::{HumanEmitter, OutputTheme}; +use rustc_errors::translation::Translator; use rustc_errors::{DiagCtxt, MultiSpan, PResult}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -41,9 +42,8 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> { fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc<SourceMap>, Arc<Mutex<Vec<u8>>>) { let output = Arc::new(Mutex::new(Vec::new())); let source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); - let fallback_bundle = - rustc_errors::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); - let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), fallback_bundle) + let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); + let mut emitter = HumanEmitter::new(Box::new(Shared { data: output.clone() }), translator) .sm(Some(source_map.clone())) .diagnostic_width(Some(140)); emitter = emitter.theme(theme); diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 620a34044d1..d874a071cee 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -885,6 +885,7 @@ impl<'a> Parser<'a> { || self.check(exp!(Tilde)) || self.check_keyword(exp!(For)) || self.check(exp!(OpenParen)) + || self.check(exp!(OpenBracket)) || self.check_keyword(exp!(Const)) || self.check_keyword(exp!(Async)) || self.check_keyword(exp!(Use)) @@ -982,12 +983,12 @@ impl<'a> Parser<'a> { Ok(()) } - /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `~const Trait`. + /// Parses the modifiers that may precede a trait in a bound, e.g. `?Trait` or `[const] Trait`. /// /// If no modifiers are present, this does not consume any tokens. /// /// ```ebnf - /// CONSTNESS = [["~"] "const"] + /// CONSTNESS = [["["] "const" ["]"]] /// ASYNCNESS = ["async"] /// POLARITY = ["?" | "!"] /// ``` @@ -995,18 +996,7 @@ impl<'a> Parser<'a> { /// See `parse_generic_ty_bound` for the complete grammar of trait bound modifiers. fn parse_trait_bound_modifiers(&mut self) -> PResult<'a, TraitBoundModifiers> { let modifier_lo = self.token.span; - let constness = if self.eat(exp!(Tilde)) { - let tilde = self.prev_token.span; - self.expect_keyword(exp!(Const))?; - let span = tilde.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::const_trait_impl, span); - BoundConstness::Maybe(span) - } else if self.eat_keyword(exp!(Const)) { - self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); - BoundConstness::Always(self.prev_token.span) - } else { - BoundConstness::Never - }; + let constness = self.parse_bound_constness()?; let asyncness = if self.token_uninterpolated_span().at_least_rust_2018() && self.eat_keyword(exp!(Async)) @@ -1068,13 +1058,41 @@ impl<'a> Parser<'a> { Ok(TraitBoundModifiers { constness, asyncness, polarity }) } + pub fn parse_bound_constness(&mut self) -> PResult<'a, BoundConstness> { + // FIXME(const_trait_impl): remove `~const` parser support once bootstrap has the new syntax + // in rustfmt + Ok(if self.eat(exp!(Tilde)) { + let tilde = self.prev_token.span; + self.expect_keyword(exp!(Const))?; + let span = tilde.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::const_trait_impl, span); + BoundConstness::Maybe(span) + } else if self.check(exp!(OpenBracket)) + && self.look_ahead(1, |t| t.is_keyword(kw::Const)) + && self.look_ahead(2, |t| *t == token::CloseBracket) + { + let start = self.token.span; + self.bump(); + self.expect_keyword(exp!(Const)).unwrap(); + self.bump(); + let span = start.to(self.prev_token.span); + self.psess.gated_spans.gate(sym::const_trait_impl, span); + BoundConstness::Maybe(span) + } else if self.eat_keyword(exp!(Const)) { + self.psess.gated_spans.gate(sym::const_trait_impl, self.prev_token.span); + BoundConstness::Always(self.prev_token.span) + } else { + BoundConstness::Never + }) + } + /// Parses a type bound according to: /// ```ebnf /// TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN) /// TY_BOUND_NOPAREN = [for<GENERIC_PARAMS> CONSTNESS ASYNCNESS | POLARITY] SIMPLE_PATH /// ``` /// - /// For example, this grammar accepts `for<'a: 'b> ~const ?m::Trait<'a>`. + /// For example, this grammar accepts `for<'a: 'b> [const] ?m::Trait<'a>`. fn parse_generic_ty_bound( &mut self, lo: Span, @@ -1101,7 +1119,7 @@ impl<'a> Parser<'a> { } // Recover erroneous lifetime bound with modifiers or binder. - // e.g. `T: for<'a> 'a` or `T: ~const 'a`. + // e.g. `T: for<'a> 'a` or `T: [const] 'a`. if self.token.is_lifetime() { let _: ErrorGuaranteed = self.error_lt_bound_with_modifiers(modifiers, binder_span); return self.parse_generic_lt_bound(lo, has_parens); diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 555ab3cdb2b..8b1d864c995 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -282,11 +282,35 @@ fn emit_malformed_attribute( name: Symbol, template: AttributeTemplate, ) { + // attrs with new parsers are locally validated so excluded here + if matches!( + name, + sym::inline + | sym::may_dangle + | sym::rustc_as_ptr + | sym::rustc_pub_transparent + | sym::rustc_const_stable_indirect + | sym::rustc_force_inline + | sym::rustc_confusables + | sym::rustc_skip_during_method_dispatch + | sym::repr + | sym::align + | sym::deprecated + | sym::optimize + | sym::cold + | sym::naked + | sym::no_mangle + | sym::must_use + | sym::track_caller + | sym::link_name + ) { + return; + } + // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = |name| { - matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) - }; + let should_warn = + |name| matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench); let error_msg = format!("malformed `{name}` attribute input"); let mut suggestions = vec![]; |
