Skip to content

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

@RalfJung

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

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