From 92debb13db02cf59694d3fe9cf6f71e131cf85c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 10 Apr 2024 21:12:45 +0000 Subject: [PATCH] Properly handle emojis as literal prefix in macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not accept the following ```rust macro_rules! lexes {($($_:tt)*) => {}} lexes!(🐛"foo"); ``` Before, invalid emoji identifiers were gated during parsing instead of lexing in all cases, but this didn't account for macro expansion of literal prefixes. Fix #123696. --- compiler/rustc_lexer/src/lib.rs | 6 +++++- compiler/rustc_parse/src/lexer/mod.rs | 5 ++++- tests/ui/lexer/emoji-literal-prefix.rs | 8 ++++++++ tests/ui/lexer/emoji-literal-prefix.stderr | 14 ++++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/ui/lexer/emoji-literal-prefix.rs create mode 100644 tests/ui/lexer/emoji-literal-prefix.stderr diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index ca84e930c2439..83fff98bad56c 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -88,6 +88,10 @@ pub enum TokenKind { /// tokens. UnknownPrefix, + /// 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. + InvalidPrefix, + /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid /// suffix, but may be present here on string and float literals. Users of /// this type will need to check for and reject that case. @@ -528,7 +532,7 @@ impl Cursor<'_> { // Known prefixes must have been handled earlier. So if // we see a prefix here, it is definitely an unknown prefix. match self.first() { - '#' | '"' | '\'' => UnknownPrefix, + '#' | '"' | '\'' => InvalidPrefix, _ => InvalidIdent, } } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 69b48bf0aff71..85c4c74e1e90f 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -205,6 +205,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> { self.ident(start) } rustc_lexer::TokenKind::InvalidIdent + | rustc_lexer::TokenKind::InvalidPrefix // Do not recover an identifier with emoji if the codepoint is a confusable // with a recoverable substitution token, like `➖`. if !UNICODE_ARRAY @@ -302,7 +303,9 @@ impl<'psess, 'src> StringReader<'psess, 'src> { rustc_lexer::TokenKind::Caret => token::BinOp(token::Caret), rustc_lexer::TokenKind::Percent => token::BinOp(token::Percent), - rustc_lexer::TokenKind::Unknown | rustc_lexer::TokenKind::InvalidIdent => { + rustc_lexer::TokenKind::Unknown + | rustc_lexer::TokenKind::InvalidIdent + | rustc_lexer::TokenKind::InvalidPrefix => { // Don't emit diagnostics for sequences of the same invalid token if swallow_next_invalid > 0 { swallow_next_invalid -= 1; diff --git a/tests/ui/lexer/emoji-literal-prefix.rs b/tests/ui/lexer/emoji-literal-prefix.rs new file mode 100644 index 0000000000000..ccc8d48d4cc3e --- /dev/null +++ b/tests/ui/lexer/emoji-literal-prefix.rs @@ -0,0 +1,8 @@ +macro_rules! lexes {($($_:tt)*) => {}} + +lexes!(🐛#); //~ ERROR identifiers cannot contain emoji +lexes!(🐛"foo"); +lexes!(🐛'q'); +lexes!(🐛'q); + +fn main() {} diff --git a/tests/ui/lexer/emoji-literal-prefix.stderr b/tests/ui/lexer/emoji-literal-prefix.stderr new file mode 100644 index 0000000000000..25aafed48ea9a --- /dev/null +++ b/tests/ui/lexer/emoji-literal-prefix.stderr @@ -0,0 +1,14 @@ +error: identifiers cannot contain emoji: `🐛` + --> $DIR/emoji-literal-prefix.rs:3:8 + | +LL | lexes!(🐛#); + | ^^ +LL | lexes!(🐛"foo"); + | ^^ +LL | lexes!(🐛'q'); + | ^^ +LL | lexes!(🐛'q); + | ^^ + +error: aborting due to 1 previous error +