Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile error mixing declarative macros with procedural macros #82784

Open
incidental-complexity opened this issue Mar 4, 2021 · 4 comments
Open
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug.

Comments

@incidental-complexity
Copy link

incidental-complexity commented Mar 4, 2021

Cross posting with tokio issue tracker.

I know how to work around this (can put parens around the macro variable: ($foo_factory)()), but I don't think this should be happening in the first place. Feels like a bug in the macro system. This is reproducible in the playground:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fb6d73cfb878547b438d8ec49431a4d2

concrete_tests2 and concrete_tests3 compile whereas concrete_tests1 does not.

I'm producing a declarative macro that takes in an expr that is meant to be a closure, and produces a #[tokio::test] that invokes that closure. The compile error is:

error[E0618]: expected function, found `Concrete`
  --> src/lib.rs:38:32
   |
14 |             $crate::test_suite::async_test($foo_factory()).await;
   |                                                        -- call expression requires function
...
38 |     crate::use_test_suite!( || crate::Concrete::default() );
   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

The code (from the playground link above) is:

// /////////////////////////
// Define a trait Foo 
// /////////////////////////
pub trait Foo{}

// /////////////////////////
// Define a test suite suitable for any implementator of Foo
// /////////////////////////
#[macro_export]
macro_rules! use_test_suite {
    ($foo_factory:expr) => {
        #[tokio::test]
        async fn async_test() {
            $crate::test_suite::async_test($foo_factory()).await;
        }
            
        #[test]
        fn sync_test() {
            $crate::test_suite::sync_test($foo_factory());
        }
    }
}

pub mod test_suite {
    pub async fn async_test(_foo: impl crate::Foo) -> u8 { 0 }
    pub fn sync_test(_foo: impl crate::Foo) -> u8 { 0 }
}

// /////////////////////////
// Define an implementaion of Foo and test it
// /////////////////////////
#[derive(Default)]
struct Concrete;
impl Foo for Concrete {}

#[cfg(test)]
mod concrete_tests1 {
    crate::use_test_suite!( || crate::Concrete::default() );
}

#[cfg(test)]
mod concrete_tests2 {
    crate::use_test_suite!( (|| crate::Concrete::default()) );
}

#[cfg(test)]
mod concrete_tests3 {
    crate::use_test_suite!( crate::Concrete::default );
}
@taiki-e
Copy link
Member

taiki-e commented May 6, 2021

Looks like this is a regression introduced in 1.49.0 (probably #77135, cc @Aaron1011).

Code

# Cargo.toml
[package]
name = "repro"
version = "0.1.0"
authors = []
edition = "2018"

[dependencies]
# The `macro-debug' branch contains a patch that prints the input and output of `tokio::main`:
# https://github.com/taiki-e/tokio/commit/13bdbe4b15183887b4382382dc7a6295155e533e
tokio = { version = "1", features = ["full"], git = "https://github.com/taiki-e/tokio.git", branch = "macro-debug" }
// src/main.rs
fn main() {
    macro_rules! mac {
        ($e:expr) => {
            #[tokio::main]
            async fn f() -> i32 {
                $e(())
            }
        };
    }
    mac!(|_| 5);
}

cargo +1.48.0 build

Compile passed because closure wrapped with parentheses (#75734).

            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Literal {
                        kind: Integer,
                        symbol: "5",
                        suffix: None,
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },

(I've confirmed that it works with all versions of 1.45 (tokio's MSRV) to 1.48.)

full input tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:181] &input = TokenStream [
    Ident {
        ident: "async",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "fn",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "f",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #0 bytes(0..0),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #0 bytes(0..0),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "i32",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(0..0),
                    },
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(0..0),
                    },
                    Literal {
                        kind: Integer,
                        symbol: "5",
                        suffix: None,
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Group {
                        delimiter: Parenthesis,
                        stream: TokenStream [],
                        span: #0 bytes(0..0),
                    },
                ],
                span: #0 bytes(0..0),
            },
        ],
        span: #0 bytes(0..0),
    },
]

full output tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:183] &out = TokenStream [
    Ident {
        ident: "fn",
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "f",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #0 bytes(0..0),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #0 bytes(0..0),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #0 bytes(0..0),
    },
    Ident {
        ident: "i32",
        span: #0 bytes(0..0),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Ident {
                ident: "tokio",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "runtime",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "Builder",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "new_multi_thread",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "enable_all",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "build",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "unwrap",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "block_on",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Ident {
                        ident: "async",
                        span: #8 bytes(70..84),
                    },
                    Group {
                        delimiter: Brace,
                        stream: TokenStream [
                            Group {
                                delimiter: Parenthesis,
                                stream: TokenStream [
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(0..0),
                                    },
                                    Ident {
                                        ident: "_",
                                        span: #0 bytes(0..0),
                                    },
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(0..0),
                                    },
                                    Literal {
                                        kind: Integer,
                                        symbol: "5",
                                        suffix: None,
                                        span: #0 bytes(0..0),
                                    },
                                ],
                                span: #0 bytes(0..0),
                            },
                            Group {
                                delimiter: Parenthesis,
                                stream: TokenStream [
                                    Group {
                                        delimiter: Parenthesis,
                                        stream: TokenStream [],
                                        span: #0 bytes(0..0),
                                    },
                                ],
                                span: #0 bytes(0..0),
                            },
                        ],
                        span: #0 bytes(0..0),
                    },
                ],
                span: #8 bytes(70..84),
            },
        ],
        span: #8 bytes(70..84),
    },
]

cargo +1.49.0 build

The closure is wrapped with a none-delimited group instead of parentheses.

            Group {
                delimiter: None,
                stream: TokenStream [
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(182..183),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(183..184),
                    },
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(184..185),
                    },
                    Literal {
                        kind: Integer,
                        symbol: "5",
                        suffix: None,
                        span: #0 bytes(186..187),
                    },
                ],
                span: #6 bytes(135..137),
            },

and output from macro seems to preserve the none-delimited group and its span.

                            Group {
                                delimiter: None,
                                stream: TokenStream [
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(182..183),
                                    },
                                    Ident {
                                        ident: "_",
                                        span: #0 bytes(183..184),
                                    },
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(184..185),
                                    },
                                    Literal {
                                        kind: Integer,
                                        symbol: "5",
                                        suffix: None,
                                        span: #0 bytes(186..187),
                                    },
                                ],
                                span: #6 bytes(135..137),
                            },

but its precedence is not preserved and causes compile error.

error[E0618]: expected function, found `{integer}`
  --> src/main.rs:10:14
   |
6  |                 $e(())
   |                   ---- call expression requires function
...
10 |     mac!(|_| 5);
   |              ^

error: aborting due to previous error
full input tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:181] &input = TokenStream [
    Ident {
        ident: "async",
        span: #6 bytes(97..102),
    },
    Ident {
        ident: "fn",
        span: #6 bytes(103..105),
    },
    Ident {
        ident: "f",
        span: #6 bytes(106..107),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #6 bytes(107..109),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #6 bytes(110..112),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #6 bytes(110..112),
    },
    Ident {
        ident: "i32",
        span: #6 bytes(113..116),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Group {
                delimiter: None,
                stream: TokenStream [
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(182..183),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(183..184),
                    },
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(184..185),
                    },
                    Literal {
                        kind: Integer,
                        symbol: "5",
                        suffix: None,
                        span: #0 bytes(186..187),
                    },
                ],
                span: #6 bytes(135..137),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Group {
                        delimiter: Parenthesis,
                        stream: TokenStream [],
                        span: #6 bytes(138..140),
                    },
                ],
                span: #6 bytes(137..141),
            },
        ],
        span: #6 bytes(117..155),
    },
]
full output tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:183] &out = TokenStream [
    Ident {
        ident: "fn",
        span: #6 bytes(103..105),
    },
    Ident {
        ident: "f",
        span: #6 bytes(106..107),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #6 bytes(107..109),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #6 bytes(110..112),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #6 bytes(110..112),
    },
    Ident {
        ident: "i32",
        span: #6 bytes(113..116),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Ident {
                ident: "tokio",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "runtime",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "Builder",
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #8 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "new_multi_thread",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "enable_all",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "build",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "unwrap",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #8 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #8 bytes(70..84),
            },
            Ident {
                ident: "block_on",
                span: #8 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Ident {
                        ident: "async",
                        span: #8 bytes(70..84),
                    },
                    Group {
                        delimiter: Brace,
                        stream: TokenStream [
                            Group {
                                delimiter: None,
                                stream: TokenStream [
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(182..183),
                                    },
                                    Ident {
                                        ident: "_",
                                        span: #0 bytes(183..184),
                                    },
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(184..185),
                                    },
                                    Literal {
                                        kind: Integer,
                                        symbol: "5",
                                        suffix: None,
                                        span: #0 bytes(186..187),
                                    },
                                ],
                                span: #6 bytes(135..137),
                            },
                            Group {
                                delimiter: Parenthesis,
                                stream: TokenStream [
                                    Group {
                                        delimiter: Parenthesis,
                                        stream: TokenStream [],
                                        span: #6 bytes(138..140),
                                    },
                                ],
                                span: #6 bytes(137..141),
                            },
                        ],
                        span: #6 bytes(117..155),
                    },
                ],
                span: #8 bytes(70..84),
            },
        ],
        span: #8 bytes(70..84),
    },
]

cargo +nightly build

rustc -V: rustc 1.54.0-nightly (bacf770f2 2021-05-05)

Both input and output are the almost same as 1.49.0. And there is the same error.

error[E0618]: expected function, found `{integer}`
  --> src/main.rs:10:14
   |
6  |                 $e(())
   |                   ---- call expression requires function
...
10 |     mac!(|_| 5);
   |              ^

error: aborting due to previous error
full input tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:181] &input = TokenStream [
    Ident {
        ident: "async",
        span: #3 bytes(97..102),
    },
    Ident {
        ident: "fn",
        span: #3 bytes(103..105),
    },
    Ident {
        ident: "f",
        span: #3 bytes(106..107),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #3 bytes(107..109),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #3 bytes(110..112),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #3 bytes(110..112),
    },
    Ident {
        ident: "i32",
        span: #3 bytes(113..116),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Group {
                delimiter: None,
                stream: TokenStream [
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(182..183),
                    },
                    Ident {
                        ident: "_",
                        span: #0 bytes(183..184),
                    },
                    Punct {
                        ch: '|',
                        spacing: Alone,
                        span: #0 bytes(184..185),
                    },
                    Literal {
                        kind: Integer,
                        symbol: "5",
                        suffix: None,
                        span: #0 bytes(186..187),
                    },
                ],
                span: #3 bytes(135..137),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Group {
                        delimiter: Parenthesis,
                        stream: TokenStream [],
                        span: #3 bytes(138..140),
                    },
                ],
                span: #3 bytes(137..141),
            },
        ],
        span: #3 bytes(117..155),
    },
]
full output tokens
[/Users/taiki/.cargo/git/checkouts/tokio-7eef92cc7b2e8568/13bdbe4/tokio-macros/src/lib.rs:183] &out = TokenStream [
    Ident {
        ident: "fn",
        span: #3 bytes(103..105),
    },
    Ident {
        ident: "f",
        span: #3 bytes(106..107),
    },
    Group {
        delimiter: Parenthesis,
        stream: TokenStream [],
        span: #3 bytes(107..109),
    },
    Punct {
        ch: '-',
        spacing: Joint,
        span: #3 bytes(110..112),
    },
    Punct {
        ch: '>',
        spacing: Alone,
        span: #3 bytes(110..112),
    },
    Ident {
        ident: "i32",
        span: #3 bytes(113..116),
    },
    Group {
        delimiter: Brace,
        stream: TokenStream [
            Ident {
                ident: "tokio",
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "runtime",
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "Builder",
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Joint,
                span: #5 bytes(70..84),
            },
            Punct {
                ch: ':',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "new_multi_thread",
                span: #5 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #5 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "enable_all",
                span: #5 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #5 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "build",
                span: #5 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #5 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "unwrap",
                span: #5 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [],
                span: #5 bytes(70..84),
            },
            Punct {
                ch: '.',
                spacing: Alone,
                span: #5 bytes(70..84),
            },
            Ident {
                ident: "block_on",
                span: #5 bytes(70..84),
            },
            Group {
                delimiter: Parenthesis,
                stream: TokenStream [
                    Ident {
                        ident: "async",
                        span: #5 bytes(70..84),
                    },
                    Group {
                        delimiter: Brace,
                        stream: TokenStream [
                            Group {
                                delimiter: None,
                                stream: TokenStream [
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(182..183),
                                    },
                                    Ident {
                                        ident: "_",
                                        span: #0 bytes(183..184),
                                    },
                                    Punct {
                                        ch: '|',
                                        spacing: Alone,
                                        span: #0 bytes(184..185),
                                    },
                                    Literal {
                                        kind: Integer,
                                        symbol: "5",
                                        suffix: None,
                                        span: #0 bytes(186..187),
                                    },
                                ],
                                span: #3 bytes(135..137),
                            },
                            Group {
                                delimiter: Parenthesis,
                                stream: TokenStream [
                                    Group {
                                        delimiter: Parenthesis,
                                        stream: TokenStream [],
                                        span: #3 bytes(138..140),
                                    },
                                ],
                                span: #3 bytes(137..141),
                            },
                        ],
                        span: #3 bytes(117..155),
                    },
                ],
                span: #5 bytes(70..84),
            },
        ],
        span: #5 bytes(70..84),
    },
]

Known workaround

tokio-rs/tokio#3583 (However, it doesn't seem to work on ~1.46 EDIT: It seems to fail with or without a workaround, on ~1.46.)

@Aaron1011
Copy link
Member

This is caused by the fact that we do not parse None-delimited groups correctly. The parser currently ignores None delimiters in the token stream, so it will parse the input as |_| 5 (), which is interpreted as trying to call 5. See #67062.

For now, this can be worked around by inserting extra parenthesis into the macro body - for example: ($e)(()) instead of $e(()).

@Aaron1011
Copy link
Member

As a side note - #77135 is only tangentially related to this. The root cause of this issue is the fact that we now preserve the original TokenStream in all (stable) cases, which includes None-delimited groups. Previously, the pretty-print back-compat hack would kick in, which effectively hid this issue.

@Aaron1011 Aaron1011 added the A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) label May 6, 2021
@Aaron1011
Copy link
Member

Unless we do some kind of closure-specific check in the parser, it's very unlikely that this will be resolved any time soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) C-bug Category: This is a bug.
Projects
None yet
Development

No branches or pull requests

3 participants