1
Fork 0

Auto merge of #138083 - nnethercote:rm-NtItem-NtStmt, r=petrochenkov

Remove `NtItem` and `NtStmt`

Another piece of #124141.

r? `@petrochenkov`
This commit is contained in:
bors 2025-03-12 14:18:36 +00:00
commit aaa2d47dae
49 changed files with 273 additions and 145 deletions

View file

@ -1364,7 +1364,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))
@ -3064,7 +3063,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);

View file

@ -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;

View file

@ -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>),

View file

@ -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()

View file

@ -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);
};