Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use a macro which is defined by another macro in the same crate?

Tags:

macros

rust

I'm defining a macro that defines other macros like this:

macros.rs

#[macro_export]
macro_rules! m1 {
    () => {
        #[macro_export]
        macro_rules! m2 {
            () => {}
        }
    }
}

m1!();
m2!(); // no problem;

I can use m2! in another crate by use {{crate_name}}::macros::*, and I can use m2! in macros.rs, but I don't know how to use m2! in files that are in the same crate.

lib.rs

#[macro_use]
pub mod macros;
pub mod test;
pub mod test2;

test.rs (in the same crate as macros.rs)

use crate::m1; // no problem
use crate::m2; // ERROR: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths

m1!(); // no problem
m2!(); // error, no m2

test2.rs

use crate::*;
m2!(); // this works, but I don't really want to use crate::*

examples/yo.rs

use {{crate_name}}::m2;
m2!(); // no problem

What is the correct way to use that m2 macro in other files in the same crate? I'm using Rust 1.31.1.

like image 335
tga Avatar asked Dec 29 '18 18:12

tga


People also ask

How do you define a macro in Rust?

We use a dollar sign ( $ ) to declare a variable in the macro system that will contain the Rust code matching the pattern. The dollar sign makes it clear this is a macro variable as opposed to a regular Rust variable.

Can you use macros in Rust?

Rust has two types of macros: Declarative macros sometimes referred to as "macros by example", “ macro_rules! macros,” or just plain “macros”. Declarative macros enable you to write something similar to a match expression that operates on the Rust code you provide as arguments.

What does tt mean in Rust?

I'm reading a book about Rust, and start playing with Rust macros. All metavariable types are explained there and have examples, except the last one – tt . According to the book, it is a “a single token tree”.

How do I export macros in Rust?

macros can be exported from the current crate using #[macro_export] . Note that this ignores all visibility.


1 Answers

Read and follow the compiler's instructions:

error[E0659]: `m2` is ambiguous (macro-expanded name vs less macro-expanded name from outer scope during import/macro resolution)
  --> src/lib.rs:22:5
   |
22 |     m2!();
   |     ^^ ambiguous name
   |
note: `m2` could refer to the macro defined here
  --> src/lib.rs:7:13
   |
7  | /             macro_rules! m2 {
8  | |                 () => {};
9  | |             }
   | |_____________^
...
21 |       m1!();
   |       ------ in this macro invocation
note: `m2` could also refer to the macro defined here
  --> src/lib.rs:7:13
   |
7  | /             macro_rules! m2 {
8  | |                 () => {};
9  | |             }
   | |_____________^
...
13 |       m1!();
   |       ------ in this macro invocation

error: a macro named `m2` has already been exported
  --> src/lib.rs:7:13
   |
7  | /             macro_rules! m2 {
8  | |                 () => {};
9  | |             }
   | |_____________^ `m2` already exported
...
21 |       m1!();
   |       ------ in this macro invocation
   |
   = note: #[deny(duplicate_macro_exports)] on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
   = note: for more information, see issue #35896 <https://github.com/rust-lang/rust/issues/35896>
note: previous macro export is now shadowed
  --> src/lib.rs:7:13
   |
7  | /             macro_rules! m2 {
8  | |                 () => {};
9  | |             }
   | |_____________^
...
13 |       m1!();
   |       ------ in this macro invocation

error: macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
  --> src/lib.rs:19:9
   |
19 |     use crate::m2; 
   |         ^^^^^^^^^
   |
   = note: #[deny(macro_expanded_macro_exports_accessed_by_absolute_paths)] on by default
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #52234 <https://github.com/rust-lang/rust/issues/52234>
note: the macro is defined here
  --> src/lib.rs:7:13
   |
7  | /             macro_rules! m2 {
8  | |                 () => {};
9  | |             }
   | |_____________^
...
21 |       m1!();
   |       ------ in this macro invocation

Specifically:

error: macro-expanded macro_export macros from the current crate cannot be referred to by absolute paths

Applied:

  1. Don't import the macro; there's no need.
  2. Don't call m1; doing so creates a second m2.

test.rs

// use crate::m1;
// use crate::m2; 

// m1!();
m2!();
like image 152
Shepmaster Avatar answered Sep 29 '22 00:09

Shepmaster