about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs20
-rw-r--r--tests/ui/proc-macro/nodelim-groups.rs13
-rw-r--r--tests/ui/proc-macro/nodelim-groups.stdout15
3 files changed, 47 insertions, 1 deletions
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 7e5e02fd41b..e0269eb6903 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -115,7 +115,7 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
 
         while let Some(tree) = iter.next() {
             let (Token { kind, span }, joint) = match tree.clone() {
-                tokenstream::TokenTree::Delimited(span, _, delim, stream) => {
+                tokenstream::TokenTree::Delimited(span, _, mut delim, mut stream) => {
                     // 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
@@ -131,6 +131,24 @@ impl FromInternal<(TokenStream, &mut Rustc<'_, '_>)> for Vec<TokenTree<TokenStre
                             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 {
                         delimiter: pm::Delimiter::from_internal(delim),
                         stream: Some(stream),
diff --git a/tests/ui/proc-macro/nodelim-groups.rs b/tests/ui/proc-macro/nodelim-groups.rs
index 9acdc7023c0..8b0324214b9 100644
--- a/tests/ui/proc-macro/nodelim-groups.rs
+++ b/tests/ui/proc-macro/nodelim-groups.rs
@@ -19,4 +19,17 @@ macro_rules! expand_it {
 fn main() {
     expand_it!(1 + (25) + 1);
     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);
 }
diff --git a/tests/ui/proc-macro/nodelim-groups.stdout b/tests/ui/proc-macro/nodelim-groups.stdout
index cdf851b535a..61001035c26 100644
--- a/tests/ui/proc-macro/nodelim-groups.stdout
+++ b/tests/ui/proc-macro/nodelim-groups.stdout
@@ -165,3 +165,18 @@ PRINT-BANG INPUT (DEBUG): TokenStream [
         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),
+    },
+]