diff options
| author | Nicholas Nethercote <n.nethercote@gmail.com> | 2024-04-18 14:53:52 +1000 |
|---|---|---|
| committer | Nicholas Nethercote <n.nethercote@gmail.com> | 2025-03-07 14:51:07 +1100 |
| commit | 141719f68a3084f3b96f644c34734af077b9d197 (patch) | |
| tree | e225e18d7f27af1ef8accd3f1d1aa4989b46f334 /compiler/rustc_parse/src | |
| parent | 98a48781feb1220c0cf2feea23f9ef92cdfa7437 (diff) | |
| download | rust-141719f68a3084f3b96f644c34734af077b9d197.tar.gz rust-141719f68a3084f3b96f644c34734af077b9d197.zip | |
Remove `NtItem` and `NtStmt`.
This involves replacing `nt_pretty_printing_compatibility_hack` with `stream_pretty_printing_compatibility_hack`. The handling of statements in `transcribe` is slightly different to other nonterminal kinds, due to the lack of `from_ast` implementation for empty statements. Notable test changes: - `tests/ui/proc-macro/expand-to-derive.rs`: the diff looks large but the only difference is the insertion of a single invisible-delimited group around a metavar.
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/expr.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/nonterminal.rs | 12 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/stmt.rs | 60 |
5 files changed, 64 insertions, 36 deletions
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0a08c6faeb4..cab0c7df3e0 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1357,7 +1357,6 @@ impl<'a> Parser<'a> { self.bump(); return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); } - _ => {} }; } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| { this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) @@ -3046,7 +3045,7 @@ impl<'a> Parser<'a> { } self.restore_snapshot(pre_pat_snapshot); - match self.parse_stmt_without_recovery(true, ForceCollect::No) { + match self.parse_stmt_without_recovery(true, ForceCollect::No, false) { // Consume statements for as long as possible. Ok(Some(stmt)) => { stmts.push(stmt); diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c3b1956ad2e..5d537a0e144 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -21,10 +21,10 @@ use super::diagnostics::{ConsumeClosingDelim, dummy_arg}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::{ AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, - Trailing, UsePreAttrPos, + Recovered, Trailing, UsePreAttrPos, }; use crate::errors::{self, MacroExpandsToAdtField}; -use crate::{exp, fluent_generated as fluent, maybe_whole}; +use crate::{exp, fluent_generated as fluent}; impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. @@ -142,10 +142,13 @@ impl<'a> Parser<'a> { fn_parse_mode: FnParseMode, force_collect: ForceCollect, ) -> PResult<'a, Option<Item>> { - maybe_whole!(self, NtItem, |item| { + if let Some(item) = + self.eat_metavar_seq(MetaVarKind::Item, |this| this.parse_item(ForceCollect::Yes)) + { + let mut item = item.expect("an actual item"); attrs.prepend_to_nt_inner(&mut item.attrs); - Some(item.into_inner()) - }); + return Ok(Some(item.into_inner())); + } self.collect_tokens(None, attrs, force_collect, |this, mut attrs| { let lo = this.token.span; diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 7dabc28c645..0bb6e2ab126 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1076,10 +1076,12 @@ impl<'a> Parser<'a> { let initial_semicolon = self.token.span; while self.eat(exp!(Semi)) { - let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| { - e.cancel(); - None - }); + let _ = self + .parse_stmt_without_recovery(false, ForceCollect::No, false) + .unwrap_or_else(|e| { + e.cancel(); + None + }); } expect_err @@ -1746,6 +1748,8 @@ pub enum ParseNtResult { Tt(TokenTree), Ident(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw), + Item(P<ast::Item>), + Stmt(P<ast::Stmt>), Pat(P<ast::Pat>, NtPatKind), Ty(P<ast::Ty>), Meta(P<ast::AttrItem>), diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs index d537bc17ce3..1123755ce00 100644 --- a/compiler/rustc_parse/src/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -48,12 +48,11 @@ impl<'a> Parser<'a> { /// Old variant of `may_be_ident`. Being phased out. fn nt_may_be_ident(nt: &Nonterminal) -> bool { match nt { - NtStmt(_) - | NtExpr(_) + NtExpr(_) | NtLiteral(_) // `true`, `false` => true, - NtItem(_) | NtBlock(_) => false, + NtBlock(_) => false, } } @@ -96,8 +95,7 @@ impl<'a> Parser<'a> { token::OpenDelim(Delimiter::Brace) => true, token::NtLifetime(..) => true, token::Interpolated(nt) => match &**nt { - NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, - NtItem(_) => false, + NtBlock(_) | NtExpr(_) | NtLiteral(_) => true, }, token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { MetaVarKind::Block @@ -147,7 +145,7 @@ impl<'a> Parser<'a> { // Note that TT is treated differently to all the others. NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { - Some(item) => NtItem(item), + Some(item) => return Ok(ParseNtResult::Item(item)), None => { return Err(self .dcx() @@ -160,7 +158,7 @@ impl<'a> Parser<'a> { NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) } NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { - Some(s) => NtStmt(P(s)), + Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))), None => { return Err(self .dcx() diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 3a9dc5ce798..0896bd88b4c 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -5,7 +5,7 @@ use std::ops::Bound; use ast::Label; use rustc_ast as ast; use rustc_ast::ptr::P; -use rustc_ast::token::{self, Delimiter, TokenKind}; +use rustc_ast::token::{self, Delimiter, InvisibleOrigin, MetaVarKind, TokenKind}; use rustc_ast::util::classify::{self, TrailingBrace}; use rustc_ast::{ AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, Expr, ExprKind, HasAttrs, Local, @@ -33,8 +33,8 @@ impl<'a> Parser<'a> { /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of /// whether or not we have attributes. // Public for rustfmt usage. - pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { - Ok(self.parse_stmt_without_recovery(false, force_collect).unwrap_or_else(|e| { + pub fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { + Ok(self.parse_stmt_without_recovery(false, force_collect, false).unwrap_or_else(|e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); None @@ -42,23 +42,27 @@ impl<'a> Parser<'a> { } /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of - /// whether or not we have attributes. - // Public for `cfg_eval` macro expansion. + /// whether or not we have attributes. If `force_full_expr` is true, parses the stmt without + /// using `Restriction::STMT_EXPR`. Public for `cfg_eval` macro expansion. pub fn parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, + force_full_expr: bool, ) -> PResult<'a, Option<Stmt>> { let pre_attr_pos = self.collect_pos(); let attrs = self.parse_outer_attributes()?; let lo = self.token.span; - maybe_whole!(self, NtStmt, |stmt| { + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + this.parse_stmt_without_recovery(false, ForceCollect::Yes, false) + }) { + let mut stmt = stmt.expect("an actual statement"); stmt.visit_attrs(|stmt_attrs| { attrs.prepend_to_nt_inner(stmt_attrs); }); - Some(stmt.into_inner()) - }); + return Ok(Some(stmt)); + } if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) { self.bump(); @@ -147,12 +151,14 @@ impl<'a> Parser<'a> { } else if self.token != token::CloseDelim(Delimiter::Brace) { // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // above. + let restrictions = + if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR }; let e = self.collect_tokens( Some(pre_attr_pos), AttrWrapper::empty(), force_collect, |this, _empty_attrs| { - let (expr, _) = this.parse_expr_res(Restrictions::STMT_EXPR, attrs)?; + let (expr, _) = this.parse_expr_res(restrictions, attrs)?; Ok((expr, Trailing::No, UsePreAttrPos::Yes)) }, )?; @@ -229,11 +235,15 @@ impl<'a> Parser<'a> { let mac = P(MacCall { path, args }); let kind = if (style == MacStmtStyle::Braces - && self.token != token::Dot - && self.token != token::Question) - || self.token == token::Semi - || self.token == token::Eof - { + && !matches!(self.token.kind, token::Dot | token::Question)) + || matches!( + self.token.kind, + token::Semi + | token::Eof + | token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar( + MetaVarKind::Stmt + ))) + ) { StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) } else { // Since none of the above applied, this is an expression statement macro. @@ -501,7 +511,7 @@ impl<'a> Parser<'a> { // bar; // // which is valid in other languages, but not Rust. - match self.parse_stmt_without_recovery(false, ForceCollect::No) { + match self.parse_stmt_without_recovery(false, ForceCollect::No, false) { // If the next token is an open brace, e.g., we have: // // if expr other_expr { @@ -810,10 +820,24 @@ impl<'a> Parser<'a> { &mut self, recover: AttemptLocalParseRecovery, ) -> PResult<'a, Option<Stmt>> { - // Skip looking for a trailing semicolon when we have an interpolated statement. - maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner())); + // Skip looking for a trailing semicolon when we have a metavar seq. + if let Some(stmt) = self.eat_metavar_seq(MetaVarKind::Stmt, |this| { + // Why pass `true` for `force_full_expr`? Statement expressions are less expressive + // than "full" expressions, due to the `STMT_EXPR` restriction, and sometimes need + // parentheses. E.g. the "full" expression `match paren_around_match {} | true` when + // used in statement context must be written `(match paren_around_match {} | true)`. + // However, if the expression we are parsing in this statement context was pasted by a + // declarative macro, it may have come from a "full" expression context, and lack + // these parentheses. So we lift the `STMT_EXPR` restriction to ensure the statement + // will reparse successfully. + this.parse_stmt_without_recovery(false, ForceCollect::No, true) + }) { + let stmt = stmt.expect("an actual statement"); + return Ok(Some(stmt)); + } - let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No)? else { + let Some(mut stmt) = self.parse_stmt_without_recovery(true, ForceCollect::No, false)? + else { return Ok(None); }; |
