Skip to content

Commit b53a0e4

Browse files
committed
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/macros/nonterminal-matching.rs` now passes. Removal of `Token::Interpolated` will remove the "captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens" restriction. - `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. I hope this doesn't cause any new `ProceduralMasquerade`-type problems.
1 parent c193815 commit b53a0e4

23 files changed

+246
-282
lines changed

compiler/rustc_ast/src/ast_traits.rs

-4
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,6 @@ impl HasTokens for Attribute {
231231
impl HasTokens for Nonterminal {
232232
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
233233
match self {
234-
Nonterminal::NtItem(item) => item.tokens(),
235-
Nonterminal::NtStmt(stmt) => stmt.tokens(),
236234
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
237235
Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
238236
Nonterminal::NtPath(path) => path.tokens(),
@@ -242,8 +240,6 @@ impl HasTokens for Nonterminal {
242240
}
243241
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
244242
match self {
245-
Nonterminal::NtItem(item) => item.tokens_mut(),
246-
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
247243
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
248244
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
249245
Nonterminal::NtPath(path) => path.tokens_mut(),

compiler/rustc_ast/src/mut_visit.rs

-12
Original file line numberDiff line numberDiff line change
@@ -823,19 +823,7 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
823823
// multiple items there....
824824
pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
825825
match nt {
826-
token::NtItem(item) => visit_clobber(item, |item| {
827-
// This is probably okay, because the only visitors likely to
828-
// peek inside interpolated nodes will be renamings/markings,
829-
// which map single items to single items.
830-
vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item")
831-
}),
832826
token::NtBlock(block) => vis.visit_block(block),
833-
token::NtStmt(stmt) => visit_clobber(stmt, |stmt| {
834-
// See reasoning above.
835-
stmt.map(|stmt| {
836-
vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item")
837-
})
838-
}),
839827
token::NtExpr(expr) => vis.visit_expr(expr),
840828
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
841829
token::NtLifetime(ident) => vis.visit_ident(ident),

compiler/rustc_ast/src/token.rs

-8
Original file line numberDiff line numberDiff line change
@@ -924,9 +924,7 @@ impl PartialEq<TokenKind> for Token {
924924
#[derive(Clone, Encodable, Decodable)]
925925
/// For interpolation during macro expansion.
926926
pub enum Nonterminal {
927-
NtItem(P<ast::Item>),
928927
NtBlock(P<ast::Block>),
929-
NtStmt(P<ast::Stmt>),
930928
NtExpr(P<ast::Expr>),
931929
NtIdent(Ident, IdentIsRaw),
932930
NtLifetime(Ident),
@@ -1017,9 +1015,7 @@ impl fmt::Display for NonterminalKind {
10171015
impl Nonterminal {
10181016
pub fn use_span(&self) -> Span {
10191017
match self {
1020-
NtItem(item) => item.span,
10211018
NtBlock(block) => block.span,
1022-
NtStmt(stmt) => stmt.span,
10231019
NtExpr(expr) | NtLiteral(expr) => expr.span,
10241020
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
10251021
NtMeta(attr_item) => attr_item.span(),
@@ -1029,9 +1025,7 @@ impl Nonterminal {
10291025

10301026
pub fn descr(&self) -> &'static str {
10311027
match self {
1032-
NtItem(..) => "item",
10331028
NtBlock(..) => "block",
1034-
NtStmt(..) => "statement",
10351029
NtExpr(..) => "expression",
10361030
NtLiteral(..) => "literal",
10371031
NtIdent(..) => "identifier",
@@ -1061,9 +1055,7 @@ impl PartialEq for Nonterminal {
10611055
impl fmt::Debug for Nonterminal {
10621056
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
10631057
match *self {
1064-
NtItem(..) => f.pad("NtItem(..)"),
10651058
NtBlock(..) => f.pad("NtBlock(..)"),
1066-
NtStmt(..) => f.pad("NtStmt(..)"),
10671059
NtExpr(..) => f.pad("NtExpr(..)"),
10681060
NtIdent(..) => f.pad("NtIdent(..)"),
10691061
NtLiteral(..) => f.pad("NtLiteral(..)"),

compiler/rustc_ast/src/tokenstream.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
//! and a borrowed `TokenStream` is sufficient to build an owned `TokenStream` without taking
1414
//! ownership of the original.
1515
16-
use crate::ast::{AttrStyle, StmtKind};
16+
use crate::ast::AttrStyle;
1717
use crate::ast_traits::{HasAttrs, HasSpan, HasTokens};
1818
use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
1919
use crate::AttrVec;
@@ -450,6 +450,16 @@ impl TokenStream {
450450
TokenStream::new(vec![TokenTree::token_alone(kind, span)])
451451
}
452452

453+
/// Create a token stream containing a single `Delimited`.
454+
pub fn delimited(
455+
span: DelimSpan,
456+
spacing: DelimSpacing,
457+
delim: Delimiter,
458+
tts: TokenStream,
459+
) -> TokenStream {
460+
TokenStream::new(vec![TokenTree::Delimited(span, spacing, delim, tts)])
461+
}
462+
453463
pub fn from_ast(node: &(impl HasAttrs + HasSpan + HasTokens + fmt::Debug)) -> TokenStream {
454464
let Some(tokens) = node.tokens() else {
455465
panic!("missing tokens for node at {:?}: {:?}", node.span(), node);
@@ -473,13 +483,7 @@ impl TokenStream {
473483
Nonterminal::NtLifetime(ident) => {
474484
TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
475485
}
476-
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
477486
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
478-
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
479-
// FIXME: Properly collect tokens for empty statements.
480-
TokenStream::token_alone(token::Semi, stmt.span)
481-
}
482-
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
483487
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
484488
Nonterminal::NtPath(path) => TokenStream::from_ast(path),
485489
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),

compiler/rustc_ast_pretty/src/pprust/state.rs

-2
Original file line numberDiff line numberDiff line change
@@ -847,9 +847,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
847847
token::NtExpr(e) => self.expr_to_string(e),
848848
token::NtMeta(e) => self.attr_item_to_string(e),
849849
token::NtPath(e) => self.path_to_string(e),
850-
token::NtItem(e) => self.item_to_string(e),
851850
token::NtBlock(e) => self.block_to_string(e),
852-
token::NtStmt(e) => self.stmt_to_string(e),
853851
&token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
854852
token::NtLifetime(e) => e.to_string(),
855853
token::NtLiteral(e) => self.expr_to_string(e),

compiler/rustc_expand/src/base.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::module::DirOwnership;
55

66
use rustc_ast::attr::MarkedAttrs;
77
use rustc_ast::ptr::P;
8-
use rustc_ast::token::{self, Nonterminal};
8+
use rustc_ast::token::{self, NonterminalKind};
99
use rustc_ast::tokenstream::TokenStream;
1010
use rustc_ast::visit::{AssocCtxt, Visitor};
1111
use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
@@ -1524,13 +1524,13 @@ pub fn parse_macro_name_and_helper_attrs(
15241524
/// asserts in old versions of those crates and their wide use in the ecosystem.
15251525
/// See issue #73345 for more details.
15261526
/// FIXME(#73933): Remove this eventually.
1527-
fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
1527+
fn pretty_printing_compatibility_hack(item: &Item, psess: &ParseSess) -> bool {
15281528
let name = item.ident.name;
15291529
if name == sym::ProceduralMasqueradeDummyType {
15301530
if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
15311531
if let [variant] = &*enum_def.variants {
15321532
if variant.ident.name == sym::Input {
1533-
let filename = sess.source_map().span_to_filename(item.ident.span);
1533+
let filename = psess.source_map().span_to_filename(item.ident.span);
15341534
if let FileName::Real(real) = filename {
15351535
if let Some(c) = real
15361536
.local_path()
@@ -1554,7 +1554,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
15541554
if crate_matches {
15551555
// FIXME: make this translatable
15561556
#[allow(rustc::untranslatable_diagnostic)]
1557-
sess.psess.buffer_lint_with_diagnostic(
1557+
psess.buffer_lint_with_diagnostic(
15581558
PROC_MACRO_BACK_COMPAT,
15591559
item.ident.span,
15601560
ast::CRATE_NODE_ID,
@@ -1575,7 +1575,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &Session) -> bool {
15751575
false
15761576
}
15771577

1578-
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &Session) -> bool {
1578+
pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, psess: &ParseSess) -> bool {
15791579
let item = match ann {
15801580
Annotatable::Item(item) => item,
15811581
Annotatable::Stmt(stmt) => match &stmt.kind {
@@ -1584,17 +1584,34 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &S
15841584
},
15851585
_ => return false,
15861586
};
1587-
pretty_printing_compatibility_hack(item, sess)
1587+
pretty_printing_compatibility_hack(item, psess)
15881588
}
15891589

1590-
pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &Session) -> bool {
1591-
let item = match nt {
1592-
Nonterminal::NtItem(item) => item,
1593-
Nonterminal::NtStmt(stmt) => match &stmt.kind {
1594-
ast::StmtKind::Item(item) => item,
1595-
_ => return false,
1596-
},
1590+
pub(crate) fn stream_pretty_printing_compatibility_hack(
1591+
kind: NonterminalKind,
1592+
stream: &TokenStream,
1593+
psess: &ParseSess,
1594+
) -> bool {
1595+
let item = match kind {
1596+
NonterminalKind::Item => {
1597+
let mut parser = parser::Parser::new(psess, stream.clone(), None);
1598+
let Ok(parser::ParseNtResult::Item(item)) = parser.parse_nonterminal(kind) else {
1599+
panic!("failed to reparse");
1600+
};
1601+
item
1602+
}
1603+
NonterminalKind::Stmt => {
1604+
// njn: reparsing and then checking for StmtKind::Item sucks, hmm
1605+
let mut parser = parser::Parser::new(psess, stream.clone(), None);
1606+
let Ok(parser::ParseNtResult::Stmt(stmt)) = parser.parse_nonterminal(kind) else {
1607+
panic!("failed to reparse");
1608+
};
1609+
match &stmt.kind {
1610+
ast::StmtKind::Item(item) => item.clone(),
1611+
_ => return false,
1612+
}
1613+
}
15971614
_ => return false,
15981615
};
1599-
pretty_printing_compatibility_hack(item, sess)
1616+
pretty_printing_compatibility_hack(&item, psess)
16001617
}

compiler/rustc_expand/src/mbe/transcribe.rs

+13
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use crate::mbe::{self, KleeneOp, MetaVarExpr};
88
use rustc_ast::mut_visit::{self, MutVisitor};
99
use rustc_ast::token::{self, Delimiter, InvisibleOrigin, NonterminalKind, Token, TokenKind};
1010
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
11+
use rustc_ast::StmtKind;
1112
use rustc_data_structures::fx::FxHashMap;
1213
use rustc_errors::{pluralize, Diag, PResult};
1314
use rustc_parse::parser::ParseNtResult;
@@ -266,6 +267,18 @@ pub(super) fn transcribe<'a>(
266267
// without wrapping them into groups.
267268
maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
268269
}
270+
MatchedSingle(ParseNtResult::Item(ref item)) => {
271+
mk_delimited(NonterminalKind::Item, TokenStream::from_ast(item))
272+
}
273+
MatchedSingle(ParseNtResult::Stmt(ref stmt)) => {
274+
let stream = if let StmtKind::Empty = stmt.kind {
275+
// FIXME: Properly collect tokens for empty statements.
276+
TokenStream::token_alone(token::Semi, stmt.span)
277+
} else {
278+
TokenStream::from_ast(stmt)
279+
};
280+
mk_delimited(NonterminalKind::Stmt, stream)
281+
}
269282
MatchedSingle(ParseNtResult::PatParam(ref pat, inferred)) => mk_delimited(
270283
NonterminalKind::PatParam { inferred: *inferred },
271284
TokenStream::from_ast(pat),

compiler/rustc_expand/src/proc_macro.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use crate::proc_macro_server;
44

55
use rustc_ast as ast;
66
use rustc_ast::ptr::P;
7-
use rustc_ast::token;
8-
use rustc_ast::tokenstream::TokenStream;
9-
use rustc_data_structures::sync::Lrc;
7+
use rustc_ast::token::{Delimiter, InvisibleOrigin, NonterminalKind};
8+
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream};
109
use rustc_errors::ErrorGuaranteed;
1110
use rustc_parse::parser::ForceCollect;
1211
use rustc_session::config::ProcMacroExecutionStrategy;
@@ -120,14 +119,25 @@ impl MultiItemModifier for DeriveProcMacro {
120119
// We need special handling for statement items
121120
// (e.g. `fn foo() { #[derive(Debug)] struct Bar; }`)
122121
let is_stmt = matches!(item, Annotatable::Stmt(..));
123-
let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess);
122+
let hack = crate::base::ann_pretty_printing_compatibility_hack(&item, &ecx.sess.psess);
124123
let input = if hack {
125-
let nt = match item {
126-
Annotatable::Item(item) => token::NtItem(item),
127-
Annotatable::Stmt(stmt) => token::NtStmt(stmt),
124+
let delim_span = DelimSpan::from_single(DUMMY_SP);
125+
let delim_spacing = DelimSpacing::new(Spacing::Alone, Spacing::Alone); // njn: ?
126+
match item {
127+
Annotatable::Item(item) => TokenStream::delimited(
128+
delim_span,
129+
delim_spacing,
130+
Delimiter::Invisible(InvisibleOrigin::MetaVar(NonterminalKind::Item)),
131+
TokenStream::from_ast(&item),
132+
),
133+
Annotatable::Stmt(stmt) => TokenStream::delimited(
134+
delim_span,
135+
delim_spacing,
136+
Delimiter::Invisible(InvisibleOrigin::MetaVar(NonterminalKind::Stmt)),
137+
TokenStream::from_ast(&stmt),
138+
),
128139
_ => unreachable!(),
129-
};
130-
TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
140+
}
131141
} else {
132142
item.to_tokens()
133143
};

compiler/rustc_expand/src/proc_macro_server.rs

+31-26
Original file line numberDiff line numberDiff line change
@@ -113,17 +113,32 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
113113

114114
while let Some(tree) = cursor.next() {
115115
let (Token { kind, span }, joint) = match tree.clone() {
116-
tokenstream::TokenTree::Delimited(span, _, delim, tts) => {
117-
let delimiter = pm::Delimiter::from_internal(delim);
118-
trees.push(TokenTree::Group(Group {
119-
delimiter,
120-
stream: Some(tts),
121-
span: DelimSpan {
122-
open: span.open,
123-
close: span.close,
124-
entire: span.entire(),
125-
},
126-
}));
116+
tokenstream::TokenTree::Delimited(span, _, delim, stream) => {
117+
// A hack used to pass AST fragments to attribute and derive
118+
// macros as a single nonterminal token instead of a token
119+
// stream. Such token needs to be "unwrapped" and not
120+
// represented as a delimited group.
121+
// FIXME: It needs to be removed, but there are some
122+
// compatibility issues (see #73345).
123+
if let Delimiter::Invisible(InvisibleOrigin::MetaVar(kind)) = delim
124+
&& crate::base::stream_pretty_printing_compatibility_hack(
125+
kind,
126+
&stream,
127+
rustc.psess(),
128+
)
129+
{
130+
trees.extend(Self::from_internal((stream, rustc)));
131+
} else {
132+
trees.push(TokenTree::Group(Group {
133+
delimiter: pm::Delimiter::from_internal(delim),
134+
stream: Some(stream),
135+
span: DelimSpan {
136+
open: span.open,
137+
close: span.close,
138+
entire: span.entire(),
139+
},
140+
}));
141+
}
127142
continue;
128143
}
129144
tokenstream::TokenTree::Token(token, spacing) => {
@@ -269,21 +284,11 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
269284

270285
Interpolated(nt) => {
271286
let stream = TokenStream::from_nonterminal_ast(&nt.0);
272-
// A hack used to pass AST fragments to attribute and derive
273-
// macros as a single nonterminal token instead of a token
274-
// stream. Such token needs to be "unwrapped" and not
275-
// represented as a delimited group.
276-
// FIXME: It needs to be removed, but there are some
277-
// compatibility issues (see #73345).
278-
if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
279-
trees.extend(Self::from_internal((stream, rustc)));
280-
} else {
281-
trees.push(TokenTree::Group(Group {
282-
delimiter: pm::Delimiter::None,
283-
stream: Some(stream),
284-
span: DelimSpan::from_single(span),
285-
}))
286-
}
287+
trees.push(TokenTree::Group(Group {
288+
delimiter: pm::Delimiter::None,
289+
stream: Some(stream),
290+
span: DelimSpan::from_single(span),
291+
}))
287292
}
288293

289294
// njn: covers invis-delim

compiler/rustc_parse/src/parser/item.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
22
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
33
use super::{
4-
AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing,
5-
TrailingToken,
4+
AttrWrapper, FollowedByType, ForceCollect, ParseNtResult, Parser, PathStyle, Recovered,
5+
Trailing, TrailingToken,
66
};
77
use crate::errors::{self, MacroExpandsToAdtField};
88
use crate::fluent_generated as fluent;
9-
use crate::maybe_whole;
9+
use crate::maybe_reparse_metavar_seq;
1010
use ast::token::IdentIsRaw;
1111
use rustc_ast::ast::*;
1212
use rustc_ast::ptr::P;
@@ -116,10 +116,16 @@ impl<'a> Parser<'a> {
116116
fn_parse_mode: FnParseMode,
117117
force_collect: ForceCollect,
118118
) -> PResult<'a, Option<Item>> {
119-
maybe_whole!(self, NtItem, |item| {
119+
if let Some(mut item) = maybe_reparse_metavar_seq!(
120+
self,
121+
NonterminalKind::Item,
122+
NonterminalKind::Item,
123+
ParseNtResult::Item(item),
124+
item
125+
) {
120126
attrs.prepend_to_nt_inner(&mut item.attrs);
121-
Some(item.into_inner())
122-
});
127+
return Ok(Some(item.into_inner()));
128+
}
123129

124130
let item =
125131
self.collect_tokens_trailing_token(attrs, force_collect, |this: &mut Self, attrs| {

0 commit comments

Comments
 (0)