about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser/mod.rs
diff options
context:
space:
mode:
authorNicholas Nethercote <n.nethercote@gmail.com>2024-12-04 15:55:06 +1100
committerNicholas Nethercote <n.nethercote@gmail.com>2024-12-19 16:05:41 +1100
commitb9bf0b4b10148aa914243a527d9010aba9b7b827 (patch)
tree2478d44acd2d710543d168353b729e0716aefb70 /compiler/rustc_parse/src/parser/mod.rs
parentd5370d981f58ebadf575f075a6f0d8c35bc704e8 (diff)
downloadrust-b9bf0b4b10148aa914243a527d9010aba9b7b827.tar.gz
rust-b9bf0b4b10148aa914243a527d9010aba9b7b827.zip
Speed up `Parser::expected_token_types`.
The parser pushes a `TokenType` to `Parser::expected_token_types` on
every call to the various `check`/`eat` methods, and clears it on every
call to `bump`. Some of those `TokenType` values are full tokens that
require cloning and dropping. This is a *lot* of work for something
that is only used in error messages and it accounts for a significant
fraction of parsing execution time.

This commit overhauls `TokenType` so that `Parser::expected_token_types`
can be implemented as a bitset. This requires changing `TokenType` to a
C-style parameterless enum, and adding `TokenTypeSet` which uses a
`u128` for the bits. (The new `TokenType` has 105 variants.)

The new types `ExpTokenPair` and `ExpKeywordPair` are now arguments to
the `check`/`eat` methods. This is for maximum speed. The elements in
the pairs are always statically known; e.g. a
`token::BinOp(token::Star)` is always paired with a `TokenType::Star`.
So we now compute `TokenType`s in advance and pass them in to
`check`/`eat` rather than the current approach of constructing them on
insertion into `expected_token_types`.

Values of these pair types can be produced by the new `exp!` macro,
which is used at every `check`/`eat` call site. The macro is for
convenience, allowing any pair to be generated from a single identifier.

The ident/keyword filtering in `expected_one_of_not_found` is no longer
necessary. It was there to account for some sloppiness in
`TokenKind`/`TokenType` comparisons.

The existing `TokenType` is moved to a new file `token_type.rs`, and all
its new infrastructure is added to that file. There is more boilerplate
code than I would like, but I can't see how to make it shorter.
Diffstat (limited to 'compiler/rustc_parse/src/parser/mod.rs')
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs226
1 files changed, 99 insertions, 127 deletions
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 3e82a9cf1bb..43328c48015 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -8,6 +8,7 @@ mod nonterminal;
 mod pat;
 mod path;
 mod stmt;
+pub mod token_type;
 mod ty;
 
 use std::assert_matches::debug_assert_matches;
@@ -39,11 +40,14 @@ use rustc_index::interval::IntervalSet;
 use rustc_session::parse::ParseSess;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use thin_vec::ThinVec;
+use token_type::TokenTypeSet;
+pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType};
 use tracing::debug;
 
 use crate::errors::{
     self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
 };
+use crate::exp;
 use crate::lexer::UnmatchedDelim;
 
 #[cfg(test)]
@@ -141,7 +145,7 @@ pub struct Parser<'a> {
     pub prev_token: Token,
     pub capture_cfg: bool,
     restrictions: Restrictions,
-    expected_token_types: Vec<TokenType>,
+    expected_token_types: TokenTypeSet,
     token_cursor: TokenCursor,
     // The number of calls to `bump`, i.e. the position in the token stream.
     num_bump_calls: u32,
@@ -367,48 +371,21 @@ impl TokenCursor {
     }
 }
 
-#[derive(Debug, Clone, PartialEq)]
-enum TokenType {
-    Token(TokenKind),
-    Keyword(Symbol),
-    Operator,
-    Lifetime,
-    Ident,
-    Path,
-    Type,
-    Const,
-}
-
-impl TokenType {
-    fn to_string(&self) -> String {
-        match self {
-            TokenType::Token(t) => format!("`{}`", pprust::token_kind_to_string(t)),
-            TokenType::Keyword(kw) => format!("`{kw}`"),
-            TokenType::Operator => "an operator".to_string(),
-            TokenType::Lifetime => "lifetime".to_string(),
-            TokenType::Ident => "identifier".to_string(),
-            TokenType::Path => "path".to_string(),
-            TokenType::Type => "type".to_string(),
-            TokenType::Const => "a const expression".to_string(),
-        }
-    }
-}
-
 /// A sequence separator.
 #[derive(Debug)]
-struct SeqSep {
+struct SeqSep<'a> {
     /// The separator token.
-    sep: Option<TokenKind>,
+    sep: Option<ExpTokenPair<'a>>,
     /// `true` if a trailing separator is allowed.
     trailing_sep_allowed: bool,
 }
 
-impl SeqSep {
-    fn trailing_allowed(t: TokenKind) -> SeqSep {
-        SeqSep { sep: Some(t), trailing_sep_allowed: true }
+impl<'a> SeqSep<'a> {
+    fn trailing_allowed(sep: ExpTokenPair<'a>) -> SeqSep<'a> {
+        SeqSep { sep: Some(sep), trailing_sep_allowed: true }
     }
 
-    fn none() -> SeqSep {
+    fn none() -> SeqSep<'a> {
         SeqSep { sep: None, trailing_sep_allowed: false }
     }
 }
@@ -490,7 +467,7 @@ impl<'a> Parser<'a> {
             prev_token: Token::dummy(),
             capture_cfg: false,
             restrictions: Restrictions::empty(),
-            expected_token_types: Vec::new(),
+            expected_token_types: TokenTypeSet::new(),
             token_cursor: TokenCursor { curr: TokenTreeCursor::new(stream), stack: Vec::new() },
             num_bump_calls: 0,
             break_last_token: 0,
@@ -553,16 +530,16 @@ impl<'a> Parser<'a> {
     }
 
     /// Expects and consumes the token `t`. Signals an error if the next token is not `t`.
-    pub fn expect(&mut self, t: &TokenKind) -> PResult<'a, Recovered> {
+    pub fn expect(&mut self, exp: ExpTokenPair<'_>) -> PResult<'a, Recovered> {
         if self.expected_token_types.is_empty() {
-            if self.token == *t {
+            if self.token == *exp.tok {
                 self.bump();
                 Ok(Recovered::No)
             } else {
-                self.unexpected_try_recover(t)
+                self.unexpected_try_recover(exp.tok)
             }
         } else {
-            self.expect_one_of(slice::from_ref(t), &[])
+            self.expect_one_of(slice::from_ref(&exp), &[])
         }
     }
 
@@ -571,13 +548,13 @@ impl<'a> Parser<'a> {
     /// anything. Signal a fatal error if next token is unexpected.
     fn expect_one_of(
         &mut self,
-        edible: &[TokenKind],
-        inedible: &[TokenKind],
+        edible: &[ExpTokenPair<'_>],
+        inedible: &[ExpTokenPair<'_>],
     ) -> PResult<'a, Recovered> {
-        if edible.contains(&self.token.kind) {
+        if edible.iter().any(|exp| exp.tok == &self.token.kind) {
             self.bump();
             Ok(Recovered::No)
-        } else if inedible.contains(&self.token.kind) {
+        } else if inedible.iter().any(|exp| exp.tok == &self.token.kind) {
             // leave it in the input
             Ok(Recovered::No)
         } else if self.token != token::Eof
@@ -622,10 +599,10 @@ impl<'a> Parser<'a> {
     /// This method will automatically add `tok` to `expected_token_types` if `tok` is not
     /// encountered.
     #[inline]
-    fn check(&mut self, tok: &TokenKind) -> bool {
-        let is_present = self.token == *tok;
+    fn check(&mut self, exp: ExpTokenPair<'_>) -> bool {
+        let is_present = self.token == *exp.tok;
         if !is_present {
-            self.expected_token_types.push(TokenType::Token(tok.clone()));
+            self.expected_token_types.insert(exp.token_type);
         }
         is_present
     }
@@ -653,8 +630,8 @@ impl<'a> Parser<'a> {
     /// Consumes a token 'tok' if it exists. Returns whether the given token was present.
     #[inline]
     #[must_use]
-    pub fn eat(&mut self, tok: &TokenKind) -> bool {
-        let is_present = self.check(tok);
+    pub fn eat(&mut self, exp: ExpTokenPair<'_>) -> bool {
+        let is_present = self.check(exp);
         if is_present {
             self.bump()
         }
@@ -665,23 +642,23 @@ impl<'a> Parser<'a> {
     /// An expectation is also added for diagnostics purposes.
     #[inline]
     #[must_use]
-    fn check_keyword(&mut self, kw: Symbol) -> bool {
-        let is_keyword = self.token.is_keyword(kw);
+    fn check_keyword(&mut self, exp: ExpKeywordPair) -> bool {
+        let is_keyword = self.token.is_keyword(exp.kw);
         if !is_keyword {
-            self.expected_token_types.push(TokenType::Keyword(kw));
+            self.expected_token_types.insert(exp.token_type);
         }
         is_keyword
     }
 
     #[inline]
     #[must_use]
-    fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
-        if self.check_keyword(kw) {
+    fn check_keyword_case(&mut self, exp: ExpKeywordPair, case: Case) -> bool {
+        if self.check_keyword(exp) {
             true
         // Do an ASCII case-insensitive match, because all keywords are ASCII.
         } else if case == Case::Insensitive
             && let Some((ident, IdentIsRaw::No)) = self.token.ident()
-            && ident.as_str().eq_ignore_ascii_case(kw.as_str())
+            && ident.as_str().eq_ignore_ascii_case(exp.kw.as_str())
         {
             true
         } else {
@@ -694,8 +671,8 @@ impl<'a> Parser<'a> {
     // Public for rustc_builtin_macros and rustfmt usage.
     #[inline]
     #[must_use]
-    pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
-        let is_keyword = self.check_keyword(kw);
+    pub fn eat_keyword(&mut self, exp: ExpKeywordPair) -> bool {
+        let is_keyword = self.check_keyword(exp);
         if is_keyword {
             self.bump();
         }
@@ -707,14 +684,14 @@ impl<'a> Parser<'a> {
     /// This is useful for recovery.
     #[inline]
     #[must_use]
-    fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
-        if self.eat_keyword(kw) {
+    fn eat_keyword_case(&mut self, exp: ExpKeywordPair, case: Case) -> bool {
+        if self.eat_keyword(exp) {
             true
         } else if case == Case::Insensitive
             && let Some((ident, IdentIsRaw::No)) = self.token.ident()
-            && ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
+            && ident.as_str().to_lowercase() == exp.kw.as_str().to_lowercase()
         {
-            self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() });
+            self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: exp.kw.as_str() });
             self.bump();
             true
         } else {
@@ -738,8 +715,8 @@ impl<'a> Parser<'a> {
     /// If the given word is not a keyword, signals an error.
     /// If the next token is not the given word, signals an error.
     /// Otherwise, eats it.
-    pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
-        if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
+    pub fn expect_keyword(&mut self, exp: ExpKeywordPair) -> PResult<'a, ()> {
+        if !self.eat_keyword(exp) { self.unexpected() } else { Ok(()) }
     }
 
     /// Is the given keyword `kw` followed by a non-reserved identifier?
@@ -748,9 +725,9 @@ impl<'a> Parser<'a> {
     }
 
     #[inline]
-    fn check_or_expected(&mut self, ok: bool, typ: TokenType) -> bool {
+    fn check_or_expected(&mut self, ok: bool, token_type: TokenType) -> bool {
         if !ok {
-            self.expected_token_types.push(typ);
+            self.expected_token_types.insert(token_type);
         }
         ok
     }
@@ -795,22 +772,19 @@ impl<'a> Parser<'a> {
     /// Otherwise returns `false`.
     #[inline]
     fn check_plus(&mut self) -> bool {
-        self.check_or_expected(
-            self.token.is_like_plus(),
-            TokenType::Token(token::BinOp(token::Plus)),
-        )
+        self.check_or_expected(self.token.is_like_plus(), TokenType::Plus)
     }
 
     /// Eats the expected token if it's present possibly breaking
     /// compound tokens like multi-character operators in process.
     /// Returns `true` if the token was eaten.
-    fn break_and_eat(&mut self, expected: TokenKind) -> bool {
-        if self.token == expected {
+    fn break_and_eat(&mut self, exp: ExpTokenPair<'_>) -> bool {
+        if self.token == *exp.tok {
             self.bump();
             return true;
         }
         match self.token.kind.break_two_token_op(1) {
-            Some((first, second)) if first == expected => {
+            Some((first, second)) if first == *exp.tok => {
                 let first_span = self.psess.source_map().start_point(self.token.span);
                 let second_span = self.token.span.with_lo(first_span.hi());
                 self.token = Token::new(first, first_span);
@@ -827,7 +801,7 @@ impl<'a> Parser<'a> {
                 true
             }
             _ => {
-                self.expected_token_types.push(TokenType::Token(expected));
+                self.expected_token_types.insert(exp.token_type);
                 false
             }
         }
@@ -835,24 +809,24 @@ impl<'a> Parser<'a> {
 
     /// Eats `+` possibly breaking tokens like `+=` in process.
     fn eat_plus(&mut self) -> bool {
-        self.break_and_eat(token::BinOp(token::Plus))
+        self.break_and_eat(exp!(Plus))
     }
 
     /// Eats `&` possibly breaking tokens like `&&` in process.
     /// Signals an error if `&` is not eaten.
     fn expect_and(&mut self) -> PResult<'a, ()> {
-        if self.break_and_eat(token::BinOp(token::And)) { Ok(()) } else { self.unexpected() }
+        if self.break_and_eat(exp!(And)) { Ok(()) } else { self.unexpected() }
     }
 
     /// Eats `|` possibly breaking tokens like `||` in process.
     /// Signals an error if `|` was not eaten.
     fn expect_or(&mut self) -> PResult<'a, ()> {
-        if self.break_and_eat(token::BinOp(token::Or)) { Ok(()) } else { self.unexpected() }
+        if self.break_and_eat(exp!(Or)) { Ok(()) } else { self.unexpected() }
     }
 
     /// Eats `<` possibly breaking tokens like `<<` in process.
     fn eat_lt(&mut self) -> bool {
-        let ate = self.break_and_eat(token::Lt);
+        let ate = self.break_and_eat(exp!(Lt));
         if ate {
             // See doc comment for `unmatched_angle_bracket_count`.
             self.unmatched_angle_bracket_count += 1;
@@ -870,7 +844,7 @@ impl<'a> Parser<'a> {
     /// Eats `>` possibly breaking tokens like `>>` in process.
     /// Signals an error if `>` was not eaten.
     fn expect_gt(&mut self) -> PResult<'a, ()> {
-        if self.break_and_eat(token::Gt) {
+        if self.break_and_eat(exp!(Gt)) {
             // See doc comment for `unmatched_angle_bracket_count`.
             if self.unmatched_angle_bracket_count > 0 {
                 self.unmatched_angle_bracket_count -= 1;
@@ -885,10 +859,10 @@ impl<'a> Parser<'a> {
     /// Checks if the next token is contained within `closes`, and returns `true` if so.
     fn expect_any_with_type(
         &mut self,
-        closes_expected: &[&TokenKind],
+        closes_expected: &[ExpTokenPair<'_>],
         closes_not_expected: &[&TokenKind],
     ) -> bool {
-        closes_expected.iter().any(|k| self.check(k))
+        closes_expected.iter().any(|&close| self.check(close))
             || closes_not_expected.iter().any(|k| self.check_noexpect(k))
     }
 
@@ -897,9 +871,9 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_seq_to_before_tokens<T>(
         &mut self,
-        closes_expected: &[&TokenKind],
+        closes_expected: &[ExpTokenPair<'_>],
         closes_not_expected: &[&TokenKind],
-        sep: SeqSep,
+        sep: SeqSep<'_>,
         mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
         let mut first = true;
@@ -911,13 +885,13 @@ impl<'a> Parser<'a> {
             if let token::CloseDelim(..) | token::Eof = self.token.kind {
                 break;
             }
-            if let Some(t) = &sep.sep {
+            if let Some(exp) = sep.sep {
                 if first {
                     // no separator for the first element
                     first = false;
                 } else {
                     // check for separator
-                    match self.expect(t) {
+                    match self.expect(exp) {
                         Ok(Recovered::No) => {
                             self.current_closure.take();
                         }
@@ -928,7 +902,7 @@ impl<'a> Parser<'a> {
                         }
                         Err(mut expect_err) => {
                             let sp = self.prev_token.span.shrink_to_hi();
-                            let token_str = pprust::token_kind_to_string(t);
+                            let token_str = pprust::token_kind_to_string(exp.tok);
 
                             match self.current_closure.take() {
                                 Some(closure_spans) if self.token == TokenKind::Semi => {
@@ -948,7 +922,7 @@ impl<'a> Parser<'a> {
 
                                 _ => {
                                     // Attempt to keep parsing if it was a similar separator.
-                                    if let Some(tokens) = t.similar_tokens() {
+                                    if let Some(tokens) = exp.tok.similar_tokens() {
                                         if tokens.contains(&self.token.kind) {
                                             self.bump();
                                         }
@@ -998,15 +972,17 @@ impl<'a> Parser<'a> {
                                     // Parsing failed, therefore it must be something more serious
                                     // than just a missing separator.
                                     for xx in &e.children {
-                                        // propagate the help message from sub error 'e' to main error 'expect_err;
+                                        // Propagate the help message from sub error `e` to main
+                                        // error `expect_err`.
                                         expect_err.children.push(xx.clone());
                                     }
                                     e.cancel();
                                     if self.token == token::Colon {
-                                        // we will try to recover in `maybe_recover_struct_lit_bad_delims`
+                                        // We will try to recover in
+                                        // `maybe_recover_struct_lit_bad_delims`.
                                         return Err(expect_err);
-                                    } else if let [token::CloseDelim(Delimiter::Parenthesis)] =
-                                        closes_expected
+                                    } else if let [exp] = closes_expected
+                                        && exp.token_type == TokenType::CloseParen
                                     {
                                         return Err(expect_err);
                                     } else {
@@ -1040,7 +1016,7 @@ impl<'a> Parser<'a> {
     ) -> PResult<'a, ()> {
         let initial_semicolon = self.token.span;
 
-        while self.eat(&TokenKind::Semi) {
+        while self.eat(exp!(Semi)) {
             let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| {
                 e.cancel();
                 None
@@ -1096,8 +1072,8 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_seq_to_before_end<T>(
         &mut self,
-        close: &TokenKind,
-        sep: SeqSep,
+        close: ExpTokenPair<'_>,
+        sep: SeqSep<'_>,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing, Recovered)> {
         self.parse_seq_to_before_tokens(&[close], &[], sep, f)
@@ -1108,8 +1084,8 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_seq_to_end<T>(
         &mut self,
-        close: &TokenKind,
-        sep: SeqSep,
+        close: ExpTokenPair<'_>,
+        sep: SeqSep<'_>,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         let (val, trailing, recovered) = self.parse_seq_to_before_end(close, sep, f)?;
@@ -1127,9 +1103,9 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_unspanned_seq<T>(
         &mut self,
-        open: &TokenKind,
-        close: &TokenKind,
-        sep: SeqSep,
+        open: ExpTokenPair<'_>,
+        close: ExpTokenPair<'_>,
+        sep: SeqSep<'_>,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         self.expect(open)?;
@@ -1141,15 +1117,11 @@ impl<'a> Parser<'a> {
     /// closing bracket.
     fn parse_delim_comma_seq<T>(
         &mut self,
-        delim: Delimiter,
+        open: ExpTokenPair<'_>,
+        close: ExpTokenPair<'_>,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
-        self.parse_unspanned_seq(
-            &token::OpenDelim(delim),
-            &token::CloseDelim(delim),
-            SeqSep::trailing_allowed(token::Comma),
-            f,
-        )
+        self.parse_unspanned_seq(open, close, SeqSep::trailing_allowed(exp!(Comma)), f)
     }
 
     /// Parses a comma-separated sequence delimited by parentheses (e.g. `(x, y)`).
@@ -1159,7 +1131,7 @@ impl<'a> Parser<'a> {
         &mut self,
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
-        self.parse_delim_comma_seq(Delimiter::Parenthesis, f)
+        self.parse_delim_comma_seq(exp!(OpenParen), exp!(CloseParen), f)
     }
 
     /// Advance the parser by one token using provided token as the next one.
@@ -1265,11 +1237,11 @@ impl<'a> Parser<'a> {
     /// Parses asyncness: `async` or nothing.
     fn parse_coroutine_kind(&mut self, case: Case) -> Option<CoroutineKind> {
         let span = self.token.uninterpolated_span();
-        if self.eat_keyword_case(kw::Async, case) {
+        if self.eat_keyword_case(exp!(Async), case) {
             // FIXME(gen_blocks): Do we want to unconditionally parse `gen` and then
             // error if edition <= 2024, like we do with async and edition <= 2018?
             if self.token.uninterpolated_span().at_least_rust_2024()
-                && self.eat_keyword_case(kw::Gen, case)
+                && self.eat_keyword_case(exp!(Gen), case)
             {
                 let gen_span = self.prev_token.uninterpolated_span();
                 Some(CoroutineKind::AsyncGen {
@@ -1285,7 +1257,7 @@ impl<'a> Parser<'a> {
                 })
             }
         } else if self.token.uninterpolated_span().at_least_rust_2024()
-            && self.eat_keyword_case(kw::Gen, case)
+            && self.eat_keyword_case(exp!(Gen), case)
         {
             Some(CoroutineKind::Gen {
                 span,
@@ -1299,9 +1271,9 @@ impl<'a> Parser<'a> {
 
     /// Parses fn unsafety: `unsafe`, `safe` or nothing.
     fn parse_safety(&mut self, case: Case) -> Safety {
-        if self.eat_keyword_case(kw::Unsafe, case) {
+        if self.eat_keyword_case(exp!(Unsafe), case) {
             Safety::Unsafe(self.prev_token.uninterpolated_span())
-        } else if self.eat_keyword_case(kw::Safe, case) {
+        } else if self.eat_keyword_case(exp!(Safe), case) {
             Safety::Safe(self.prev_token.uninterpolated_span())
         } else {
             Safety::Default
@@ -1327,7 +1299,7 @@ impl<'a> Parser<'a> {
         if (self.check_const_closure() == is_closure)
             && !self
                 .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
-            && self.eat_keyword_case(kw::Const, case)
+            && self.eat_keyword_case(exp!(Const), case)
         {
             Const::Yes(self.prev_token.uninterpolated_span())
         } else {
@@ -1340,7 +1312,7 @@ impl<'a> Parser<'a> {
         if pat {
             self.psess.gated_spans.gate(sym::inline_const_pat, span);
         }
-        self.expect_keyword(kw::Const)?;
+        self.expect_keyword(exp!(Const))?;
         let (attrs, blk) = self.parse_inner_attrs_and_block()?;
         let anon_const = AnonConst {
             id: DUMMY_NODE_ID,
@@ -1352,19 +1324,19 @@ impl<'a> Parser<'a> {
 
     /// Parses mutability (`mut` or nothing).
     fn parse_mutability(&mut self) -> Mutability {
-        if self.eat_keyword(kw::Mut) { Mutability::Mut } else { Mutability::Not }
+        if self.eat_keyword(exp!(Mut)) { Mutability::Mut } else { Mutability::Not }
     }
 
     /// Parses reference binding mode (`ref`, `ref mut`, or nothing).
     fn parse_byref(&mut self) -> ByRef {
-        if self.eat_keyword(kw::Ref) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
+        if self.eat_keyword(exp!(Ref)) { ByRef::Yes(self.parse_mutability()) } else { ByRef::No }
     }
 
     /// Possibly parses mutability (`const` or `mut`).
     fn parse_const_or_mut(&mut self) -> Option<Mutability> {
-        if self.eat_keyword(kw::Mut) {
+        if self.eat_keyword(exp!(Mut)) {
             Some(Mutability::Mut)
-        } else if self.eat_keyword(kw::Const) {
+        } else if self.eat_keyword(exp!(Const)) {
             Some(Mutability::Not)
         } else {
             None
@@ -1395,7 +1367,7 @@ impl<'a> Parser<'a> {
     fn parse_attr_args(&mut self) -> PResult<'a, AttrArgs> {
         Ok(if let Some(args) = self.parse_delim_args_inner() {
             AttrArgs::Delimited(args)
-        } else if self.eat(&token::Eq) {
+        } else if self.eat(exp!(Eq)) {
             let eq_span = self.prev_token.span;
             AttrArgs::Eq { eq_span, expr: self.parse_expr_force_collect()? }
         } else {
@@ -1404,9 +1376,9 @@ impl<'a> Parser<'a> {
     }
 
     fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
-        let delimited = self.check(&token::OpenDelim(Delimiter::Parenthesis))
-            || self.check(&token::OpenDelim(Delimiter::Bracket))
-            || self.check(&token::OpenDelim(Delimiter::Brace));
+        let delimited = self.check(exp!(OpenParen))
+            || self.check(exp!(OpenBracket))
+            || self.check(exp!(OpenBrace));
 
         delimited.then(|| {
             let TokenTree::Delimited(dspan, _, delim, tokens) = self.parse_token_tree() else {
@@ -1485,7 +1457,7 @@ impl<'a> Parser<'a> {
     pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> {
         maybe_whole!(self, NtVis, |vis| vis.into_inner());
 
-        if !self.eat_keyword(kw::Pub) {
+        if !self.eat_keyword(exp!(Pub)) {
             // We need a span for our `Spanned<VisibilityKind>`, but there's inherently no
             // keyword to grab a span from for inherited visibility; an empty span at the
             // beginning of the current token would seem to be the "Schelling span".
@@ -1497,7 +1469,7 @@ impl<'a> Parser<'a> {
         }
         let lo = self.prev_token.span;
 
-        if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
+        if self.check(exp!(OpenParen)) {
             // We don't `self.bump()` the `(` yet because this might be a struct definition where
             // `()` or a tuple might be allowed. For example, `struct Struct(pub (), pub (usize));`.
             // Because of this, we only `bump` the `(` if we're assured it is appropriate to do so
@@ -1507,7 +1479,7 @@ impl<'a> Parser<'a> {
                 self.bump(); // `(`
                 self.bump(); // `in`
                 let path = self.parse_path(PathStyle::Mod)?; // `path`
-                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
+                self.expect(exp!(CloseParen))?; // `)`
                 let vis = VisibilityKind::Restricted {
                     path: P(path),
                     id: ast::DUMMY_NODE_ID,
@@ -1524,7 +1496,7 @@ impl<'a> Parser<'a> {
                 // Parse `pub(crate)`, `pub(self)`, or `pub(super)`.
                 self.bump(); // `(`
                 let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
-                self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
+                self.expect(exp!(CloseParen))?; // `)`
                 let vis = VisibilityKind::Restricted {
                     path: P(path),
                     id: ast::DUMMY_NODE_ID,
@@ -1550,7 +1522,7 @@ impl<'a> Parser<'a> {
     fn recover_incorrect_vis_restriction(&mut self) -> PResult<'a, ()> {
         self.bump(); // `(`
         let path = self.parse_path(PathStyle::Mod)?;
-        self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
+        self.expect(exp!(CloseParen))?; // `)`
 
         let path_str = pprust::path_to_string(&path);
         self.dcx()
@@ -1561,7 +1533,7 @@ impl<'a> Parser<'a> {
 
     /// Parses `extern string_literal?`.
     fn parse_extern(&mut self, case: Case) -> Extern {
-        if self.eat_keyword_case(kw::Extern, case) {
+        if self.eat_keyword_case(exp!(Extern), case) {
             let mut extern_span = self.prev_token.span;
             let abi = self.parse_abi();
             if let Some(abi) = abi {
@@ -1601,7 +1573,7 @@ impl<'a> Parser<'a> {
 
     /// Checks for `::` or, potentially, `:::` and then look ahead after it.
     fn check_path_sep_and_look_ahead(&mut self, looker: impl Fn(&Token) -> bool) -> bool {
-        if self.check(&token::PathSep) {
+        if self.check(exp!(PathSep)) {
             if self.may_recover() && self.look_ahead(1, |t| t.kind == token::Colon) {
                 debug_assert!(!self.look_ahead(1, &looker), "Looker must not match on colon");
                 self.look_ahead(2, looker)