proc-macro2
proc-macro2 copied to clipboard
Span pointing to its own construction site like Location::caller
I couldn't easily figure by myself reading the code and documentation of proc-macro
and proc-macro2
, so asking here. Is it possible to generate a Span
that points to its own span? Or maybe asked differently, is it possible to create a Span
from (or similarly to) a core::panic::Location
(or 2 to make it an actual span, but a point in code is enough for me)?
Here's the motivation (which I would understand if it's not something proc-macro
is trying to address):
- I would like to use
proc-macro
to generate code from some data-structure describing the code to be generated (see below for why this data-structure cannot be a token stream). - This data-structure would be built within the
proc-macro
crate itself (or eventually from a dependency crate). - When building this data-structure, I would like to "capture" the
Span
of constructor calls. - I would then use
quote_spanned!()
to generate theproc-macro
output based on thoseSpan
s. - (I hope
rust-analyzer
would then be able to point me back to the correct place in theproc-macro
crate when looking for definitions generated by the proc-macro.)
Here's a sketch of a concret example:
enum Input { ... } // data-structure to generate code from
#[proc_macro]
pub fn generate(_: TokenStream) -> TokenStream {
// We don't need the proc-macro input. We use the `Input` data-structure.
let input = Input::generate(); // The input is actually constant, but built dynamically.
input.into_token_stream().into()
}
impl Input {
fn generate() -> Input {
...
let span = Span::caller(); // This behaves like Location::caller();
let sub_input = SubInput::Foo { span, ... };
...
let span = Span::caller(); // All those calls could be split in multiple modules and possibly crates.
Input::Bar { span, sub_input, ... }
}
}
impl ToTokens for Input {
fn to_tokens(&self, tokens: &mut TokenStream2) {
...
tokens.extend(quote_spanned!(sub_input.span => ...));
...
}
}
The reason to not use the input token stream is that it doesn't support going through modules recursively. I would like my data-structure (or equivalently the proc-macro
input) to be hierarchically structured through multiple files like the module hierarchy in a crate does. In other words, the following alternatives would also work for me:
- It is possible within a proc-macro to read the content of a file (relative to the initial macro invocation) as a token stream.
- It is possible for a proc-macro to take a full crate as input, where modules are flattened as if it was a single file. (But this assumes the proc-macro input is valid Rust, which adds a usage constraint.)
Actually found out about https://github.com/rust-lang/rust/issues/92565, https://github.com/rust-lang/rfcs/pull/3200, and in particular https://github.com/rust-lang/rust/issues/55904, which may be solving my problem in a different way.