Reserve prefix lifetimes too

This commit is contained in:
Michael Goulet 2024-08-26 11:11:13 -04:00
parent 59d4114b2d
commit 9aaf873396
4 changed files with 51 additions and 9 deletions

View File

@ -91,6 +91,12 @@ pub enum TokenKind {
/// tokens. /// tokens.
UnknownPrefix, UnknownPrefix,
/// An unknown prefix in a lifetime, like `'foo#`.
///
/// Note that like above, only the `'` and prefix are included in the token
/// and not the separator.
UnknownPrefixLifetime,
/// Similar to the above, but *always* an error on every edition. This is used /// Similar to the above, but *always* an error on every edition. This is used
/// for emoji identifier recovery, as those are not meant to be ever accepted. /// for emoji identifier recovery, as those are not meant to be ever accepted.
InvalidPrefix, InvalidPrefix,
@ -688,15 +694,17 @@ fn lifetime_or_char(&mut self) -> TokenKind {
self.bump(); self.bump();
self.eat_while(is_id_continue); self.eat_while(is_id_continue);
// Check if after skipping literal contents we've met a closing match self.first() {
// single quote (which means that user attempted to create a // Check if after skipping literal contents we've met a closing
// string with single quotes). // single quote (which means that user attempted to create a
if self.first() == '\'' { // string with single quotes).
self.bump(); '\'' => {
let kind = Char { terminated: true }; self.bump();
Literal { kind, suffix_start: self.pos_within_token() } let kind = Char { terminated: true };
} else { Literal { kind, suffix_start: self.pos_within_token() }
Lifetime { starts_with_number } }
'#' if !starts_with_number => UnknownPrefixLifetime,
_ => Lifetime { starts_with_number },
} }
} }

View File

@ -205,6 +205,16 @@ fn next_token(&mut self) -> (Token, bool) {
self.report_unknown_prefix(start); self.report_unknown_prefix(start);
self.ident(start) self.ident(start)
} }
rustc_lexer::TokenKind::UnknownPrefixLifetime => {
self.report_unknown_prefix(start);
// Include the leading `'` in the real identifier, for macro
// expansion purposes. See #12512 for the gory details of why
// this is necessary.
let lifetime_name = self.str_from(start);
self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
let ident = Symbol::intern(lifetime_name);
token::Lifetime(ident, IdentIsRaw::No)
}
rustc_lexer::TokenKind::InvalidIdent rustc_lexer::TokenKind::InvalidIdent
| rustc_lexer::TokenKind::InvalidPrefix | rustc_lexer::TokenKind::InvalidPrefix
// Do not recover an identifier with emoji if the codepoint is a confusable // Do not recover an identifier with emoji if the codepoint is a confusable

View File

@ -0,0 +1,10 @@
//@ edition: 2021
macro_rules! w {
($($tt:tt)*) => {};
}
w!('foo#lifetime);
//~^ ERROR prefix `'foo` is unknown
fn main() {}

View File

@ -0,0 +1,14 @@
error: prefix `'foo` is unknown
--> $DIR/prefixed-lifetime.rs:7:4
|
LL | w!('foo#lifetime);
| ^^^^ unknown prefix
|
= note: prefixed identifiers and literals are reserved since Rust 2021
help: consider inserting whitespace here
|
LL | w!('foo #lifetime);
| +
error: aborting due to 1 previous error