[−][src]Macro quote::quote_spanned
Same as quote!
, but applies a given span to all tokens originating within
the macro invocation.
Syntax
A span expression of type Span
, followed by =>
, followed by the tokens
to quote. The span expression should be brief -- use a variable for anything
more than a few characters. There should be no space before the =>
token.
# use proc_macro2::Span;
# use quote::quote_spanned;
#
# const IGNORE_TOKENS: &'static str = stringify! {
let span = /* ... */;
# };
# let span = Span::call_site();
# let init = 0;
// On one line, use parentheses.
let tokens = quote_spanned!(span=> Box::into_raw(Box::new(#init)));
// On multiple lines, place the span at the top and use braces.
let tokens = quote_spanned! {span=>
Box::into_raw(Box::new(#init))
};
The lack of space before the =>
should look jarring to Rust programmers
and this is intentional. The formatting is designed to be visibly
off-balance and draw the eye a particular way, due to the span expression
being evaluated in the context of the procedural macro and the remaining
tokens being evaluated in the generated code.
Hygiene
Any interpolated tokens preserve the Span
information provided by their
ToTokens
implementation. Tokens that originate within the quote_spanned!
invocation are spanned with the given span argument.
Example
The following procedural macro code uses quote_spanned!
to assert that a
particular Rust type implements the Sync
trait so that references can be
safely shared between threads.
# use quote::{quote_spanned, TokenStreamExt, ToTokens};
# use proc_macro2::{Span, TokenStream};
#
# struct Type;
#
# impl Type {
# fn span(&self) -> Span {
# Span::call_site()
# }
# }
#
# impl ToTokens for Type {
# fn to_tokens(&self, _tokens: &mut TokenStream) {}
# }
#
# let ty = Type;
# let call_site = Span::call_site();
#
let ty_span = ty.span();
let assert_sync = quote_spanned! {ty_span=>
struct _AssertSync where #ty: Sync;
};
If the assertion fails, the user will see an error like the following. The input span of their type is hightlighted in the error.
error[E0277]: the trait bound `*const (): std::marker::Sync` is not satisfied
--> src/main.rs:10:21
|
10 | static ref PTR: *const () = &();
| ^^^^^^^^^ `*const ()` cannot be shared between threads safely
In this example it is important for the where-clause to be spanned with the
line/column information of the user's input type so that error messages are
placed appropriately by the compiler. But it is also incredibly important
that Sync
resolves at the macro definition site and not the macro call
site. If we resolve Sync
at the same span that the user's type is going to
be resolved, then they could bypass our check by defining their own trait
named Sync
that is implemented for their type.