Auto merge of #69129 - Centril:macro-legacy-errors, r=petrochenkov

Transition macro_legacy_warnings into a hard error

Fixes https://github.com/rust-lang/rust/issues/67098.

r? @petrochenkov
diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs
index 371d1f7..77db2a5 100644
--- a/src/librustc_expand/expand.rs
+++ b/src/librustc_expand/expand.rs
@@ -832,7 +832,7 @@
         span: Span,
     ) -> AstFragment {
         let mut parser = self.cx.new_parser_from_tts(toks);
-        match parse_ast_fragment(&mut parser, kind, false) {
+        match parse_ast_fragment(&mut parser, kind) {
             Ok(fragment) => {
                 ensure_complete_parse(&mut parser, path, kind.name(), span);
                 fragment
@@ -851,7 +851,6 @@
 pub fn parse_ast_fragment<'a>(
     this: &mut Parser<'a>,
     kind: AstFragmentKind,
-    macro_legacy_warnings: bool,
 ) -> PResult<'a, AstFragment> {
     Ok(match kind {
         AstFragmentKind::Items => {
@@ -884,11 +883,9 @@
         }
         AstFragmentKind::Stmts => {
             let mut stmts = SmallVec::new();
-            while this.token != token::Eof &&
-                    // won't make progress on a `}`
-                    this.token != token::CloseDelim(token::Brace)
-            {
-                if let Some(stmt) = this.parse_full_stmt(macro_legacy_warnings)? {
+            // Won't make progress on a `}`.
+            while this.token != token::Eof && this.token != token::CloseDelim(token::Brace) {
+                if let Some(stmt) = this.parse_full_stmt()? {
                     stmts.push(stmt);
                 }
             }
diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs
index f6abcce..f3c827b 100644
--- a/src/librustc_expand/mbe/macro_rules.rs
+++ b/src/librustc_expand/mbe/macro_rules.rs
@@ -87,7 +87,7 @@
 impl<'a> ParserAnyMacro<'a> {
     crate fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFragment {
         let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
-        let fragment = panictry!(parse_ast_fragment(parser, kind, true).map_err(|mut e| {
+        let fragment = panictry!(parse_ast_fragment(parser, kind).map_err(|mut e| {
             if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
                 if !e.span.is_dummy() {
                     // early end of macro arm (#52866)
diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs
index 742fc48..0ce0e0d 100644
--- a/src/librustc_parse/parser/stmt.rs
+++ b/src/librustc_parse/parser/stmt.rs
@@ -22,17 +22,14 @@
     /// Parses a statement. This stops just before trailing semicolons on everything but items.
     /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
     pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
-        Ok(self.parse_stmt_without_recovery(true).unwrap_or_else(|mut e| {
+        Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| {
             e.emit();
             self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
             None
         }))
     }
 
-    fn parse_stmt_without_recovery(
-        &mut self,
-        macro_legacy_warnings: bool,
-    ) -> PResult<'a, Option<Stmt>> {
+    fn parse_stmt_without_recovery(&mut self) -> PResult<'a, Option<Stmt>> {
         maybe_whole!(self, NtStmt, |x| Some(x));
 
         let attrs = self.parse_outer_attributes()?;
@@ -64,7 +61,7 @@
             let path = self.parse_path(PathStyle::Expr)?;
 
             if self.eat(&token::Not) {
-                return self.parse_stmt_mac(lo, attrs.into(), path, macro_legacy_warnings);
+                return self.parse_stmt_mac(lo, attrs.into(), path);
             }
 
             let expr = if self.check(&token::OpenDelim(token::Brace)) {
@@ -127,7 +124,6 @@
         lo: Span,
         attrs: AttrVec,
         path: ast::Path,
-        legacy_warnings: bool,
     ) -> PResult<'a, Option<Stmt>> {
         let args = self.parse_mac_args()?;
         let delim = args.delim();
@@ -140,30 +136,6 @@
 
         let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof
         {
-            StmtKind::Mac(P((mac, style, attrs.into())))
-        }
-        // We used to incorrectly stop parsing macro-expanded statements here.
-        // If the next token will be an error anyway but could have parsed with the
-        // earlier behavior, stop parsing here and emit a warning to avoid breakage.
-        else if legacy_warnings
-            && self.token.can_begin_expr()
-            && match self.token.kind {
-                // These can continue an expression, so we can't stop parsing and warn.
-                token::OpenDelim(token::Paren)
-                | token::OpenDelim(token::Bracket)
-                | token::BinOp(token::Minus)
-                | token::BinOp(token::Star)
-                | token::BinOp(token::And)
-                | token::BinOp(token::Or)
-                | token::AndAnd
-                | token::OrOr
-                | token::DotDot
-                | token::DotDotDot
-                | token::DotDotEq => false,
-                _ => true,
-            }
-        {
-            self.warn_missing_semicolon();
             StmtKind::Mac(P((mac, style, attrs)))
         } else {
             // Since none of the above applied, this is an expression statement macro.
@@ -310,7 +282,7 @@
         //      bar;
         //
         // which is valid in other languages, but not Rust.
-        match self.parse_stmt_without_recovery(false) {
+        match self.parse_stmt_without_recovery() {
             Ok(Some(stmt)) => {
                 if self.look_ahead(1, |t| t == &token::OpenDelim(token::Brace))
                     || do_not_suggest_help
@@ -369,7 +341,7 @@
             if self.token == token::Eof {
                 break;
             }
-            let stmt = match self.parse_full_stmt(false) {
+            let stmt = match self.parse_full_stmt() {
                 Err(mut err) => {
                     self.maybe_annotate_with_ascription(&mut err, false);
                     err.emit();
@@ -389,11 +361,11 @@
     }
 
     /// Parses a statement, including the trailing semicolon.
-    pub fn parse_full_stmt(&mut self, macro_legacy_warnings: bool) -> PResult<'a, Option<Stmt>> {
+    pub fn parse_full_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
         // Skip looking for a trailing semicolon when we have an interpolated statement.
         maybe_whole!(self, NtStmt, |x| Some(x));
 
-        let mut stmt = match self.parse_stmt_without_recovery(macro_legacy_warnings)? {
+        let mut stmt = match self.parse_stmt_without_recovery()? {
             Some(stmt) => stmt,
             None => return Ok(None),
         };
@@ -433,13 +405,8 @@
                 }
             }
             StmtKind::Local(..) => {
-                // We used to incorrectly allow a macro-expanded let statement to lack a semicolon.
-                if macro_legacy_warnings && self.token != token::Semi {
-                    self.warn_missing_semicolon();
-                } else {
-                    self.expect_semi()?;
-                    eat_semi = false;
-                }
+                self.expect_semi()?;
+                eat_semi = false;
             }
             _ => {}
         }
@@ -451,17 +418,6 @@
         Ok(Some(stmt))
     }
 
-    fn warn_missing_semicolon(&self) {
-        self.diagnostic()
-            .struct_span_warn(self.token.span, {
-                &format!("expected `;`, found {}", super::token_descr(&self.token))
-            })
-            .note({
-                "this was erroneously allowed and will become a hard error in a future release"
-            })
-            .emit();
-    }
-
     pub(super) fn mk_block(&self, stmts: Vec<Stmt>, rules: BlockCheckMode, span: Span) -> P<Block> {
         P(Block { stmts, id: DUMMY_NODE_ID, rules, span })
     }
diff --git a/src/test/ui/missing/missing-semicolon-warning.rs b/src/test/ui/missing/missing-semicolon-warning.rs
deleted file mode 100644
index d962a52..0000000
--- a/src/test/ui/missing/missing-semicolon-warning.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// build-pass (FIXME(62277): could be check-pass?)
-#![allow(unused)]
-
-macro_rules! m {
-    ($($e1:expr),*; $($e2:expr),*) => {
-        $( let x = $e1 )*; //~ WARN expected `;`
-        $( println!("{}", $e2) )*; //~ WARN expected `;`
-    }
-}
-
-
-fn main() { m!(0, 0; 0, 0); }
diff --git a/src/test/ui/missing/missing-semicolon-warning.stderr b/src/test/ui/missing/missing-semicolon-warning.stderr
deleted file mode 100644
index ecaefd4..0000000
--- a/src/test/ui/missing/missing-semicolon-warning.stderr
+++ /dev/null
@@ -1,24 +0,0 @@
-warning: expected `;`, found keyword `let`
-  --> $DIR/missing-semicolon-warning.rs:6:12
-   |
-LL |         $( let x = $e1 )*;
-   |            ^^^
-...
-LL | fn main() { m!(0, 0; 0, 0); }
-   |             --------------- in this macro invocation
-   |
-   = note: this was erroneously allowed and will become a hard error in a future release
-   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
-warning: expected `;`, found `println`
-  --> $DIR/missing-semicolon-warning.rs:7:12
-   |
-LL |         $( println!("{}", $e2) )*;
-   |            ^^^^^^^
-...
-LL | fn main() { m!(0, 0; 0, 0); }
-   |             --------------- in this macro invocation
-   |
-   = note: this was erroneously allowed and will become a hard error in a future release
-   = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
-
diff --git a/src/test/ui/parser/missing-semicolon.rs b/src/test/ui/parser/missing-semicolon.rs
new file mode 100644
index 0000000..a24dfa7
--- /dev/null
+++ b/src/test/ui/parser/missing-semicolon.rs
@@ -0,0 +1,8 @@
+macro_rules! m {
+    ($($e1:expr),*; $($e2:expr),*) => {
+        $( let x = $e1 )*; //~ ERROR expected one of `.`, `;`, `?`, or
+        $( println!("{}", $e2) )*;
+    }
+}
+
+fn main() { m!(0, 0; 0, 0); }
diff --git a/src/test/ui/parser/missing-semicolon.stderr b/src/test/ui/parser/missing-semicolon.stderr
new file mode 100644
index 0000000..26cb3d1
--- /dev/null
+++ b/src/test/ui/parser/missing-semicolon.stderr
@@ -0,0 +1,13 @@
+error: expected one of `.`, `;`, `?`, or an operator, found keyword `let`
+  --> $DIR/missing-semicolon.rs:3:12
+   |
+LL |         $( let x = $e1 )*;
+   |            ^^^ expected one of `.`, `;`, `?`, or an operator
+...
+LL | fn main() { m!(0, 0; 0, 0); }
+   |             --------------- in this macro invocation
+   |
+   = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+