Skip to content

Compile error mixing declarative macros with procedural macros #82784

New issue

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

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

Already on GitHub? # to your account

Open
rusty-objects opened this issue Mar 4, 2021 · 4 comments
Open

Compile error mixing declarative macros with procedural macros #82784

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

Comments

@rusty-objects
Copy link

rusty-objects 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.

# for free to join this conversation on GitHub. Already have an account? # 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