Is it possible to reexport a proc_macro?


#1

Hi, I was experimenting with new proc macros recently and wondered if it’s possible to reexport them. Consider the following scenario:

Let’s say there’s a crate called definition containing a foo macro:

#![feature(proc_macro)]
extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn foo(_input: TokenStream) -> TokenStream { unimplemented!() }

I’ve created a reexport crate:

#![feature(proc_macro)]
extern crate definition;
pub use definition::foo;

Now, when I try to use the reexported macro:

#[feature(proc_macro)]

// #[macro_use]
extern crate reexport;

use reexport::foo;

fn main() {
    foo!()
}

It fails with unresolved import:

error[E0432]: unresolved import `reexport::foo`
 --> src/main.rs:6:5
  |
6 | use reexport::foo;
  |     ^^^^^^^^^^^^^ no `foo` in the root

I’ve created a repository with such a setup, if anybody wants to experiment.

Now, the fun part is that if I comment out the use line and uncomment the macro_use instead, the reexported macro runs, ie. the message proc macro paniced is printed. But if I change the macro not to panic, I get the following error:

error: procedural macros cannot be imported with `#[macro_use]`
 --> src/main.rs:9:5
  |
9 |     foo!()
  |     ^^^
help: instead, import the procedural macro like any other item
  |
8 | use definition::foo;
  |

Which is exactly what I was trying in the first place!

So, is it actually possible to reexport a procedural macro?

In the case I’ve fallen into some XY-problem trap: My original problem was “how to export both macro_rules and a proc-macro macros in the same crate” and I’ve tried to put the proc macro in separate definition crate (to sidestep the limitation that proc-macro = true crate can’t contain macro_rules macros).


#2

The failure crate exports both macro_rules and proc macros from the same crate. Take a look at what they do.


#3

I’ve tried grepping proc_macro in failure’s source, but it seems that failure exports only macro_rules macros and failure_derive exports the procedural derive. Perhaps I’ve missed something?


#4

The same crate exports both the Fail custom derive procedural macro and the macro rules listed in https://docs.rs/failure/0.1/failure/#macros.

#[macro_use]
extern crate failure;

#[derive(Debug, Fail)]
enum ToolchainError {
    #[fail(display = "invalid toolchain name")]
    InvalidToolchainName,
}

fn main() {
    let _ = format_err!("Error code: {}", 101);
}

#5

Sorry, my bad then – the failure crate indeed reexports proc macro from failure_derive. It does so by #[macro_use] + pub use and as per your example, requires only #[macro_use] on usage site. Unfortunately, when I try to apply this pattern to my usecase, I get the same procedural macros cannot be imported with #[macro_use] error as before. Perhaps the difference is that I try to use expression-style, not derive-style macro.