Macro failed to resolve: use of undeclared crate or module

I am new to using macros in rust. I got syn's heapsize example to work, but with a few changes, I suddenly have run into errors.

myderivemacro/lib.rs

use proc_macro2::TokenStream;
use quote::{quote, quote_spanned};
use syn::{parse_macro_input, parse_quote, Data, DeriveInput, Fields, GenericParam, Generics, Index};
use syn::spanned::Spanned;

#[proc_macro_derive(SpecialPrinter)]
pub fn derive_special_printer(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    // Parse the input tokens into a syntax tree.
    let input = parse_macro_input!(input as DeriveInput);

    // Used in the quasi-quotation below as `#name`.
    let name = input.ident;

    let generics = add_trait_bounds(input.generics);
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let printing = print_all(&input.data);

    let expanded = quote! {
        // The generated impl.
        impl #impl_generics myderiveexample::SpecialPrinter for #name #ty_generics #where_clause {
            fn print_all(&self) {
               #printing
            }
        }
    };

    // Hand the output tokens back to the compiler.
    proc_macro::TokenStream::from(expanded)
}

fn add_trait_bounds(mut generics: Generics) -> Generics {
    for param in &mut generics.params {
        if let GenericParam::Type(ref mut type_param) = *param {
            type_param.bounds.push(parse_quote!(myderiveexample::SpecialPrinter));
        }
    }
    generics
}

fn print_all(data: &Data) -> TokenStream {
    match *data {
        Data::Struct(ref data) => {
            match data.fields {
                Fields::Named(ref fields) => {
                    let recurse = fields.named.iter().map(|f| {
                        let name = &f.ident;
                        quote_spanned! {f.span()=>
                            myderiveexample::SpecialPrinter::print_all(&self.#name)
                        }
                    });
                    quote! {
                        0 #(+ #recurse)*
                    }
                }
                Fields::Unnamed(ref fields) => {
                    let recurse = fields.unnamed.iter().enumerate().map(|(i, f)| {
                        let index = Index::from(i);
                        quote_spanned! {f.span()=>
                            myderiveexample::SpecialPrinter::print_all(&self.#index)
                        }
                    });
                    quote! {
                        0 #(+ #recurse)*
                    }
                }
                Fields::Unit => {
                    quote!(dbg!("Butter"))
                }
            }
        }
        Data::Enum(_) | Data::Union(_) => unimplemented!(),
    }
}

myderiveexample/main.rs

use myderivemacro::SpecialPrinter;

pub trait SpecialPrinter {
    fn print_all(&self);
}

#[derive(Debug, SpecialPrinter)]
pub struct Dang {
    pub x: u32,
    pub y: u64,
}

impl SpecialPrinter for u32 {
    fn print_all(&self) {
       dbg!(self);
    }
}

impl SpecialPrinter for u64 {
    fn print_all(&self) {
       dbg!(self);
    }
}

pub fn main() {}

Compiling the procedural macro works fine, but when compiling mydebugexample, I get the following:

failed to resolve: use of undeclared crate or module myderiveexample

7 | #[derive(Debug, SpecialPrinter)]
| ^^^^^^^^^^^^^^
| |
| use of undeclared crate or module myderiveexample
| in this derive macro expansion

7 | pub fn derive_special_printer(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
| ---------------------------------------------------------------------------------------- in this expansion of #[derive(SpecialPrinter)]

I have no idea what the problem is. Referring to the crate with the original heapsize example worked fine.

Welcome! Please format your code snippets and compiler errors as described here so we can read them easily:

I think the problem is that the expansion of the SpecialPrinter derive macro refers to myderiveexample::SpecialPrinter, and then you try to invoke the macro from myderiveexample. This is problematic because paths starting with whatever:: are not meaningful inside the whatever crate. Think of it as myderiveexample depending (explicitly) on myderivemacro and myderivemacro depending (implicitly, via the macro expansion) on myderiveexample—this cyclical dependence is the essence of the issue. You can fix it by introducing a third crate, call it special_printer, that just defines the SpecialPrinter trait; then the derive macro in myderivemacro can refer to special_printer::SpecialPrinter in expansions, and myderiveexample can depend on special_printer (as well as on myderiveexample), breaking the cycle. Note that this division into three crates is exactly how the heapsize example does it.

There is also the option to add a:

extern crate self as myderiveexample;

to the src/lib.rs inside the myderiveexample crate, which takes care of:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.