1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! `compile_error!` does not interrupt compilation right away. This means
//! `rustc` doesn't just show you the error and abort, it carries on the
//! compilation process, looking for other errors to report.
//!
//! Let's consider an example:
//!
//! ```rust,ignore
//! trait MyTrait {
//! fn do_thing();
//! }
//!
//! // this proc macro is supposed to generate MyTrait impl
//! #[proc_macro_derive(MyTrait)]
//! fn example(input: TokenStream) -> TokenStream {
//! // somewhere deep inside
//! span_error!(span, "something's wrong");
//!
//! // this implementation will be generated if no error happened
//! quote! {
//! impl MyTrait for #name {
//! fn do_thing() {/* whatever */}
//! }
//! }
//! }
//!
//! // ================
//! // in main.rs
//!
//! // this derive triggers an error
//! #[derive(MyTrait)] // first BOOM!
//! struct Foo;
//!
//! fn main() {
//! Foo::do_thing(); // second BOOM!
//! }
//! ```
//!
//! The problem is: the generated token stream contains only `compile_error!`
//! invocation, the impl was not generated. That means user will see two compilation
//! errors:
//! ```text
//! error: set_dummy test
//! --> $DIR/probe.rs:9:10
//! |
//! 9 |#[proc_macro_derive(MyTrait)]
//! | ^^^^^^^
//!
//! error[E0277]: the trait bound `Foo: Default` is not satisfied
//!
//! --> $DIR/probe.rs:14:10
//!
//! |
//! 98 | #[derive(MyTrait)]
//! | ^^^^^^^ the trait `Default` is not implemented for `Foo`
//!
//! ```
//!
//! But the second error is meaningless! We definitely need to fix this.
//!
//! Most used approach in cases like this is "dummy implementation" -
//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`.
//!
//! This is how you do it:
//! ```rust,ignore
//! trait MyTrait {
//! fn do_thing();
//! }
//!
//! // this proc macro is supposed to generate MyTrait impl
//! #[proc_macro_derive(MyTrait)]
//! fn example(input: TokenStream) -> TokenStream {
//! // first of all - we set a dummy impl which will be appended to
//! // `compile_error!` invocations in case a trigger does happen
//! proc_macro_error::set_dummy(Some(quote! {
//! impl MyTrait for #name {
//! fn do_thing() { unimplemented!() }
//! }
//! }));
//!
//! // somewhere deep inside
//! span_error!(span, "something's wrong");
//!
//! // this implementation will be generated if no error happened
//! quote! {
//! impl MyTrait for #name {
//! fn do_thing() {/* whatever */}
//! }
//! }
//! }
//!
//! // ================
//! // in main.rs
//!
//! // this derive triggers an error
//! #[derive(MyTrait)] // first BOOM!
//! struct Foo;
//!
//! fn main() {
//! Foo::do_thing(); // no more errors!
//! }
//! ```
use TokenStream;
use RefCell;
thread_local!
pub
/// Sets dummy token stream which will be appended to `compile_error!(msg);...`
/// invocations, should a trigger happen. Returns an old dummy, if set.
///
/// # Warning:
/// If you do `set_dummy(Some(ts))` you **must** do `set_dummy(None)`
/// before macro execution completes (`filer_macro_errors!` will do that for you)!
/// Otherwise `rustc` will fail with creepy
/// ```text
/// thread 'rustc' panicked at 'use-after-free in `proc_macro` handle', src\libcore\option.rs:1166:5
/// note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
/// error: proc-macro derive panicked
/// ```