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

Allow shadowing of procedural macro generated macros #57283

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
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, ..) 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