Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/rust/syn/spanned.rs
38271 views
1
// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3
//! A trait that can provide the `Span` of the complete contents of a syntax
4
//! tree node.
5
//!
6
//! <br>
7
//!
8
//! # Example
9
//!
10
//! Suppose in a procedural macro we have a [`Type`] that we want to assert
11
//! implements the [`Sync`] trait. Maybe this is the type of one of the fields
12
//! of a struct for which we are deriving a trait implementation, and we need to
13
//! be able to pass a reference to one of those fields across threads.
14
//!
15
//! [`Type`]: crate::Type
16
//! [`Sync`]: std::marker::Sync
17
//!
18
//! If the field type does *not* implement `Sync` as required, we want the
19
//! compiler to report an error pointing out exactly which type it was.
20
//!
21
//! The following macro code takes a variable `ty` of type `Type` and produces a
22
//! static assertion that `Sync` is implemented for that type.
23
//!
24
//! ```
25
//! # extern crate proc_macro;
26
//! #
27
//! use proc_macro::TokenStream;
28
//! use proc_macro2::Span;
29
//! use quote::quote_spanned;
30
//! use syn::Type;
31
//! use syn::spanned::Spanned;
32
//!
33
//! # const IGNORE_TOKENS: &str = stringify! {
34
//! #[proc_macro_derive(MyMacro)]
35
//! # };
36
//! pub fn my_macro(input: TokenStream) -> TokenStream {
37
//! # let ty = get_a_type();
38
//! /* ... */
39
//!
40
//! let assert_sync = quote_spanned! {ty.span()=>
41
//! struct _AssertSync where #ty: Sync;
42
//! };
43
//!
44
//! /* ... */
45
//! # input
46
//! }
47
//! #
48
//! # fn get_a_type() -> Type {
49
//! # unimplemented!()
50
//! # }
51
//! ```
52
//!
53
//! By inserting this `assert_sync` fragment into the output code generated by
54
//! our macro, the user's code will fail to compile if `ty` does not implement
55
//! `Sync`. The errors they would see look like the following.
56
//!
57
//! ```text
58
//! error[E0277]: the trait bound `*const i32: std::marker::Sync` is not satisfied
59
//! --> src/main.rs:10:21
60
//! |
61
//! 10 | bad_field: *const i32,
62
//! | ^^^^^^^^^^ `*const i32` cannot be shared between threads safely
63
//! ```
64
//!
65
//! In this technique, using the `Type`'s span for the error message makes the
66
//! error appear in the correct place underlining the right type.
67
//!
68
//! <br>
69
//!
70
//! # Limitations
71
//!
72
//! The underlying [`proc_macro::Span::join`] method is nightly-only. When
73
//! called from within a procedural macro in a nightly compiler, `Spanned` will
74
//! use `join` to produce the intended span. When not using a nightly compiler,
75
//! only the span of the *first token* of the syntax tree node is returned.
76
//!
77
//! In the common case of wanting to use the joined span as the span of a
78
//! `syn::Error`, consider instead using [`syn::Error::new_spanned`] which is
79
//! able to span the error correctly under the complete syntax tree node without
80
//! needing the unstable `join`.
81
//!
82
//! [`syn::Error::new_spanned`]: crate::Error::new_spanned
83
84
use proc_macro2::Span;
85
use quote::spanned::Spanned as ToTokens;
86
87
/// A trait that can provide the `Span` of the complete contents of a syntax
88
/// tree node.
89
///
90
/// This trait is automatically implemented for all types that implement
91
/// [`ToTokens`] from the `quote` crate, as well as for `Span` itself.
92
///
93
/// [`ToTokens`]: quote::ToTokens
94
///
95
/// See the [module documentation] for an example.
96
///
97
/// [module documentation]: self
98
pub trait Spanned: private::Sealed {
99
/// Returns a `Span` covering the complete contents of this syntax tree
100
/// node, or [`Span::call_site()`] if this node is empty.
101
///
102
/// [`Span::call_site()`]: proc_macro2::Span::call_site
103
fn span(&self) -> Span;
104
}
105
106
impl<T: ?Sized + ToTokens> Spanned for T {
107
fn span(&self) -> Span {
108
self.__span()
109
}
110
}
111
112
mod private {
113
use crate::spanned::ToTokens;
114
115
pub trait Sealed {}
116
impl<T: ?Sized + ToTokens> Sealed for T {}
117
118
#[cfg(any(feature = "full", feature = "derive"))]
119
impl Sealed for crate::QSelf {}
120
}
121
122