5

Github Implement span quoting for proc-macros by Aaron1011 · Pull Request #84278...

 3 years ago
source link: https://github.com/rust-lang/rust/pull/84278
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Copy link

Member

Aaron1011 commented on Apr 17

This PR implements span quoting, allowing proc-macros to produce spans
pointing into their own crate. This is used by the unstable
proc_macro::quote! macro, allowing us to get error messages like this:

error[E0412]: cannot find type `MissingType` in this scope
  --> $DIR/auxiliary/span-from-proc-macro.rs:37:20
   |
LL | pub fn error_from_attribute(_args: TokenStream, _input: TokenStream) -> TokenStream {
   | ----------------------------------------------------------------------------------- in this expansion of procedural macro `#[error_from_attribute]`
...
LL |             field: MissingType
   |                    ^^^^^^^^^^^ not found in this scope
   |
  ::: $DIR/span-from-proc-macro.rs:8:1
   |
LL | #[error_from_attribute]
   | ----------------------- in this macro invocation

Here, MissingType occurs inside the implementation of the proc-macro
#[error_from_attribute]. Previosuly, this would always result in a
span pointing at #[error_from_attribute]

This will make many proc-macro-related error message much more useful -
when a proc-macro generates code containing an error, users will get an
error message pointing directly at that code (within the macro
definition), instead of always getting a span pointing at the macro
invocation site.

This is implemented as follows:

  • When a proc-macro crate is being compiled, it causes the quote!
    macro to get run. This saves all of the sapns in the input to quote!
    into the metadata of the proc-macro-crate (which we are currently
    compiling). The quote! macro then expands to a call to
    proc_macro::Span::recover_proc_macro_span(id), where id is an
    opaque identifier for the span in the crate metadata.
  • When the same proc-macro crate is run (e.g. it is loaded from disk
    and invoked by some consumer crate), the call to
    proc_macro::Span::recover_proc_macro_span causes us to load the span
    from the proc-macro crate's metadata. The proc-macro then produces a
    TokenStream containing a Span pointing into the proc-macro crate
    itself.

The recursive nature of 'quote!' can be difficult to understand at
first. The file src/test/ui/proc-macro/quote-debug.stdout shows
the output of the quote! macro, which should make this eaier to
understand.

This PR also supports custom quoting spans in custom quote macros (e.g.
the quote crate). All span quoting goes through the
proc_macro::quote_span method, which can be called by a custom quote
macro to perform span quoting. An example of this usage is provided in
src/test/ui/proc-macro/auxiliary/custom-quote.rs

Custom quoting currently has a few limitations:

In order to quote a span, we need to generate a call to
proc_macro::Span::recover_proc_macro_span. However, proc-macros
support renaming the proc_macro crate, so we can't simply hardcode
this path. Previously, the quote_span method used the path
crate::Span - however, this only works when it is called by the
builtin quote! macro in the same crate. To support being called from
arbitrary crates, we need access to the name of the proc_macro crate
to generate a path. This PR adds an additional argument to quote_span
to specify the name of the proc_macro crate. Howver, this feels kind
of hacky, and we may want to change this before stabilizing anything
quote-related.

Additionally, using quote_span currently requires enabling the
proc_macro_internals feature. The builtin quote! macro
has an #[allow_internal_unstable] attribute, but this won't work for
custom quote implementations. This will likely require some additional
tricks to apply allow_internal_unstable to the span of
proc_macro::Span::recover_proc_macro_span.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK