From e4076e34f8215cff65c4deaff4ba7fbda20d2a7f Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Mon, 29 Jul 2024 21:21:15 -0400
Subject: [PATCH 1/2] Mark Parser::eat/check methods as must_use

---
 .../rustc_builtin_macros/src/pattern_type.rs  |  2 +-
 compiler/rustc_parse/src/parser/expr.rs       |  5 +++--
 compiler/rustc_parse/src/parser/generics.rs   |  3 ++-
 compiler/rustc_parse/src/parser/item.rs       |  7 ++++---
 compiler/rustc_parse/src/parser/mod.rs        | 19 +++++++++++++++----
 compiler/rustc_parse/src/parser/path.rs       |  3 ++-
 tests/crashes/123809.rs                       |  2 +-
 tests/ui/type/pattern_types/missing-is.rs     |  8 ++++++++
 tests/ui/type/pattern_types/missing-is.stderr |  8 ++++++++
 9 files changed, 44 insertions(+), 13 deletions(-)
 create mode 100644 tests/ui/type/pattern_types/missing-is.rs
 create mode 100644 tests/ui/type/pattern_types/missing-is.stderr

diff --git a/compiler/rustc_builtin_macros/src/pattern_type.rs b/compiler/rustc_builtin_macros/src/pattern_type.rs
index 87187125541b2..869d203f68eba 100644
--- a/compiler/rustc_builtin_macros/src/pattern_type.rs
+++ b/compiler/rustc_builtin_macros/src/pattern_type.rs
@@ -24,7 +24,7 @@ fn parse_pat_ty<'a>(cx: &mut ExtCtxt<'a>, stream: TokenStream) -> PResult<'a, (P
     let mut parser = cx.new_parser_from_tts(stream);
 
     let ty = parser.parse_ty()?;
-    parser.eat_keyword(sym::is);
+    parser.expect_keyword(sym::is)?;
     let pat = parser.parse_pat_no_top_alt(None, None)?;
 
     Ok((ty, pat))
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a242dc5cd582d..a4d9d97045d2a 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3153,7 +3153,8 @@ impl<'a> Parser<'a> {
 
                 if !require_comma {
                     arm_body = Some(expr);
-                    this.eat(&token::Comma);
+                    // Eat a comma if it exists, though.
+                    let _ = this.eat(&token::Comma);
                     Ok(Recovered::No)
                 } else if let Some((span, guar)) =
                     this.parse_arm_body_missing_braces(&expr, arrow_span)
@@ -3654,7 +3655,7 @@ impl<'a> Parser<'a> {
                         fields.push(f);
                     }
                     self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore);
-                    self.eat(&token::Comma);
+                    let _ = self.eat(&token::Comma);
                 }
             }
         }
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index a67e3d05551db..9124c15707de5 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -178,7 +178,8 @@ impl<'a> Parser<'a> {
                             span: this.prev_token.span,
                         });
 
-                        this.eat(&token::Comma);
+                        // Eat a trailing comma, if it exists.
+                        let _ = this.eat(&token::Comma);
                     }
 
                     let param = if this.check_lifetime() {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 68da055494528..baa5eb2df635d 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1192,13 +1192,14 @@ impl<'a> Parser<'a> {
         mut safety: Safety,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
+        // FIXME: This recovery should be tested better.
         if safety == Safety::Default
             && self.token.is_keyword(kw::Unsafe)
             && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
         {
             self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
             safety = Safety::Unsafe(self.token.span);
-            self.eat_keyword(kw::Unsafe);
+            let _ = self.eat_keyword(kw::Unsafe);
         }
         let module = ast::ForeignMod {
             safety,
@@ -1759,7 +1760,7 @@ impl<'a> Parser<'a> {
                     }
                 }
             }
-            self.eat(&token::CloseDelim(Delimiter::Brace));
+            self.expect(&token::CloseDelim(Delimiter::Brace))?;
         } else {
             let token_str = super::token_descr(&self.token);
             let where_str = if parsed_where { "" } else { "`where`, or " };
@@ -1902,7 +1903,7 @@ impl<'a> Parser<'a> {
                         if let Some(_guar) = guar {
                             // Handle a case like `Vec<u8>>,` where we can continue parsing fields
                             // after the comma
-                            self.eat(&token::Comma);
+                            let _ = self.eat(&token::Comma);
 
                             // `check_trailing_angle_brackets` already emitted a nicer error, as
                             // proven by the presence of `_guar`. We can continue parsing.
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 26ee5bfdee42c..e01f605722b72 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -547,6 +547,7 @@ impl<'a> Parser<'a> {
     }
 
     #[inline]
+    #[must_use]
     fn check_noexpect(&self, tok: &TokenKind) -> bool {
         self.token == *tok
     }
@@ -556,6 +557,7 @@ impl<'a> Parser<'a> {
     /// the main purpose of this function is to reduce the cluttering of the suggestions list
     /// which using the normal eat method could introduce in some cases.
     #[inline]
+    #[must_use]
     fn eat_noexpect(&mut self, tok: &TokenKind) -> bool {
         let is_present = self.check_noexpect(tok);
         if is_present {
@@ -566,6 +568,7 @@ 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);
         if is_present {
@@ -577,12 +580,14 @@ impl<'a> Parser<'a> {
     /// If the next token is the given keyword, returns `true` without eating it.
     /// An expectation is also added for diagnostics purposes.
     #[inline]
+    #[must_use]
     fn check_keyword(&mut self, kw: Symbol) -> bool {
         self.expected_tokens.push(TokenType::Keyword(kw));
         self.token.is_keyword(kw)
     }
 
     #[inline]
+    #[must_use]
     fn check_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.check_keyword(kw) {
             return true;
@@ -602,6 +607,7 @@ impl<'a> Parser<'a> {
     /// Otherwise, returns `false`. An expectation is also added for diagnostics purposes.
     // Public for rustc_builtin_macros and rustfmt usage.
     #[inline]
+    #[must_use]
     pub fn eat_keyword(&mut self, kw: Symbol) -> bool {
         if self.check_keyword(kw) {
             self.bump();
@@ -615,6 +621,7 @@ impl<'a> Parser<'a> {
     /// If the case differs (and is ignored) an error is issued.
     /// This is useful for recovery.
     #[inline]
+    #[must_use]
     fn eat_keyword_case(&mut self, kw: Symbol, case: Case) -> bool {
         if self.eat_keyword(kw) {
             return true;
@@ -636,6 +643,7 @@ impl<'a> Parser<'a> {
     /// Otherwise, returns `false`. No expectation is added.
     // Public for rustc_builtin_macros usage.
     #[inline]
+    #[must_use]
     pub fn eat_keyword_noexpect(&mut self, kw: Symbol) -> bool {
         if self.token.is_keyword(kw) {
             self.bump();
@@ -648,7 +656,7 @@ 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.
-    fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
+    pub fn expect_keyword(&mut self, kw: Symbol) -> PResult<'a, ()> {
         if !self.eat_keyword(kw) { self.unexpected() } else { Ok(()) }
     }
 
@@ -1025,8 +1033,11 @@ impl<'a> Parser<'a> {
         f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
     ) -> PResult<'a, (ThinVec<T>, Trailing)> {
         let (val, trailing, recovered) = self.parse_seq_to_before_end(ket, sep, f)?;
-        if matches!(recovered, Recovered::No) {
-            self.eat(ket);
+        if matches!(recovered, Recovered::No) && !self.eat(ket) {
+            self.dcx().span_delayed_bug(
+                self.token.span,
+                "recovered but `parse_seq_to_before_end` did not give us the ket token",
+            );
         }
         Ok((val, trailing))
     }
@@ -1250,7 +1261,7 @@ impl<'a> Parser<'a> {
         if pat {
             self.psess.gated_spans.gate(sym::inline_const_pat, span);
         }
-        self.eat_keyword(kw::Const);
+        self.expect_keyword(kw::Const)?;
         let (attrs, blk) = self.parse_inner_attrs_and_block()?;
         let anon_const = AnonConst {
             id: DUMMY_NODE_ID,
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c5111226d3783..70d2c98d4f1bd 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -313,7 +313,8 @@ impl<'a> Parser<'a> {
                 }
 
                 // Generic arguments are found - `<`, `(`, `::<` or `::(`.
-                self.eat(&token::PathSep);
+                // First, eat `::` if it exists.
+                let _ = self.eat(&token::PathSep);
                 let lo = self.token.span;
                 let args = if self.eat_lt() {
                     // `<'a, T, A = U>`
diff --git a/tests/crashes/123809.rs b/tests/crashes/123809.rs
index c7a633aed018c..75abe6dc0cd83 100644
--- a/tests/crashes/123809.rs
+++ b/tests/crashes/123809.rs
@@ -1,4 +1,4 @@
 //@ known-bug: #123809
-type Positive = std::pat::pattern_type!(std::pat:: is 0..);
+type Positive = std::pat::pattern_type!(std::pat is 0..);
 
 pub fn main() {}
diff --git a/tests/ui/type/pattern_types/missing-is.rs b/tests/ui/type/pattern_types/missing-is.rs
new file mode 100644
index 0000000000000..2fbcc1908efcb
--- /dev/null
+++ b/tests/ui/type/pattern_types/missing-is.rs
@@ -0,0 +1,8 @@
+#![feature(core_pattern_type, core_pattern_types)]
+
+use std::pat::pattern_type;
+
+fn main() {
+    let x: pattern_type!(i32 0..1);
+    //~^ ERROR expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0`
+}
diff --git a/tests/ui/type/pattern_types/missing-is.stderr b/tests/ui/type/pattern_types/missing-is.stderr
new file mode 100644
index 0000000000000..8ed654fe9071a
--- /dev/null
+++ b/tests/ui/type/pattern_types/missing-is.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!`, `(`, `+`, `::`, `<`, or `is`, found `0`
+  --> $DIR/missing-is.rs:6:30
+   |
+LL |     let x: pattern_type!(i32 0..1);
+   |                              ^ expected one of `!`, `(`, `+`, `::`, `<`, or `is`
+
+error: aborting due to 1 previous error
+

From 4776ac0f885044685c6f6127632f42522a88c05d Mon Sep 17 00:00:00 2001
From: Michael Goulet <michael@errs.io>
Date: Tue, 30 Jul 2024 10:10:36 -0400
Subject: [PATCH 2/2] Suppress must_use on eat calls in rustfmt

---
 src/tools/rustfmt/src/parse/macros/lazy_static.rs | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
index 7baac247e2229..b6de5f8691c25 100644
--- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs
+++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
@@ -33,15 +33,17 @@ pub(crate) fn parse_lazy_static(
     }
     while parser.token.kind != TokenKind::Eof {
         // Parse a `lazy_static!` item.
+        // FIXME: These `eat_*` calls should be converted to `parse_or` to avoid
+        // silently formatting malformed lazy-statics.
         let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No);
-        parser.eat_keyword(kw::Static);
-        parser.eat_keyword(kw::Ref);
+        let _ = parser.eat_keyword(kw::Static);
+        let _ = parser.eat_keyword(kw::Ref);
         let id = parse_or!(parse_ident);
-        parser.eat(&TokenKind::Colon);
+        let _ = parser.eat(&TokenKind::Colon);
         let ty = parse_or!(parse_ty);
-        parser.eat(&TokenKind::Eq);
+        let _ = parser.eat(&TokenKind::Eq);
         let expr = parse_or!(parse_expr);
-        parser.eat(&TokenKind::Semi);
+        let _ = parser.eat(&TokenKind::Semi);
         result.push((vis, id, ty, expr));
     }