|
1 |
| -use rustc_ast::ast::AttrStyle; |
| 1 | +use rustc_ast::ast::{self, AttrStyle}; |
2 | 2 | use rustc_ast::token::{self, CommentKind, Token, TokenKind};
|
3 | 3 | use rustc_ast::tokenstream::{Spacing, TokenStream};
|
4 | 4 | use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult};
|
5 | 5 | use rustc_lexer::unescape::{self, Mode};
|
6 | 6 | use rustc_lexer::{Base, DocStyle, RawStrError};
|
| 7 | +use rustc_session::lint::builtin::RESERVED_PREFIX; |
| 8 | +use rustc_session::lint::BuiltinLintDiagnostics; |
7 | 9 | use rustc_session::parse::ParseSess;
|
8 | 10 | use rustc_span::symbol::{sym, Symbol};
|
9 |
| -use rustc_span::{BytePos, Pos, Span}; |
| 11 | +use rustc_span::{edition::Edition, BytePos, Pos, Span}; |
10 | 12 |
|
11 | 13 | use tracing::debug;
|
12 | 14 |
|
@@ -166,12 +168,18 @@ impl<'a> StringReader<'a> {
|
166 | 168 | self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style)
|
167 | 169 | }
|
168 | 170 | rustc_lexer::TokenKind::Whitespace => return None,
|
169 |
| - rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent => { |
| 171 | + rustc_lexer::TokenKind::Ident |
| 172 | + | rustc_lexer::TokenKind::RawIdent |
| 173 | + | rustc_lexer::TokenKind::UnknownPrefix => { |
170 | 174 | let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent;
|
| 175 | + let is_unknown_prefix = token == rustc_lexer::TokenKind::UnknownPrefix; |
171 | 176 | let mut ident_start = start;
|
172 | 177 | if is_raw_ident {
|
173 | 178 | ident_start = ident_start + BytePos(2);
|
174 | 179 | }
|
| 180 | + if is_unknown_prefix { |
| 181 | + self.report_unknown_prefix(start); |
| 182 | + } |
175 | 183 | let sym = nfc_normalize(self.str_from(ident_start));
|
176 | 184 | let span = self.mk_sp(start, self.pos);
|
177 | 185 | self.sess.symbol_gallery.insert(sym, span);
|
@@ -491,6 +499,42 @@ impl<'a> StringReader<'a> {
|
491 | 499 | FatalError.raise()
|
492 | 500 | }
|
493 | 501 |
|
| 502 | + // RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021, |
| 503 | + // using a (unknown) prefix is an error. In earlier editions, however, they |
| 504 | + // only result in a (allowed by default) lint, and are treated as regular |
| 505 | + // identifier tokens. |
| 506 | + fn report_unknown_prefix(&self, start: BytePos) { |
| 507 | + let prefix_span = self.mk_sp(start, self.pos); |
| 508 | + let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); |
| 509 | + |
| 510 | + let expn_data = prefix_span.ctxt().outer_expn_data(); |
| 511 | + |
| 512 | + if expn_data.edition >= Edition::Edition2021 { |
| 513 | + // In Rust 2021, this is a hard error. |
| 514 | + let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg); |
| 515 | + err.span_label(prefix_span, "unknown prefix"); |
| 516 | + if expn_data.is_root() { |
| 517 | + err.span_suggestion_verbose( |
| 518 | + prefix_span.shrink_to_hi(), |
| 519 | + "consider inserting whitespace here", |
| 520 | + " ".into(), |
| 521 | + Applicability::MachineApplicable, |
| 522 | + ); |
| 523 | + } |
| 524 | + err.note("prefixed identifiers and literals are reserved since Rust 2021"); |
| 525 | + err.emit(); |
| 526 | + } else { |
| 527 | + // Before Rust 2021, only emit a lint for migration. |
| 528 | + self.sess.buffer_lint_with_diagnostic( |
| 529 | + &RESERVED_PREFIX, |
| 530 | + prefix_span, |
| 531 | + ast::CRATE_NODE_ID, |
| 532 | + &msg, |
| 533 | + BuiltinLintDiagnostics::ReservedPrefix(prefix_span), |
| 534 | + ); |
| 535 | + } |
| 536 | + } |
| 537 | + |
494 | 538 | /// Note: It was decided to not add a test case, because it would be too big.
|
495 | 539 | /// <https://github.com/rust-lang/rust/pull/50296#issuecomment-392135180>
|
496 | 540 | fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! {
|
|
0 commit comments