@@ -3,7 +3,10 @@ use std::sync::Arc;
3
3
4
4
use rustc_ast:: ExprKind ;
5
5
use rustc_ast:: mut_visit:: { self , MutVisitor } ;
6
- use rustc_ast:: token:: { self , Delimiter , IdentIsRaw , Lit , LitKind , Nonterminal , Token , TokenKind } ;
6
+ use rustc_ast:: token:: {
7
+ self , Delimiter , IdentIsRaw , InvisibleOrigin , Lit , LitKind , MetaVarKind , Nonterminal , Token ,
8
+ TokenKind ,
9
+ } ;
7
10
use rustc_ast:: tokenstream:: { DelimSpacing , DelimSpan , Spacing , TokenStream , TokenTree } ;
8
11
use rustc_data_structures:: fx:: FxHashMap ;
9
12
use rustc_errors:: { Diag , DiagCtxtHandle , PResult , pluralize} ;
@@ -274,6 +277,33 @@ pub(super) fn transcribe<'a>(
274
277
// some of the unnecessary whitespace.
275
278
let ident = MacroRulesNormalizedIdent :: new ( original_ident) ;
276
279
if let Some ( cur_matched) = lookup_cur_matched ( ident, interp, & repeats) {
280
+ // We wrap the tokens in invisible delimiters, unless they are already wrapped
281
+ // in invisible delimiters with the same `MetaVarKind`. Because some proc
282
+ // macros can't multiple layers of invisible delimiters of the same
283
+ // `MetaVarKind`. This loses some span info, though it hopefully won't matter.
284
+ let mut mk_delimited = |mv_kind, mut stream : TokenStream | {
285
+ if stream. len ( ) == 1 {
286
+ let tree = stream. iter ( ) . next ( ) . unwrap ( ) ;
287
+ if let TokenTree :: Delimited ( _, _, delim, inner) = tree
288
+ && let Delimiter :: Invisible ( InvisibleOrigin :: MetaVar ( mvk) ) = delim
289
+ && mv_kind == * mvk
290
+ {
291
+ stream = inner. clone ( ) ;
292
+ }
293
+ }
294
+
295
+ // Emit as a token stream within `Delimiter::Invisible` to maintain
296
+ // parsing priorities.
297
+ marker. visit_span ( & mut sp) ;
298
+ // Both the open delim and close delim get the same span, which covers the
299
+ // `$foo` in the decl macro RHS.
300
+ TokenTree :: Delimited (
301
+ DelimSpan :: from_single ( sp) ,
302
+ DelimSpacing :: new ( Spacing :: Alone , Spacing :: Alone ) ,
303
+ Delimiter :: Invisible ( InvisibleOrigin :: MetaVar ( mv_kind) ) ,
304
+ stream,
305
+ )
306
+ } ;
277
307
let tt = match cur_matched {
278
308
MatchedSingle ( ParseNtResult :: Tt ( tt) ) => {
279
309
// `tt`s are emitted into the output stream directly as "raw tokens",
@@ -292,6 +322,9 @@ pub(super) fn transcribe<'a>(
292
322
let kind = token:: NtLifetime ( * ident, * is_raw) ;
293
323
TokenTree :: token_alone ( kind, sp)
294
324
}
325
+ MatchedSingle ( ParseNtResult :: Vis ( vis) ) => {
326
+ mk_delimited ( MetaVarKind :: Vis , TokenStream :: from_ast ( vis) )
327
+ }
295
328
MatchedSingle ( ParseNtResult :: Nt ( nt) ) => {
296
329
// Other variables are emitted into the output stream as groups with
297
330
// `Delimiter::Invisible` to maintain parsing priorities.
0 commit comments