Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions compiler/rustc_lexer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ pub enum TokenKind {
/// A lifetime, e.g. `'a`.
Lifetime {
starts_with_number: bool,
has_emoji: bool,
},

/// `;`
Expand Down Expand Up @@ -975,14 +976,20 @@ impl<'a> Cursor<'a> {
fn lifetime_or_char(&mut self) -> TokenKind {
debug_assert!(self.prev() == '\'');

let mut has_emoji = false;
let can_be_a_lifetime = if self.second() == '\'' {
// It's surely not a lifetime.
false
} else {
// If the first symbol is valid for identifier, it can be a lifetime.
// Also check if it's a number for a better error reporting (so '0 will
// be reported as invalid lifetime and not as unterminated char literal).
is_id_start(self.first()) || self.first().is_ascii_digit()
let c = self.first();
let is_emoji = !c.is_ascii() && c.is_emoji_char();
if is_emoji {
has_emoji = true;
}
is_id_start(c) || c.is_ascii_digit() || is_emoji
};

if !can_be_a_lifetime {
Expand Down Expand Up @@ -1012,7 +1019,13 @@ impl<'a> Cursor<'a> {
// First symbol can be a number (which isn't a valid identifier start),
// so skip it without any checks.
self.bump();
self.eat_while(is_id_continue);
self.eat_while(|c| {
let is_emoji = !c.is_ascii() && c.is_emoji_char();
if is_emoji {
has_emoji = true;
}
is_id_continue(c) || is_emoji
});

match self.first() {
// Check if after skipping literal contents we've met a closing
Expand All @@ -1024,7 +1037,7 @@ impl<'a> Cursor<'a> {
Literal { kind, suffix_start: self.pos_within_token() }
}
'#' if !starts_with_number => UnknownPrefixLifetime,
_ => Lifetime { starts_with_number },
_ => Lifetime { starts_with_number, has_emoji },
}
}

Expand Down
7 changes: 5 additions & 2 deletions compiler/rustc_parse/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -316,19 +316,22 @@ impl<'psess, 'src> Lexer<'psess, 'src> {
self.lint_literal_unicode_text_flow(symbol, kind, self.mk_sp(start, self.pos), "literal");
token::Literal(token::Lit { kind, symbol, suffix })
}
rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
rustc_lexer::TokenKind::Lifetime { starts_with_number, has_emoji } => {
// 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 = nfc_normalize(self.str_from(start));
self.last_lifetime = Some(self.mk_sp(start, start + BytePos(1)));
let span = self.mk_sp(start, self.pos);
if starts_with_number {
let span = self.mk_sp(start, self.pos);
self.dcx()
.struct_err("lifetimes cannot start with a number")
.with_span(span)
.stash(span, StashKey::LifetimeIsChar);
}
if has_emoji {
self.dcx().struct_span_err(span, "lifetimes cannot contain emoji").emit();
}
token::Lifetime(lifetime_name, IdentIsRaw::No)
}
rustc_lexer::TokenKind::RawLifetime => {
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/lexer/emoji-in-lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// #141081
fn bad_lifetime_name<'🐛🐛🐛family👨‍👩‍👧‍👦>(_: &'🐛🐛🐛family👨‍👩‍👧‍👦 ()) {}
//~^ ERROR: lifetimes cannot contain emoji
//~| ERROR: lifetimes cannot contain emoji
fn main() {
'🐛: { //~ ERROR: lifetimes cannot contain emoji
todo!();
};
}
20 changes: 20 additions & 0 deletions tests/ui/lexer/emoji-in-lifetime.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: lifetimes cannot contain emoji
--> $DIR/emoji-in-lifetime.rs:2:22
|
LL | fn bad_lifetime_name<'🐛🐛🐛family👨👩👧👦>(_: &'🐛🐛🐛family👨👩👧👦 ()) {}
| ^^^^^^^^^^^^^^^^^^^^^

error: lifetimes cannot contain emoji
--> $DIR/emoji-in-lifetime.rs:2:45
|
LL | fn bad_lifetime_name<'🐛🐛🐛family👨👩👧👦>(_: &'🐛🐛🐛family👨👩👧👦 ()) {}
| ^^^^^^^^^^^^^^^^^^^^^

error: lifetimes cannot contain emoji
--> $DIR/emoji-in-lifetime.rs:6:5
|
LL | '🐛: {
| ^^^

error: aborting due to 3 previous errors

Loading