Skip to content

Unexpected "macro is ambiguous" error when macro imports are generated by a macro #153478

Description

@RalfJung

This code compiles just fine, as one would expect:

macro_rules! assert_biteq_rt {
    ($left:expr, $right:expr $(,)?) => {};
}
macro_rules! assert_biteq_const {
    ($left:expr, $right:expr $(,)?) => {};
}

// Use the runtime version by default.
// This way, they can be shadowed by the const versions.
pub(crate) use assert_biteq_rt as assert_biteq;

// Also make the const version available for re-exports.
pub(crate) use assert_biteq_const;

mod something_nomacro {
    use super::*;

    mod const_ {
        use super::*;
        use crate::assert_biteq_const as assert_biteq;
        
        #[test]
        pub fn test() {
            const { assert_biteq!(0, 0); }
        }
    }
}

However, if I write a macro to generate the actual module at the end that contains the test...

macro_rules! float_test {
    (
        name: $name:ident,
        test $test:block
    ) => {
        mod $name {
            use super::*;
            
            mod const_ {
                use super::*;
                use crate::assert_biteq_const as assert_biteq;
                
                #[test]
                fn test() {
                    const { $test }
                }
            }
        }
    }
}

float_test! {
    name: something_macro,
    test {
        assert_biteq!(0, 0);
    }
}

... then it stops compiling:

error[E0659]: `assert_biteq` is ambiguous
  --> src/lib.rs:53:9
   |
53 |         assert_biteq!(0, 0);
   |         ^^^^^^^^^^^^ ambiguous name
   |
   = note: ambiguous because of a conflict between a name from a glob import and a macro-expanded name in the same module during import or macro resolution
note: `assert_biteq` could refer to the macro imported here
  --> src/lib.rs:39:21
   |
39 |                   use crate::assert_biteq_const as assert_biteq;
   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
50 | / float_test! {
51 | |     name: something_macro,
52 | |     test {
53 | |         assert_biteq!(0, 0);
54 | |     }
55 | | }
   | |_- in this macro invocation
   = help: use `self::assert_biteq` to refer to this macro unambiguously
note: `assert_biteq` could also refer to the macro imported here
  --> src/lib.rs:38:21
   |
38 |                   use super::*;
   |                       ^^^^^^^^
...
50 | / float_test! {
51 | |     name: something_macro,
52 | |     test {
53 | |         assert_biteq!(0, 0);
54 | |     }
55 | | }
   | |_- in this macro invocation
   = help: consider adding an explicit import of `assert_biteq` to disambiguate

The error helpfully tells me to add an explicit import, but I already did that.

This is a minimized version of real code from the libcore test suite. The only way I found so far to avoid this problem is to avoid use super::*; inside mod const_ and instead manually re-import everything we need. That's quite annoying as it means every time we add a new top-level import, we have to remember to also import it inside mod const_ or else the macro-generated tests will start failing.

Cc @petrochenkov in the hopes that you have an idea of what is going on. It is quite puzzling to me that manually expanding the float_test! macro makes the error go away...

Activity

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, ..)A-resolveArea: Name/path resolution done by `rustc_resolve` specificallyC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions