• A
    Implement span quoting for proc-macros · f916b047
    Aaron Hill 提交于
    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`.
    f916b047
spans.rs 40.7 KB