Skip to content

Allow shadowing of procedural macro generated macros #57283

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

Closed
dtolnay opened this issue Jan 2, 2019 · 2 comments
Closed

Allow shadowing of procedural macro generated macros #57283

dtolnay opened this issue Jan 2, 2019 · 2 comments
Labels
A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@dtolnay
Copy link
Member

dtolnay commented Jan 2, 2019

The following expression compiles if macro_rules! m is generated by a macro_rules macro, but not if macro_rules! m is generated by a procedural macro. I believe it should compile in both cases. The invocation of m! should resolve to the innermost one, as happens for all other types of items.

{
    macro_rules! m { ... }
    {
        macro_rules! m { ... }
        m!()
    }
}

Repro:

src/main.rs

#![allow(unused_macros)]

macro_rules! eval_with_m {
    ($e:expr) => {{
        macro_rules! m {
            () => {
                println!("success");
            };
        }

        $e
    }};
}

macro_rules! eval_with_m_derived {
    ($e:expr) => {{
        #[derive(repro::M)]
        struct S;

        $e
    }};
}

fn main() {
    // Expanded code looks like:
    //
    //    {
    //        macro_rules! m { ... }
    //        {
    //            macro_rules! m { ... }
    //            m!()
    //        }
    //    }
    //
    eval_with_m! {
        eval_with_m! {
            m!()
        }
    }

    // Expanded code is the same but fails to compile.
    //
    //    error[E0659]: `m` is ambiguous (macro-expanded name vs less
    //    macro-expanded name from outer scope during import/macro resolution)
    //
    eval_with_m_derived! {
        eval_with_m_derived! {
            m!()
        }
    }
}

src/lib.rs

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;

#[proc_macro_derive(M)]
pub fn emit_m(_input: TokenStream) -> TokenStream {
    TokenStream::from(quote! {
        macro_rules! m {
            () => {
                println!("success");
            };
        }
    })
}

Mentioning @petrochenkov who worked on #52841 and fixed #53205.
Mentioning @cramertj who hit this using proc-macro-hack in futures.

@dtolnay dtolnay added A-macros Area: All kinds of macros (custom derive, macro_rules!, proc macros, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jan 2, 2019
@petrochenkov
Copy link
Contributor

petrochenkov commented Jan 2, 2019

@dtolnay
Do you mean #[derive(repro::M)] generates the macro_rules! m { ... } item in the second case?

Then it's a fundamental restriction, sorry :(
Without it macro resolution/expansion either cannot progress, or can produce unstable/order-dependent results.
You can read some history on this in #53778, and a bit more history in some macro modularization RFCs/issues (don't remember the specific threads, but the keyword should be "time travel").

Two tests
https://github.com/rust-lang/rust/blob/master/src/test/ui/macros/restricted-shadowing-modern.rs
https://github.com/rust-lang/rust/blob/master/src/test/ui/macros/restricted-shadowing-legacy.rs
catalogs various macro expansion configuration and show what can work and what cannot.

@dtolnay
Copy link
Member Author

dtolnay commented Jan 2, 2019

Thanks! Didn't know this limitation was already well studied.

@dtolnay dtolnay closed this as completed Jan 2, 2019
# 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, ..) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

2 participants