Skip to content

Commit 2b5be0f

Browse files
authored
Rollup merge of rust-lang#73345 - petrochenkov:nointerp, r=Aaron1011
expand: Stop using nonterminals for passing tokens to attribute and derive macros Make one more step towards fully token-based expansion and fix issues described in rust-lang#72545 (comment). Now `struct S;` is passed to `foo!(struct S;)` and `#[foo] struct S;` in the same way - as a token stream `struct S ;`, rather than a single non-terminal token `NtItem` which is then broken into parts later. The cost is making pretty-printing of token streams less pretty. Some of the pretty-printing regressions will be recovered by keeping jointness with each token, which we will need to do anyway. Unfortunately, this is not exactly the same thing as rust-lang#73102. One more observable effect is how `$crate` is printed in the attribute input. Inside `NtItem` was printed as `crate` or `that_crate`, now as a part of a token stream it's printed as `$crate` (there are good reasons for these differences, see rust-lang#62393 and related PRs). This may break old proc macros (custom derives) written before the main portion of the proc macro API (macros 1.2) was stabilized, those macros did `input.to_string()` and reparsed the result, now that result can contain `$crate` which cannot be reparsed. So, I think we should do this regardless, but we need to run crater first. r? @Aaron1011
2 parents d7e8c0c + eb4ba55 commit 2b5be0f

39 files changed

+152
-144
lines changed

src/librustc_ast/attr/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,7 @@ impl MetaItem {
475475
let span = span.with_hi(segments.last().unwrap().ident.span.hi());
476476
Path { span, segments }
477477
}
478-
Some(TokenTree::Token(Token { kind: token::Interpolated(nt, _), .. })) => match *nt {
478+
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
479479
token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
480480
token::Nonterminal::NtPath(ref path) => path.clone(),
481481
_ => return None,

src/librustc_ast/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ pub fn noop_visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
656656
*span = ident.span;
657657
return; // Avoid visiting the span for the second time.
658658
}
659-
token::Interpolated(nt, _) => {
659+
token::Interpolated(nt) => {
660660
let mut nt = Lrc::make_mut(nt);
661661
vis.visit_interpolated(&mut nt);
662662
}

src/librustc_ast/token.rs

+31-20
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::tokenstream::TokenTree;
1111
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1212
use rustc_data_structures::sync::Lrc;
1313
use rustc_macros::HashStable_Generic;
14-
use rustc_span::symbol::kw;
14+
use rustc_span::symbol::{kw, sym};
1515
use rustc_span::symbol::{Ident, Symbol};
1616
use rustc_span::{self, Span, DUMMY_SP};
1717
use std::borrow::Cow;
@@ -182,15 +182,6 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: bool) -> bool {
182182
.contains(&name)
183183
}
184184

185-
/// A hack used to pass AST fragments to attribute and derive macros
186-
/// as a single nonterminal token instead of a token stream.
187-
/// FIXME: It needs to be removed, but there are some compatibility issues (see #73345).
188-
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
189-
pub enum FlattenGroup {
190-
Yes,
191-
No,
192-
}
193-
194185
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
195186
pub enum TokenKind {
196187
/* Expression-operator symbols. */
@@ -245,7 +236,7 @@ pub enum TokenKind {
245236
/// treat regular and interpolated lifetime identifiers in the same way.
246237
Lifetime(Symbol),
247238

248-
Interpolated(Lrc<Nonterminal>, FlattenGroup),
239+
Interpolated(Lrc<Nonterminal>),
249240

250241
// Can be expanded into several tokens.
251242
/// A doc comment.
@@ -352,7 +343,7 @@ impl Token {
352343
/// if they keep spans or perform edition checks.
353344
pub fn uninterpolated_span(&self) -> Span {
354345
match &self.kind {
355-
Interpolated(nt, _) => nt.span(),
346+
Interpolated(nt) => nt.span(),
356347
_ => self.span,
357348
}
358349
}
@@ -391,7 +382,7 @@ impl Token {
391382
ModSep | // global path
392383
Lifetime(..) | // labeled loop
393384
Pound => true, // expression attributes
394-
Interpolated(ref nt, _) => match **nt {
385+
Interpolated(ref nt) => match **nt {
395386
NtLiteral(..) |
396387
NtExpr(..) |
397388
NtBlock(..) |
@@ -417,7 +408,7 @@ impl Token {
417408
Lifetime(..) | // lifetime bound in trait object
418409
Lt | BinOp(Shl) | // associated path
419410
ModSep => true, // global path
420-
Interpolated(ref nt, _) => match **nt {
411+
Interpolated(ref nt) => match **nt {
421412
NtTy(..) | NtPath(..) => true,
422413
_ => false,
423414
},
@@ -429,7 +420,7 @@ impl Token {
429420
pub fn can_begin_const_arg(&self) -> bool {
430421
match self.kind {
431422
OpenDelim(Brace) => true,
432-
Interpolated(ref nt, _) => match **nt {
423+
Interpolated(ref nt) => match **nt {
433424
NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
434425
_ => false,
435426
},
@@ -464,7 +455,7 @@ impl Token {
464455
match self.uninterpolate().kind {
465456
Literal(..) | BinOp(Minus) => true,
466457
Ident(name, false) if name.is_bool_lit() => true,
467-
Interpolated(ref nt, _) => match &**nt {
458+
Interpolated(ref nt) => match &**nt {
468459
NtLiteral(_) => true,
469460
NtExpr(e) => match &e.kind {
470461
ast::ExprKind::Lit(_) => true,
@@ -485,7 +476,7 @@ impl Token {
485476
// otherwise returns the original token.
486477
pub fn uninterpolate(&self) -> Cow<'_, Token> {
487478
match &self.kind {
488-
Interpolated(nt, _) => match **nt {
479+
Interpolated(nt) => match **nt {
489480
NtIdent(ident, is_raw) => {
490481
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
491482
}
@@ -532,7 +523,7 @@ impl Token {
532523

533524
/// Returns `true` if the token is an interpolated path.
534525
fn is_path(&self) -> bool {
535-
if let Interpolated(ref nt, _) = self.kind {
526+
if let Interpolated(ref nt) = self.kind {
536527
if let NtPath(..) = **nt {
537528
return true;
538529
}
@@ -544,7 +535,7 @@ impl Token {
544535
/// That is, is this a pre-parsed expression dropped into the token stream
545536
/// (which happens while parsing the result of macro expansion)?
546537
pub fn is_whole_expr(&self) -> bool {
547-
if let Interpolated(ref nt, _) = self.kind {
538+
if let Interpolated(ref nt) = self.kind {
548539
if let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtIdent(..) | NtBlock(_) = **nt {
549540
return true;
550541
}
@@ -555,7 +546,7 @@ impl Token {
555546

556547
// Is the token an interpolated block (`$b:block`)?
557548
pub fn is_whole_block(&self) -> bool {
558-
if let Interpolated(ref nt, _) = self.kind {
549+
if let Interpolated(ref nt) = self.kind {
559550
if let NtBlock(..) = **nt {
560551
return true;
561552
}
@@ -785,6 +776,26 @@ impl Nonterminal {
785776
NtTT(tt) => tt.span(),
786777
}
787778
}
779+
780+
/// This nonterminal looks like some specific enums from
781+
/// `proc-macro-hack` and `procedural-masquerade` crates.
782+
/// We need to maintain some special pretty-printing behavior for them due to incorrect
783+
/// asserts in old versions of those crates and their wide use in the ecosystem.
784+
/// See issue #73345 for more details.
785+
/// FIXME(#73933): Remove this eventually.
786+
pub fn pretty_printing_compatibility_hack(&self) -> bool {
787+
if let NtItem(item) = self {
788+
let name = item.ident.name;
789+
if name == sym::ProceduralMasqueradeDummyType || name == sym::ProcMacroHack {
790+
if let ast::ItemKind::Enum(enum_def, _) = &item.kind {
791+
if let [variant] = &*enum_def.variants {
792+
return variant.ident.name == sym::Input;
793+
}
794+
}
795+
}
796+
}
797+
false
798+
}
788799
}
789800

790801
impl PartialEq for Nonterminal {

src/librustc_ast/util/literal.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ impl Lit {
205205
token::Lit::new(token::Bool, name, None)
206206
}
207207
token::Literal(lit) => lit,
208-
token::Interpolated(ref nt, _) => {
208+
token::Interpolated(ref nt) => {
209209
if let token::NtExpr(expr) | token::NtLiteral(expr) = &**nt {
210210
if let ast::ExprKind::Lit(lit) = &expr.kind {
211211
return Ok(lit.clone());

src/librustc_ast_lowering/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1027,7 +1027,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
10271027

10281028
fn lower_token(&mut self, token: Token) -> TokenStream {
10291029
match token.kind {
1030-
token::Interpolated(nt, _) => {
1030+
token::Interpolated(nt) => {
10311031
let tts = (self.nt_to_tokenstream)(&nt, &self.sess.parse_sess, token.span);
10321032
self.lower_token_stream(tts)
10331033
}

src/librustc_ast_pretty/pprust.rs

+16-4
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,14 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String {
148148
printer.s.eof()
149149
}
150150

151-
// This makes comma-separated lists look slightly nicer,
152-
// and also addresses a specific regression described in issue #63896.
151+
// This makes printed token streams look slightly nicer,
152+
// and also addresses some specific regressions described in #63896 and #73345.
153153
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
154+
if let TokenTree::Token(token) = prev {
155+
if let token::DocComment(s) = token.kind {
156+
return !s.as_str().starts_with("//");
157+
}
158+
}
154159
match tt {
155160
TokenTree::Token(token) => match token.kind {
156161
token::Comma => false,
@@ -163,7 +168,14 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
163168
},
164169
_ => true,
165170
},
166-
_ => true,
171+
TokenTree::Delimited(_, DelimToken::Bracket, _) => match prev {
172+
TokenTree::Token(token) => match token.kind {
173+
token::Pound => false,
174+
_ => true,
175+
},
176+
_ => true,
177+
},
178+
TokenTree::Delimited(..) => true,
167179
}
168180
}
169181

@@ -266,7 +278,7 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>)
266278
token::Shebang(s) => format!("/* shebang: {}*/", s),
267279
token::Unknown(s) => s.to_string(),
268280

269-
token::Interpolated(ref nt, _) => nonterminal_to_string(nt),
281+
token::Interpolated(ref nt) => nonterminal_to_string(nt),
270282
}
271283
}
272284

src/librustc_expand/base.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ use crate::module::DirectoryOwnership;
44
use rustc_ast::ast::{self, Attribute, NodeId, PatKind};
55
use rustc_ast::mut_visit::{self, MutVisitor};
66
use rustc_ast::ptr::P;
7-
use rustc_ast::token::{self, FlattenGroup};
8-
use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
7+
use rustc_ast::token;
8+
use rustc_ast::tokenstream::{self, TokenStream};
99
use rustc_ast::visit::{AssocCtxt, Visitor};
1010
use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability};
1111
use rustc_data_structures::fx::FxHashMap;
1212
use rustc_data_structures::sync::{self, Lrc};
1313
use rustc_errors::{DiagnosticBuilder, ErrorReported};
14-
use rustc_parse::{self, parser, MACRO_ARGUMENTS};
14+
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
1515
use rustc_session::{parse::ParseSess, Limit};
1616
use rustc_span::def_id::DefId;
1717
use rustc_span::edition::Edition;
@@ -120,10 +120,7 @@ impl Annotatable {
120120
}
121121
}
122122

123-
crate fn into_tokens(self) -> TokenStream {
124-
// `Annotatable` can be converted into tokens directly, but we
125-
// are packing it into a nonterminal as a piece of AST to make
126-
// the produced token stream look nicer in pretty-printed form.
123+
crate fn into_tokens(self, sess: &ParseSess) -> TokenStream {
127124
let nt = match self {
128125
Annotatable::Item(item) => token::NtItem(item),
129126
Annotatable::TraitItem(item) | Annotatable::ImplItem(item) => {
@@ -142,7 +139,7 @@ impl Annotatable {
142139
| Annotatable::StructField(..)
143140
| Annotatable::Variant(..) => panic!("unexpected annotatable"),
144141
};
145-
TokenTree::token(token::Interpolated(Lrc::new(nt), FlattenGroup::Yes), DUMMY_SP).into()
142+
nt_to_tokenstream(&nt, sess, DUMMY_SP)
146143
}
147144

148145
pub fn expect_item(self) -> P<ast::Item> {
@@ -374,7 +371,7 @@ where
374371
impl MutVisitor for AvoidInterpolatedIdents {
375372
fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) {
376373
if let tokenstream::TokenTree::Token(token) = tt {
377-
if let token::Interpolated(nt, _) = &token.kind {
374+
if let token::Interpolated(nt) = &token.kind {
378375
if let token::NtIdent(ident, is_raw) = **nt {
379376
*tt = tokenstream::TokenTree::token(
380377
token::Ident(ident.name, is_raw),

src/librustc_expand/expand.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
705705
SyntaxExtensionKind::Attr(expander) => {
706706
self.gate_proc_macro_input(&item);
707707
self.gate_proc_macro_attr_item(span, &item);
708-
let tokens = item.into_tokens();
708+
let tokens = item.into_tokens(self.cx.parse_sess);
709709
let attr_item = attr.unwrap_normal_item();
710710
if let MacArgs::Eq(..) = attr_item.args {
711711
self.cx.span_err(span, "key-value macro attributes are not supported");

src/librustc_expand/mbe/macro_parser.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,7 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool {
790790
},
791791
sym::block => match token.kind {
792792
token::OpenDelim(token::Brace) => true,
793-
token::Interpolated(ref nt, _) => match **nt {
793+
token::Interpolated(ref nt) => match **nt {
794794
token::NtItem(_)
795795
| token::NtPat(_)
796796
| token::NtTy(_)
@@ -804,7 +804,7 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool {
804804
},
805805
sym::path | sym::meta => match token.kind {
806806
token::ModSep | token::Ident(..) => true,
807-
token::Interpolated(ref nt, _) => match **nt {
807+
token::Interpolated(ref nt) => match **nt {
808808
token::NtPath(_) | token::NtMeta(_) => true,
809809
_ => may_be_ident(&nt),
810810
},
@@ -823,12 +823,12 @@ fn may_begin_with(token: &Token, name: Symbol) -> bool {
823823
token::ModSep | // path
824824
token::Lt | // path (UFCS constant)
825825
token::BinOp(token::Shl) => true, // path (double UFCS)
826-
token::Interpolated(ref nt, _) => may_be_ident(nt),
826+
token::Interpolated(ref nt) => may_be_ident(nt),
827827
_ => false,
828828
},
829829
sym::lifetime => match token.kind {
830830
token::Lifetime(_) => true,
831-
token::Interpolated(ref nt, _) => match **nt {
831+
token::Interpolated(ref nt) => match **nt {
832832
token::NtLifetime(_) | token::NtTT(_) => true,
833833
_ => false,
834834
},

src/librustc_expand/mbe/transcribe.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch};
44

55
use rustc_ast::ast::MacCall;
66
use rustc_ast::mut_visit::{self, MutVisitor};
7-
use rustc_ast::token::{self, FlattenGroup, NtTT, Token};
7+
use rustc_ast::token::{self, NtTT, Token};
88
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
99
use rustc_data_structures::fx::FxHashMap;
1010
use rustc_data_structures::sync::Lrc;
@@ -240,10 +240,7 @@ pub(super) fn transcribe<'a>(
240240
result.push(tt.clone().into());
241241
} else {
242242
marker.visit_span(&mut sp);
243-
let token = TokenTree::token(
244-
token::Interpolated(nt.clone(), FlattenGroup::No),
245-
sp,
246-
);
243+
let token = TokenTree::token(token::Interpolated(nt.clone()), sp);
247244
result.push(token.into());
248245
}
249246
} else {

src/librustc_expand/proc_macro.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ use crate::base::{self, *};
22
use crate::proc_macro_server;
33

44
use rustc_ast::ast::{self, ItemKind, MetaItemKind, NestedMetaItem};
5-
use rustc_ast::token::{self, FlattenGroup};
6-
use rustc_ast::tokenstream::{self, TokenStream};
5+
use rustc_ast::token;
6+
use rustc_ast::tokenstream::{TokenStream, TokenTree};
77
use rustc_data_structures::sync::Lrc;
88
use rustc_errors::{Applicability, ErrorReported};
9+
use rustc_parse::nt_to_tokenstream;
910
use rustc_span::symbol::sym;
1011
use rustc_span::{Span, DUMMY_SP};
1112

@@ -102,8 +103,12 @@ impl MultiItemModifier for ProcMacroDerive {
102103
}
103104
}
104105

105-
let token = token::Interpolated(Lrc::new(token::NtItem(item)), FlattenGroup::Yes);
106-
let input = tokenstream::TokenTree::token(token, DUMMY_SP).into();
106+
let item = token::NtItem(item);
107+
let input = if item.pretty_printing_compatibility_hack() {
108+
TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
109+
} else {
110+
nt_to_tokenstream(&item, ecx.parse_sess, DUMMY_SP)
111+
};
107112

108113
let server = proc_macro_server::Rustc::new(ecx);
109114
let stream = match self.client.run(&EXEC_STRATEGY, server, input) {

0 commit comments

Comments
 (0)