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

@ -209,16 +209,12 @@ impl HasTokens for Attribute {
impl HasTokens for Nonterminal { impl HasTokens for Nonterminal {
fn tokens(&self) -> Option<&LazyAttrTokenStream> { fn tokens(&self) -> Option<&LazyAttrTokenStream> {
match self { match self {
Nonterminal::NtItem(item) => item.tokens(),
Nonterminal::NtStmt(stmt) => stmt.tokens(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
Nonterminal::NtBlock(block) => block.tokens(), Nonterminal::NtBlock(block) => block.tokens(),
} }
} }
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> { fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
match self { match self {
Nonterminal::NtItem(item) => item.tokens_mut(),
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(), Nonterminal::NtBlock(block) => block.tokens_mut(),
} }

View file

@ -6,6 +6,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc( #![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(deny(warnings))) test(attr(deny(warnings)))

View file

@ -895,19 +895,7 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
// multiple items there.... // multiple items there....
fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) { fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
match nt { match nt {
token::NtItem(item) => visit_clobber(item, |item| {
// This is probably okay, because the only visitors likely to
// peek inside interpolated nodes will be renamings/markings,
// which map single items to single items.
vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item")
}),
token::NtBlock(block) => vis.visit_block(block), token::NtBlock(block) => vis.visit_block(block),
token::NtStmt(stmt) => visit_clobber(stmt, |stmt| {
// See reasoning above.
stmt.map(|stmt| {
vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item")
})
}),
token::NtExpr(expr) => vis.visit_expr(expr), token::NtExpr(expr) => vis.visit_expr(expr),
token::NtLiteral(expr) => vis.visit_expr(expr), token::NtLiteral(expr) => vis.visit_expr(expr),
} }

View file

@ -870,6 +870,7 @@ impl Token {
/// Is this a pre-parsed expression dropped into the token stream /// Is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)? /// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool { pub fn is_whole_expr(&self) -> bool {
#[allow(irrefutable_let_patterns)] // FIXME: temporary
if let Interpolated(nt) = &self.kind if let Interpolated(nt) = &self.kind
&& let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt && let NtExpr(_) | NtLiteral(_) | NtBlock(_) = &**nt
{ {
@ -1103,9 +1104,7 @@ pub enum NtExprKind {
#[derive(Clone, Encodable, Decodable)] #[derive(Clone, Encodable, Decodable)]
/// For interpolation during macro expansion. /// For interpolation during macro expansion.
pub enum Nonterminal { pub enum Nonterminal {
NtItem(P<ast::Item>),
NtBlock(P<ast::Block>), NtBlock(P<ast::Block>),
NtStmt(P<ast::Stmt>),
NtExpr(P<ast::Expr>), NtExpr(P<ast::Expr>),
NtLiteral(P<ast::Expr>), NtLiteral(P<ast::Expr>),
} }
@ -1196,18 +1195,14 @@ impl fmt::Display for NonterminalKind {
impl Nonterminal { impl Nonterminal {
pub fn use_span(&self) -> Span { pub fn use_span(&self) -> Span {
match self { match self {
NtItem(item) => item.span,
NtBlock(block) => block.span, NtBlock(block) => block.span,
NtStmt(stmt) => stmt.span,
NtExpr(expr) | NtLiteral(expr) => expr.span, NtExpr(expr) | NtLiteral(expr) => expr.span,
} }
} }
pub fn descr(&self) -> &'static str { pub fn descr(&self) -> &'static str {
match self { match self {
NtItem(..) => "item",
NtBlock(..) => "block", NtBlock(..) => "block",
NtStmt(..) => "statement",
NtExpr(..) => "expression", NtExpr(..) => "expression",
NtLiteral(..) => "literal", NtLiteral(..) => "literal",
} }
@ -1227,9 +1222,7 @@ impl PartialEq for Nonterminal {
impl fmt::Debug for Nonterminal { impl fmt::Debug for Nonterminal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
NtItem(..) => f.pad("NtItem(..)"),
NtBlock(..) => f.pad("NtBlock(..)"), NtBlock(..) => f.pad("NtBlock(..)"),
NtStmt(..) => f.pad("NtStmt(..)"),
NtExpr(..) => f.pad("NtExpr(..)"), NtExpr(..) => f.pad("NtExpr(..)"),
NtLiteral(..) => f.pad("NtLiteral(..)"), NtLiteral(..) => f.pad("NtLiteral(..)"),
} }

View file

@ -23,7 +23,7 @@ use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_serialize::{Decodable, Encodable}; use rustc_serialize::{Decodable, Encodable};
use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym}; use rustc_span::{DUMMY_SP, Span, SpanDecoder, SpanEncoder, Symbol, sym};
use crate::ast::{AttrStyle, StmtKind}; use crate::ast::AttrStyle;
use crate::ast_traits::{HasAttrs, HasTokens}; use crate::ast_traits::{HasAttrs, HasTokens};
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind}; use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
use crate::{AttrVec, Attribute}; use crate::{AttrVec, Attribute};
@ -461,13 +461,7 @@ impl TokenStream {
pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream { pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt { match nt {
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block) => TokenStream::from_ast(block), Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
// FIXME: Properly collect tokens for empty statements.
TokenStream::token_alone(token::Semi, stmt.span)
}
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr), Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
} }
} }

View file

@ -32,6 +32,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -77,6 +77,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]

View file

@ -2,6 +2,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -140,8 +140,9 @@ impl CfgEval<'_> {
Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap()) Annotatable::ForeignItem(self.flat_map_foreign_item(item).pop().unwrap())
} }
Annotatable::Stmt(_) => { Annotatable::Stmt(_) => {
let stmt = let stmt = parser
parser.parse_stmt_without_recovery(false, ForceCollect::Yes)?.unwrap(); .parse_stmt_without_recovery(false, ForceCollect::Yes, false)?
.unwrap();
Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap())) Annotatable::Stmt(P(self.flat_map_stmt(stmt).pop().unwrap()))
} }
Annotatable::Expr(_) => { Annotatable::Expr(_) => {

View file

@ -5,6 +5,7 @@
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]

View file

@ -2,6 +2,7 @@
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]

View file

@ -1,6 +1,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -3,6 +3,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(rustdoc_internals)] #![feature(rustdoc_internals)]
// tidy-alphabetical-end // tidy-alphabetical-end

View file

@ -7,6 +7,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable #![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(decl_macro)] #![feature(decl_macro)]

View file

@ -7,7 +7,7 @@ use std::sync::Arc;
use rustc_ast::attr::{AttributeExt, MarkedAttrs}; use rustc_ast::attr::{AttributeExt, MarkedAttrs};
use rustc_ast::ptr::P; use rustc_ast::ptr::P;
use rustc_ast::token::Nonterminal; use rustc_ast::token::MetaVarKind;
use rustc_ast::tokenstream::TokenStream; use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::visit::{AssocCtxt, Visitor};
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind}; use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
@ -19,7 +19,7 @@ use rustc_feature::Features;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools}; use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::MACRO_ARGUMENTS;
use rustc_parse::parser::Parser; use rustc_parse::parser::{ForceCollect, Parser};
use rustc_session::config::CollapseMacroDebuginfo; use rustc_session::config::CollapseMacroDebuginfo;
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_session::{Limit, Session}; use rustc_session::{Limit, Session};
@ -1405,13 +1405,13 @@ pub fn parse_macro_name_and_helper_attrs(
/// If this item looks like a specific enums from `rental`, emit a fatal error. /// If this item looks like a specific enums from `rental`, emit a fatal error.
/// See #73345 and #83125 for more details. /// See #73345 and #83125 for more details.
/// FIXME(#73933): Remove this eventually. /// FIXME(#73933): Remove this eventually.
fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) { fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) {
let name = item.ident.name; let name = item.ident.name;
if name == sym::ProceduralMasqueradeDummyType if name == sym::ProceduralMasqueradeDummyType
&& let ast::ItemKind::Enum(enum_def, _) = &item.kind && let ast::ItemKind::Enum(enum_def, _) = &item.kind
&& let [variant] = &*enum_def.variants && let [variant] = &*enum_def.variants
&& variant.ident.name == sym::Input && variant.ident.name == sym::Input
&& let FileName::Real(real) = sess.source_map().span_to_filename(item.ident.span) && let FileName::Real(real) = psess.source_map().span_to_filename(item.ident.span)
&& let Some(c) = real && let Some(c) = real
.local_path() .local_path()
.unwrap_or(Path::new("")) .unwrap_or(Path::new(""))
@ -1429,7 +1429,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) {
}; };
if crate_matches { if crate_matches {
sess.dcx().emit_fatal(errors::ProcMacroBackCompat { psess.dcx().emit_fatal(errors::ProcMacroBackCompat {
crate_name: "rental".to_string(), crate_name: "rental".to_string(),
fixed_version: "0.5.6".to_string(), fixed_version: "0.5.6".to_string(),
}); });
@ -1437,7 +1437,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) {
} }
} }
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) { pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) {
let item = match ann { let item = match ann {
Annotatable::Item(item) => item, Annotatable::Item(item) => item,
Annotatable::Stmt(stmt) => match &stmt.kind { Annotatable::Stmt(stmt) => match &stmt.kind {
@ -1446,17 +1446,36 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &S
}, },
_ => return, _ => return,
}; };
pretty_printing_compatibility_hack(item, sess) pretty_printing_compatibility_hack(item, psess)
} }
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) { pub(crate) fn stream_pretty_printing_compatibility_hack(
let item = match nt { kind: MetaVarKind,
Nonterminal::NtItem(item) => item, stream: &TokenStream,
Nonterminal::NtStmt(stmt) => match &stmt.kind { psess: &ParseSess,
ast::StmtKind::Item(item) => item, ) {
_ => return, let item = match kind {
}, MetaVarKind::Item => {
let mut parser = Parser::new(psess, stream.clone(), None);
// No need to collect tokens for this simple check.
parser
.parse_item(ForceCollect::No)
.expect("failed to reparse item")
.expect("an actual item")
}
MetaVarKind::Stmt => {
let mut parser = Parser::new(psess, stream.clone(), None);
// No need to collect tokens for this simple check.
let stmt = parser
.parse_stmt(ForceCollect::No)
.expect("failed to reparse")
.expect("an actual stmt");
match &stmt.kind {
ast::StmtKind::Item(item) => item.clone(),
_ => return,
}
}
_ => return, _ => return,
}; };
pretty_printing_compatibility_hack(item, sess) pretty_printing_compatibility_hack(&item, psess)
} }

View file

@ -7,7 +7,7 @@ use rustc_ast::token::{
TokenKind, TokenKind,
}; };
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree}; use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::{ExprKind, TyKind}; use rustc_ast::{ExprKind, StmtKind, TyKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize}; use rustc_errors::{Diag, DiagCtxtHandle, PResult, pluralize};
use rustc_parse::lexer::nfc_normalize; use rustc_parse::lexer::nfc_normalize;
@ -323,6 +323,18 @@ pub(super) fn transcribe<'a>(
let kind = token::NtLifetime(*ident, *is_raw); let kind = token::NtLifetime(*ident, *is_raw);
TokenTree::token_alone(kind, sp) TokenTree::token_alone(kind, sp)
} }
MatchedSingle(ParseNtResult::Item(item)) => {
mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
}
MatchedSingle(ParseNtResult::Stmt(stmt)) => {
let stream = if let StmtKind::Empty = stmt.kind {
// FIXME: Properly collect tokens for empty statements.
TokenStream::token_alone(token::Semi, stmt.span)
} else {
TokenStream::from_ast(stmt)
};
mk_delimited(stmt.span, MetaVarKind::Stmt, stream)
}
MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => mk_delimited( MatchedSingle(ParseNtResult::Pat(pat, pat_kind)) => mk_delimited(
pat.span, pat.span,
MetaVarKind::Pat(*pat_kind), MetaVarKind::Pat(*pat_kind),

View file

@ -122,7 +122,7 @@ impl MultiItemModifier for DeriveProcMacro {
// We had a lint for a long time, but now we just emit a hard error. // We had a lint for a long time, but now we just emit a hard error.
// Eventually we might remove the special case hard error check // Eventually we might remove the special case hard error check
// altogether. See #73345. // altogether. See #73345.
crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess); crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
let input = item.to_tokens(); let input = item.to_tokens();
let stream = { let stream = {
let _timer = let _timer =

View file

@ -115,11 +115,43 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
while let Some(tree) = iter.next() { while let Some(tree) = iter.next() {
let (Token { kind, span }, joint) = match tree.clone() { let (Token { kind, span }, joint) = match tree.clone() {
tokenstream::TokenTree::Delimited(span, _, delim, tts) => { tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => {
let delimiter = pm::Delimiter::from_internal(delim); // We used to have an alternative behaviour for crates that
// needed it: a hack used to pass AST fragments to
// attribute and derive macros as a single nonterminal
// token instead of a token stream. Such token needs to be
// "unwrapped" and not represented as a delimited group. We
// had a lint for a long time, but now we just emit a hard
// error. Eventually we might remove the special case hard
// error check altogether. See #73345.
if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim {
crate::base::stream_pretty_printing_compatibility_hack(
kind,
&stream,
rustc.psess(),
);
}
// In `mk_delimited` we avoid nesting invisible delimited
// of the same `MetaVarKind`. Here we do the same but
// ignore the `MetaVarKind` because it is discarded when we
// convert it to a `Group`.
while let Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) = delim {
if stream.len() == 1
&& let tree = stream.iter().next().unwrap()
&& let tokenstream::TokenTree::Delimited(_, _, delim2, stream2) = tree
&& let Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) = delim2
{
delim = *delim2;
stream = stream2.clone();
} else {
break;
}
}
trees.push(TokenTree::Group(Group { trees.push(TokenTree::Group(Group {
delimiter, delimiter: pm::Delimiter::from_internal(delim),
stream: Some(tts), stream: Some(stream),
span: DelimSpan { span: DelimSpan {
open: span.open, open: span.open,
close: span.close, close: span.close,
@ -279,15 +311,6 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
Interpolated(nt) => { Interpolated(nt) => {
let stream = TokenStream::from_nonterminal_ast(&nt); let stream = TokenStream::from_nonterminal_ast(&nt);
// We used to have an alternative behaviour for crates that
// needed it: a hack used to pass AST fragments to
// attribute and derive macros as a single nonterminal
// token instead of a token stream. Such token needs to be
// "unwrapped" and not represented as a delimited group. We
// had a lint for a long time, but now we just emit a hard
// error. Eventually we might remove the special case hard
// error check altogether. See #73345.
crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess);
trees.push(TokenTree::Group(Group { trees.push(TokenTree::Group(Group {
delimiter: pm::Delimiter::None, delimiter: pm::Delimiter::None,
stream: Some(stream), stream: Some(stream),

View file

@ -4,6 +4,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(closure_track_caller)] #![feature(closure_track_caller)]

View file

@ -59,6 +59,7 @@ This API is completely unstable and subject to change.
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]

View file

@ -1,6 +1,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)] #![feature(array_windows)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(if_let_guard)] #![feature(if_let_guard)]

View file

@ -2,6 +2,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![deny(missing_docs)] #![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]

View file

@ -21,6 +21,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(array_windows)] #![feature(array_windows)]

View file

@ -1,5 +1,6 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(coroutines)] #![feature(coroutines)]

View file

@ -29,6 +29,7 @@
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::potential_query_instability)] #![allow(rustc::potential_query_instability)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(allocator_api)] #![feature(allocator_api)]

View file

@ -3,6 +3,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]
#![feature(if_let_guard)] #![feature(if_let_guard)]

View file

@ -1,4 +1,5 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -1,4 +1,5 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)] #![feature(array_windows)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -1,4 +1,5 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)] #![feature(array_windows)]
#![feature(file_buffered)] #![feature(file_buffered)]
#![feature(if_let_guard)] #![feature(if_let_guard)]

View file

@ -4,6 +4,7 @@
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)] #![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)] #![allow(rustc::untranslatable_diagnostic)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)] #![feature(array_windows)]
#![feature(assert_matches)] #![feature(assert_matches)]
#![feature(box_patterns)] #![feature(box_patterns)]

View file

@ -1364,7 +1364,6 @@ impl<'a> Parser<'a> {
self.bump(); self.bump();
return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None))); 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| { } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| {
this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type)) 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); 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. // Consume statements for as long as possible.
Ok(Some(stmt)) => { Ok(Some(stmt)) => {
stmts.push(stmt); stmts.push(stmt);

View file

@ -21,10 +21,10 @@ use super::diagnostics::{ConsumeClosingDelim, dummy_arg};
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign}; use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{ use super::{
AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle, AttrWrapper, ExpKeywordPair, ExpTokenPair, FollowedByType, ForceCollect, Parser, PathStyle,
Trailing, UsePreAttrPos, Recovered, Trailing, UsePreAttrPos,
}; };
use crate::errors::{self, MacroExpandsToAdtField}; 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> { impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser. /// 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, fn_parse_mode: FnParseMode,
force_collect: ForceCollect, force_collect: ForceCollect,
) -> PResult<'a, Option<Item>> { ) -> 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); 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| { self.collect_tokens(None, attrs, force_collect, |this, mut attrs| {
let lo = this.token.span; let lo = this.token.span;

View file

@ -1076,10 +1076,12 @@ impl<'a> Parser<'a> {
let initial_semicolon = self.token.span; let initial_semicolon = self.token.span;
while self.eat(exp!(Semi)) { while self.eat(exp!(Semi)) {
let _ = self.parse_stmt_without_recovery(false, ForceCollect::No).unwrap_or_else(|e| { let _ = self
e.cancel(); .parse_stmt_without_recovery(false, ForceCollect::No, false)
None .unwrap_or_else(|e| {
}); e.cancel();
None
});
} }
expect_err expect_err
@ -1746,6 +1748,8 @@ pub enum ParseNtResult {
Tt(TokenTree), Tt(TokenTree),
Ident(Ident, IdentIsRaw), Ident(Ident, IdentIsRaw),
Lifetime(Ident, IdentIsRaw), Lifetime(Ident, IdentIsRaw),
Item(P<ast::Item>),
Stmt(P<ast::Stmt>),
Pat(P<ast::Pat>, NtPatKind), Pat(P<ast::Pat>, NtPatKind),
Ty(P<ast::Ty>), Ty(P<ast::Ty>),
Meta(P<ast::AttrItem>), Meta(P<ast::AttrItem>),

View file

@ -48,12 +48,11 @@ impl<'a> Parser<'a> {
/// Old variant of `may_be_ident`. Being phased out. /// Old variant of `may_be_ident`. Being phased out.
fn nt_may_be_ident(nt: &Nonterminal) -> bool { fn nt_may_be_ident(nt: &Nonterminal) -> bool {
match nt { match nt {
NtStmt(_) NtExpr(_)
| NtExpr(_)
| NtLiteral(_) // `true`, `false` | NtLiteral(_) // `true`, `false`
=> true, => true,
NtItem(_) | NtBlock(_) => false, NtBlock(_) => false,
} }
} }
@ -96,8 +95,7 @@ impl<'a> Parser<'a> {
token::OpenDelim(Delimiter::Brace) => true, token::OpenDelim(Delimiter::Brace) => true,
token::NtLifetime(..) => true, token::NtLifetime(..) => true,
token::Interpolated(nt) => match &**nt { token::Interpolated(nt) => match &**nt {
NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true, NtBlock(_) | NtExpr(_) | NtLiteral(_) => true,
NtItem(_) => false,
}, },
token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k { token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
MetaVarKind::Block MetaVarKind::Block
@ -147,7 +145,7 @@ impl<'a> Parser<'a> {
// Note that TT is treated differently to all the others. // Note that TT is treated differently to all the others.
NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())), NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())),
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? { NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
Some(item) => NtItem(item), Some(item) => return Ok(ParseNtResult::Item(item)),
None => { None => {
return Err(self return Err(self
.dcx() .dcx()
@ -160,7 +158,7 @@ impl<'a> Parser<'a> {
NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?) NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
} }
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? { NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
Some(s) => NtStmt(P(s)), Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))),
None => { None => {
return Err(self return Err(self
.dcx() .dcx()

View file

@ -5,7 +5,7 @@ use std::ops::Bound;
use ast::Label; use ast::Label;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::ptr::P; 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::util::classify::{self, TrailingBrace};
use rustc_ast::{ use rustc_ast::{
AttrStyle, AttrVec, Block, BlockCheckMode, DUMMY_NODE_ID, Expr, ExprKind, HasAttrs, Local, 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 /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of
/// whether or not we have attributes. /// whether or not we have attributes.
// Public for rustfmt usage. // Public for rustfmt usage.
pub(super) fn parse_stmt(&mut self, force_collect: ForceCollect) -> PResult<'a, Option<Stmt>> { pub 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| { Ok(self.parse_stmt_without_recovery(false, force_collect, false).unwrap_or_else(|e| {
e.emit(); e.emit();
self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore);
None None
@ -42,23 +42,27 @@ impl<'a> Parser<'a> {
} }
/// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of
/// whether or not we have attributes. /// whether or not we have attributes. If `force_full_expr` is true, parses the stmt without
// Public for `cfg_eval` macro expansion. /// using `Restriction::STMT_EXPR`. Public for `cfg_eval` macro expansion.
pub fn parse_stmt_without_recovery( pub fn parse_stmt_without_recovery(
&mut self, &mut self,
capture_semi: bool, capture_semi: bool,
force_collect: ForceCollect, force_collect: ForceCollect,
force_full_expr: bool,
) -> PResult<'a, Option<Stmt>> { ) -> PResult<'a, Option<Stmt>> {
let pre_attr_pos = self.collect_pos(); let pre_attr_pos = self.collect_pos();
let attrs = self.parse_outer_attributes()?; let attrs = self.parse_outer_attributes()?;
let lo = self.token.span; 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| { stmt.visit_attrs(|stmt_attrs| {
attrs.prepend_to_nt_inner(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]) { if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
self.bump(); self.bump();
@ -147,12 +151,14 @@ impl<'a> Parser<'a> {
} else if self.token != token::CloseDelim(Delimiter::Brace) { } else if self.token != token::CloseDelim(Delimiter::Brace) {
// Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case // Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case
// above. // above.
let restrictions =
if force_full_expr { Restrictions::empty() } else { Restrictions::STMT_EXPR };
let e = self.collect_tokens( let e = self.collect_tokens(
Some(pre_attr_pos), Some(pre_attr_pos),
AttrWrapper::empty(), AttrWrapper::empty(),
force_collect, force_collect,
|this, _empty_attrs| { |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)) Ok((expr, Trailing::No, UsePreAttrPos::Yes))
}, },
)?; )?;
@ -229,11 +235,15 @@ impl<'a> Parser<'a> {
let mac = P(MacCall { path, args }); let mac = P(MacCall { path, args });
let kind = if (style == MacStmtStyle::Braces let kind = if (style == MacStmtStyle::Braces
&& self.token != token::Dot && !matches!(self.token.kind, token::Dot | token::Question))
&& self.token != token::Question) || matches!(
|| self.token == token::Semi self.token.kind,
|| self.token == token::Eof token::Semi
{ | token::Eof
| token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
MetaVarKind::Stmt
)))
) {
StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None })) StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
} else { } else {
// Since none of the above applied, this is an expression statement macro. // Since none of the above applied, this is an expression statement macro.
@ -501,7 +511,7 @@ impl<'a> Parser<'a> {
// bar; // bar;
// //
// which is valid in other languages, but not Rust. // 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 the next token is an open brace, e.g., we have:
// //
// if expr other_expr { // if expr other_expr {
@ -810,10 +820,24 @@ impl<'a> Parser<'a> {
&mut self, &mut self,
recover: AttemptLocalParseRecovery, recover: AttemptLocalParseRecovery,
) -> PResult<'a, Option<Stmt>> { ) -> PResult<'a, Option<Stmt>> {
// Skip looking for a trailing semicolon when we have an interpolated statement. // Skip looking for a trailing semicolon when we have a metavar seq.
maybe_whole!(self, NtStmt, |stmt| Some(stmt.into_inner())); 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); return Ok(None);
}; };

View file

@ -6,6 +6,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(let_chains)] #![feature(let_chains)]

View file

@ -1,5 +1,6 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(associated_type_defaults)] #![feature(associated_type_defaults)]

View file

@ -3,6 +3,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![allow(unused_parens)] #![allow(unused_parens)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(min_specialization)] #![feature(min_specialization)]

View file

@ -4,6 +4,7 @@
//! compiler. //! compiler.
// tidy-alphabetical-start // tidy-alphabetical-start
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(let_chains)] #![feature(let_chains)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
// tidy-alphabetical-end // tidy-alphabetical-end

View file

@ -9,6 +9,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![allow(rustc::usage_of_ty_tykind)] #![allow(rustc::usage_of_ty_tykind)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc( #![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(allow(unused_variables), deny(warnings))) test(attr(allow(unused_variables), deny(warnings)))

View file

@ -89,6 +89,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(let_chains)] #![feature(let_chains)]

View file

@ -1,4 +1,5 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(never_type)] #![feature(never_type)]
#![warn(unreachable_pub)] #![warn(unreachable_pub)]
// tidy-alphabetical-end // tidy-alphabetical-end

View file

@ -6,6 +6,7 @@
// tidy-alphabetical-start // tidy-alphabetical-start
#![allow(internal_features)] #![allow(internal_features)]
#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)] #![doc(rust_logo)]
#![feature(assert_matches)] #![feature(assert_matches)]

View file

@ -0,0 +1,11 @@
//@ check-pass
//
// This shows a tricky case for #124141, where `declare!(_x)` was incorrectly
// being categorised as a `StmtKind::Expr` instead of a `StmtKind::MacCall` in
// `parse_stmt_mac`.
macro_rules! as_stmt { ($s:stmt) => { $s }; }
macro_rules! declare { ($name:ident) => { let $name = 0u32; }; }
fn main() { as_stmt!(declare!(_x)); }

View file

@ -16,7 +16,7 @@ macro complex_nonterminal($nt_item: item) {
struct S; struct S;
} }
n!(a $nt_item b); //~ ERROR no rules expected item `enum E {}` n!(a $nt_item b); //~ ERROR no rules expected `item` metavariable
} }
simple_nonterminal!(a, 'a, (x, y, z)); // OK simple_nonterminal!(a, 'a, (x, y, z)); // OK
@ -32,7 +32,7 @@ macro_rules! foo {
(expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3` (expr $x:expr) => { bar!(expr $x); }; //~ ERROR: no rules expected expression `3`
(literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4` (literal $x:literal) => { bar!(literal $x); }; //~ ERROR: no rules expected literal `4`
(path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected `path` metavariable (path $x:path) => { bar!(path $x); }; //~ ERROR: no rules expected `path` metavariable
(stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected statement `let abc = 0` (stmt $x:stmt) => { bar!(stmt $x); }; //~ ERROR: no rules expected `stmt` metavariable
} }
macro_rules! bar { macro_rules! bar {

View file

@ -1,4 +1,4 @@
error: no rules expected item `enum E {}` error: no rules expected `item` metavariable
--> $DIR/nonterminal-matching.rs:19:10 --> $DIR/nonterminal-matching.rs:19:10
| |
LL | macro n(a $nt_item b) { LL | macro n(a $nt_item b) {
@ -10,7 +10,7 @@ LL | n!(a $nt_item b);
LL | complex_nonterminal!(enum E {}); LL | complex_nonterminal!(enum E {});
| ------------------------------- in this macro invocation | ------------------------------- in this macro invocation
| |
note: while trying to match item `enum E {}` note: while trying to match `item` metavariable
--> $DIR/nonterminal-matching.rs:15:15 --> $DIR/nonterminal-matching.rs:15:15
| |
LL | macro n(a $nt_item b) { LL | macro n(a $nt_item b) {
@ -89,7 +89,7 @@ LL | (path a::b::c) => {};
= help: try using `:tt` instead in the macro definition = help: try using `:tt` instead in the macro definition
= note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
error: no rules expected statement `let abc = 0` error: no rules expected `stmt` metavariable
--> $DIR/nonterminal-matching.rs:35:35 --> $DIR/nonterminal-matching.rs:35:35
| |
LL | (stmt $x:stmt) => { bar!(stmt $x); }; LL | (stmt $x:stmt) => { bar!(stmt $x); };

View file

@ -44,52 +44,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
Group { Group {
delimiter: Brace, delimiter: Brace,
stream: TokenStream [ stream: TokenStream [
Punct {
ch: '#',
spacing: Alone,
span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0),
},
Group { Group {
delimiter: Bracket, delimiter: None,
stream: TokenStream [ stream: TokenStream [
Punct {
ch: '#',
spacing: Alone,
span: $DIR/expand-to-derive.rs:27:5: 27:6 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "rustc_dummy",
span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0),
},
],
span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0),
},
Ident { Ident {
ident: "rustc_dummy", ident: "struct",
span: $DIR/expand-to-derive.rs:27:28: 27:39 (#0), span: $DIR/expand-to-derive.rs:28:5: 28:11 (#0),
},
Ident {
ident: "Inner",
span: $DIR/expand-to-derive.rs:28:12: 28:17 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "other_inner_field",
span: $DIR/expand-to-derive.rs:30:9: 30:26 (#0),
},
Punct {
ch: ':',
spacing: Alone,
span: $DIR/expand-to-derive.rs:30:26: 30:27 (#0),
},
Ident {
ident: "u8",
span: $DIR/expand-to-derive.rs:30:28: 30:30 (#0),
},
Punct {
ch: ',',
spacing: Alone,
span: $DIR/expand-to-derive.rs:30:30: 30:31 (#0),
},
],
span: $DIR/expand-to-derive.rs:28:18: 31:6 (#0),
}, },
], ],
span: $DIR/expand-to-derive.rs:27:6: 27:41 (#0), span: $DIR/expand-to-derive.rs:19:17: 19:22 (#3),
},
Ident {
ident: "struct",
span: $DIR/expand-to-derive.rs:28:5: 28:11 (#0),
},
Ident {
ident: "Inner",
span: $DIR/expand-to-derive.rs:28:12: 28:17 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "other_inner_field",
span: $DIR/expand-to-derive.rs:30:9: 30:26 (#0),
},
Punct {
ch: ':',
spacing: Alone,
span: $DIR/expand-to-derive.rs:30:26: 30:27 (#0),
},
Ident {
ident: "u8",
span: $DIR/expand-to-derive.rs:30:28: 30:30 (#0),
},
Punct {
ch: ',',
spacing: Alone,
span: $DIR/expand-to-derive.rs:30:30: 30:31 (#0),
},
],
span: $DIR/expand-to-derive.rs:28:18: 31:6 (#0),
}, },
Literal { Literal {
kind: Integer, kind: Integer,

View file

@ -19,4 +19,17 @@ macro_rules! expand_it {
fn main() { fn main() {
expand_it!(1 + (25) + 1); expand_it!(1 + (25) + 1);
expand_it!(("hello".len()) ("world".len())); expand_it!(("hello".len()) ("world".len()));
f();
}
// The key thing here is to produce a single `None`-delimited `Group`, even
// though there is multiple levels of macros.
macro_rules! m5 { ($e:expr) => { print_bang_consume!($e) }; }
macro_rules! m4 { ($e:expr) => { m5!($e); } }
macro_rules! m3 { ($e:expr) => { m4!($e); } }
macro_rules! m2 { ($e:expr) => { m3!($e); } }
macro_rules! m1 { ($e:expr) => { m2!($e); } }
fn f() {
m1!(123);
} }

View file

@ -165,3 +165,18 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8), span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8),
}, },
] ]
PRINT-BANG INPUT (DISPLAY): 123
PRINT-BANG INPUT (DEBUG): TokenStream [
Group {
delimiter: None,
stream: TokenStream [
Literal {
kind: Integer,
symbol: "123",
suffix: None,
span: $DIR/nodelim-groups.rs:34:9: 34:12 (#0),
},
],
span: $DIR/nodelim-groups.rs:27:54: 27:56 (#16),
},
]