Skip to content

$crate is missing from attribute and derive macro input #56622

Closed
@dtolnay

Description

@dtolnay

I have some macros that mostly just print their inputs:

procedural/src/lib.rs (edition = 2015 or 2018)

extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn m(input: TokenStream) -> TokenStream {
    println!("PROC MACRO INPUT:  {}", input);
    input.into_iter().collect()
}

#[proc_macro_attribute]
pub fn a(_args: TokenStream, input: TokenStream) -> TokenStream {
    println!("ATTRIBUTE INPUT:   {}", input);
    input //.into_iter().collect() // emits invalid code if uncommented
}

#[proc_macro_derive(d)]
pub fn d(input: TokenStream) -> TokenStream {
    println!("DERIVE INPUT:      {}", input);
    TokenStream::new()
}



And I invoke them each from a 2018 crate:

repro/src/main.rs (edition = 2018)

#![allow(dead_code)]

type S = bool;

macro_rules! m {
    () => {
        procedural::m! {
            struct M($crate::S);
        }

        #[procedural::a]
        struct A($crate::S);

        #[derive(procedural::d)]
        struct D($crate::S);
    };
}

m!();

fn main() {}



The unexpected output is:

PROC MACRO INPUT:  struct M ( $crate :: S ) ;
ATTRIBUTE INPUT:   struct A(::S);
DERIVE INPUT:      struct D(::S);

The attribute macro and derive macro inputs are missing the $crate. The $crate is missing both from the to_string() representation as well as when iterating over the TokenStream.

If you uncomment the commented half line in procedural::a, the downstream crate fails to compile.

error[E0412]: cannot find type `S` in the crate root
help: possible candidate is found in another module, you can import it into scope
  |
1 | use crate::S;
  |

error: aborting due to previous error

I think this means procedural macros can't in general emit correct code when invoked from a 2018 edition crate with $crate in the input item.

If we really don't want to pass $crate through in the macro input, then it needs to decay to crate if it is from a 2018 crate. (You know how in 2015 we have $crate conceptually replaced by either nothing or the crate name, depending on whether the use is from the same crate or from a different crate. In 2018 we need this to be crate or the crate name.)

Mentioning @jimmycuadra who reported this in serde-rs/serde#1440.
Mentioning @petrochenkov @eddyb @alexcrichton for thoughts.

Metadata

Metadata

Assignees

Labels

A-macrosArea: All kinds of macros (custom derive, macro_rules!, proc macros, ..)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions