Skip to content

Allow shadowing of procedural macro generated macros #57283

Description

@dtolnay

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.

Activity

  1. added
    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Jan 2, 2019
  2. petrochenkov commented on Jan 2, 2019

    @petrochenkov
    Contributor

    @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.

  3. dtolnay commented on Jan 2, 2019

    @dtolnay
    MemberAuthor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions