Skip to content

Commit cd24aee

Browse files
committed
Recursively expand TokenKind::Interpolated (take 2)
Fixes rust-lang#68430 This is a re-attempt of PR rust-lang#72388, which was previously reverted due to a large number of breakages. All of the known breakages should now be patched upstream.
1 parent 527a685 commit cd24aee

File tree

7 files changed

+152
-75
lines changed

7 files changed

+152
-75
lines changed

src/librustc_parse/lib.rs

+40-13
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
#![feature(or_patterns)]
88

99
use rustc_ast as ast;
10-
use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
11-
use rustc_ast::tokenstream::{self, TokenStream, TokenTree};
10+
use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind};
11+
use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree};
1212
use rustc_ast_pretty::pprust;
1313
use rustc_data_structures::sync::Lrc;
1414
use rustc_errors::{Diagnostic, FatalError, Level, PResult};
@@ -309,7 +309,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
309309
// modifications, including adding/removing typically non-semantic
310310
// tokens such as extra braces and commas, don't happen.
311311
if let Some(tokens) = tokens {
312-
if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real) {
312+
if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) {
313313
return tokens;
314314
}
315315
info!(
@@ -327,7 +327,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke
327327
//
328328
// This is otherwise the same as `eq_unspanned`, only recursing with a
329329
// different method.
330-
pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &TokenStream) -> bool {
330+
pub fn tokenstream_probably_equal_for_proc_macro(
331+
first: &TokenStream,
332+
other: &TokenStream,
333+
sess: &ParseSess,
334+
) -> bool {
331335
// When checking for `probably_eq`, we ignore certain tokens that aren't
332336
// preserved in the AST. Because they are not preserved, the pretty
333337
// printer arbitrarily adds or removes them when printing as token
@@ -408,20 +412,39 @@ pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &To
408412
}
409413
}
410414
token_trees = out.into_iter().map(TokenTree::Token).collect();
411-
if token_trees.len() != 1 {
412-
debug!("break_tokens: broke {:?} to {:?}", tree, token_trees);
413-
}
414415
} else {
415416
token_trees = SmallVec::new();
416417
token_trees.push(tree);
417418
}
418419
token_trees.into_iter()
419420
}
420421

421-
let mut t1 = first.trees().filter(semantic_tree).flat_map(break_tokens);
422-
let mut t2 = other.trees().filter(semantic_tree).flat_map(break_tokens);
422+
let expand_nt = |tree: TokenTree| {
423+
if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree {
424+
// When checking tokenstreams for 'probable equality', we are comparing
425+
// a captured (from parsing) `TokenStream` to a reparsed tokenstream.
426+
// The reparsed Tokenstream will never have `None`-delimited groups,
427+
// since they are only ever inserted as a result of macro expansion.
428+
// Therefore, inserting a `None`-delimtied group here (when we
429+
// convert a nested `Nonterminal` to a tokenstream) would cause
430+
// a mismatch with the reparsed tokenstream.
431+
//
432+
// Note that we currently do not handle the case where the
433+
// reparsed stream has a `Parenthesis`-delimited group
434+
// inserted. This will cause a spurious mismatch:
435+
// issue #75734 tracks resolving this.
436+
nt_to_tokenstream(nt, sess, *span).into_trees()
437+
} else {
438+
TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees()
439+
}
440+
};
441+
442+
// Break tokens after we expand any nonterminals, so that we break tokens
443+
// that are produced as a result of nonterminal expansion.
444+
let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
445+
let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens);
423446
for (t1, t2) in t1.by_ref().zip(t2.by_ref()) {
424-
if !tokentree_probably_equal_for_proc_macro(&t1, &t2) {
447+
if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) {
425448
return false;
426449
}
427450
}
@@ -433,13 +456,17 @@ pub fn tokenstream_probably_equal_for_proc_macro(first: &TokenStream, other: &To
433456
//
434457
// This is otherwise the same as `eq_unspanned`, only recursing with a
435458
// different method.
436-
fn tokentree_probably_equal_for_proc_macro(first: &TokenTree, other: &TokenTree) -> bool {
459+
pub fn tokentree_probably_equal_for_proc_macro(
460+
first: &TokenTree,
461+
other: &TokenTree,
462+
sess: &ParseSess,
463+
) -> bool {
437464
match (first, other) {
438465
(TokenTree::Token(token), TokenTree::Token(token2)) => {
439466
token_probably_equal_for_proc_macro(token, token2)
440467
}
441468
(TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => {
442-
delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2)
469+
delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess)
443470
}
444471
_ => false,
445472
}
@@ -498,7 +525,7 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool {
498525
b == d && (a == c || a == kw::DollarCrate || c == kw::DollarCrate)
499526
}
500527

501-
(&Interpolated(..), &Interpolated(..)) => false,
528+
(&Interpolated(..), &Interpolated(..)) => panic!("Unexpanded Interpolated!"),
502529

503530
_ => panic!("forgot to add a token?"),
504531
}

src/test/ui/proc-macro/input-interpolated.stdout

+26-14
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,63 @@ PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ;
1515
PRINT-ATTR INPUT (DEBUG): TokenStream [
1616
Ident {
1717
ident: "const",
18-
span: #0 bytes(0..0),
18+
span: #3 bytes(416..421),
1919
},
20-
Ident {
21-
ident: "A",
22-
span: #0 bytes(0..0),
20+
Group {
21+
delimiter: None,
22+
stream: TokenStream [
23+
Ident {
24+
ident: "A",
25+
span: #0 bytes(503..504),
26+
},
27+
],
28+
span: #3 bytes(422..424),
2329
},
2430
Punct {
2531
ch: ':',
2632
spacing: Alone,
27-
span: #0 bytes(0..0),
33+
span: #3 bytes(424..425),
2834
},
2935
Ident {
3036
ident: "u8",
31-
span: #0 bytes(0..0),
37+
span: #3 bytes(426..428),
3238
},
3339
Punct {
3440
ch: '=',
3541
spacing: Alone,
36-
span: #0 bytes(0..0),
42+
span: #3 bytes(429..430),
3743
},
3844
Literal {
3945
kind: Integer,
4046
symbol: "0",
4147
suffix: None,
42-
span: #0 bytes(0..0),
48+
span: #3 bytes(431..432),
4349
},
4450
Punct {
4551
ch: ';',
4652
spacing: Alone,
47-
span: #0 bytes(0..0),
53+
span: #3 bytes(432..433),
4854
},
4955
]
5056
PRINT-DERIVE INPUT (DISPLAY): struct A { }
5157
PRINT-DERIVE INPUT (DEBUG): TokenStream [
5258
Ident {
5359
ident: "struct",
54-
span: #0 bytes(0..0),
60+
span: #3 bytes(468..474),
5561
},
56-
Ident {
57-
ident: "A",
58-
span: #0 bytes(0..0),
62+
Group {
63+
delimiter: None,
64+
stream: TokenStream [
65+
Ident {
66+
ident: "A",
67+
span: #0 bytes(503..504),
68+
},
69+
],
70+
span: #3 bytes(475..477),
5971
},
6072
Group {
6173
delimiter: Brace,
6274
stream: TokenStream [],
63-
span: #0 bytes(0..0),
75+
span: #3 bytes(478..480),
6476
},
6577
]

src/test/ui/proc-macro/macro-rules-derive.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
// aux-build:first-second.rs
2-
// FIXME: The spans here are bad, see PR #73084
32

43
extern crate first_second;
54
use first_second::*;
65

76
macro_rules! produce_it {
87
($name:ident) => {
9-
#[first] //~ ERROR cannot find type
8+
#[first]
109
struct $name {
11-
field: MissingType
10+
field: MissingType //~ ERROR cannot find type
1211
}
1312
}
1413
}

src/test/ui/proc-macro/macro-rules-derive.stderr

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
error[E0412]: cannot find type `MissingType` in this scope
2-
--> $DIR/macro-rules-derive.rs:9:9
2+
--> $DIR/macro-rules-derive.rs:10:20
33
|
4-
LL | #[first]
5-
| ^^^^^^^^ not found in this scope
4+
LL | field: MissingType
5+
| ^^^^^^^^^^^ not found in this scope
6+
...
7+
LL | produce_it!(MyName);
8+
| -------------------- in this macro invocation
9+
|
10+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
611

712
error: aborting due to previous error
813

src/test/ui/proc-macro/nodelim-groups.stdout

+49-38
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
7171
},
7272
]
7373
PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
74-
PRINT-BANG RE-COLLECTED (DISPLAY): "hi" "hello" . len() + "world" . len() (1 + 1)
7574
PRINT-BANG INPUT (DEBUG): TokenStream [
7675
Literal {
7776
kind: Str,
@@ -82,50 +81,62 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
8281
Group {
8382
delimiter: None,
8483
stream: TokenStream [
85-
Literal {
86-
kind: Str,
87-
symbol: "hello",
88-
suffix: None,
89-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
90-
},
91-
Punct {
92-
ch: '.',
93-
spacing: Alone,
94-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
95-
},
96-
Ident {
97-
ident: "len",
98-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
99-
},
10084
Group {
101-
delimiter: Parenthesis,
102-
stream: TokenStream [],
103-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
85+
delimiter: None,
86+
stream: TokenStream [
87+
Literal {
88+
kind: Str,
89+
symbol: "hello",
90+
suffix: None,
91+
span: $DIR/nodelim-groups.rs:21:17: 21:24 (#0),
92+
},
93+
Punct {
94+
ch: '.',
95+
spacing: Alone,
96+
span: $DIR/nodelim-groups.rs:21:24: 21:25 (#0),
97+
},
98+
Ident {
99+
ident: "len",
100+
span: $DIR/nodelim-groups.rs:21:25: 21:28 (#0),
101+
},
102+
Group {
103+
delimiter: Parenthesis,
104+
stream: TokenStream [],
105+
span: $DIR/nodelim-groups.rs:21:28: 21:30 (#0),
106+
},
107+
],
108+
span: $DIR/nodelim-groups.rs:15:49: 15:54 (#7),
104109
},
105110
Punct {
106111
ch: '+',
107112
spacing: Alone,
108-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
109-
},
110-
Literal {
111-
kind: Str,
112-
symbol: "world",
113-
suffix: None,
114-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
115-
},
116-
Punct {
117-
ch: '.',
118-
spacing: Alone,
119-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
120-
},
121-
Ident {
122-
ident: "len",
123-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
113+
span: $DIR/nodelim-groups.rs:15:55: 15:56 (#7),
124114
},
125115
Group {
126-
delimiter: Parenthesis,
127-
stream: TokenStream [],
128-
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
116+
delimiter: None,
117+
stream: TokenStream [
118+
Literal {
119+
kind: Str,
120+
symbol: "world",
121+
suffix: None,
122+
span: $DIR/nodelim-groups.rs:21:33: 21:40 (#0),
123+
},
124+
Punct {
125+
ch: '.',
126+
spacing: Alone,
127+
span: $DIR/nodelim-groups.rs:21:40: 21:41 (#0),
128+
},
129+
Ident {
130+
ident: "len",
131+
span: $DIR/nodelim-groups.rs:21:41: 21:44 (#0),
132+
},
133+
Group {
134+
delimiter: Parenthesis,
135+
stream: TokenStream [],
136+
span: $DIR/nodelim-groups.rs:21:44: 21:46 (#0),
137+
},
138+
],
139+
span: $DIR/nodelim-groups.rs:15:57: 15:62 (#7),
129140
},
130141
],
131142
span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),

src/test/ui/proc-macro/weird-hygiene.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
// aux-build:weird-hygiene.rs
2-
// check-pass
3-
// FIXME: This should actually error, see PR #73084
42

53
#![feature(stmt_expr_attributes)]
64
#![feature(proc_macro_hygiene)]
@@ -22,7 +20,7 @@ macro_rules! other {
2220

2321
#[derive(WeirdDerive)]
2422
enum MyEnum {
25-
Value = (stringify!($tokens + hidden_ident), 1).1
23+
Value = (stringify!($tokens + hidden_ident), 1).1 //~ ERROR cannot find
2624
}
2725

2826
inner!();
@@ -33,7 +31,7 @@ macro_rules! invoke_it {
3331
($token:expr) => {
3432
#[recollect_attr] {
3533
$token;
36-
hidden_ident
34+
hidden_ident //~ ERROR cannot find
3735
}
3836
}
3937
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
error[E0425]: cannot find value `hidden_ident` in this scope
2+
--> $DIR/weird-hygiene.rs:23:43
3+
|
4+
LL | Value = (stringify!($tokens + hidden_ident), 1).1
5+
| ^^^^^^^^^^^^ not found in this scope
6+
...
7+
LL | other!(50);
8+
| ----------- in this macro invocation
9+
|
10+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
11+
12+
error[E0425]: cannot find value `hidden_ident` in this scope
13+
--> $DIR/weird-hygiene.rs:34:13
14+
|
15+
LL | hidden_ident
16+
| ^^^^^^^^^^^^ not found in this scope
17+
...
18+
LL | invoke_it!(25);
19+
| --------------- in this macro invocation
20+
|
21+
= note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
22+
23+
error: aborting due to 2 previous errors
24+
25+
For more information about this error, try `rustc --explain E0425`.

0 commit comments

Comments
 (0)