|
1 |
| -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT |
| 1 | +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
2 | 2 | // file at the top-level directory of this distribution and at
|
3 | 3 | // http://rust-lang.org/COPYRIGHT.
|
4 | 4 | //
|
|
13 | 13 | //! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
|
14 | 14 | //! the standard library, and "std" is the core library.
|
15 | 15 |
|
16 |
| -use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord}; |
17 |
| -use ext::base::ExtCtxt; |
| 16 | +use ast::{Item, MetaItem, MetaWord}; |
| 17 | +use attr::AttrMetaMethods; |
| 18 | +use ext::base::{ExtCtxt, SyntaxEnv, Decorator, ItemDecorator, Modifier}; |
| 19 | +use ext::build::AstBuilder; |
| 20 | +use feature_gate; |
18 | 21 | use codemap::Span;
|
| 22 | +use parse::token::{intern, intern_and_get_ident}; |
19 | 23 | use ptr::P;
|
20 | 24 |
|
21 | 25 | macro_rules! pathvec {
|
@@ -74,101 +78,133 @@ pub mod totalord;
|
74 | 78 |
|
75 | 79 | pub mod generic;
|
76 | 80 |
|
77 |
| -pub fn expand_deprecated_deriving(cx: &mut ExtCtxt, |
78 |
| - span: Span, |
79 |
| - _: &MetaItem, |
80 |
| - _: &Item, |
81 |
| - _: &mut FnMut(P<Item>)) { |
| 81 | +fn expand_deprecated_deriving(cx: &mut ExtCtxt, |
| 82 | + span: Span, |
| 83 | + _: &MetaItem, |
| 84 | + _: &Item, |
| 85 | + _: &mut FnMut(P<Item>)) { |
82 | 86 | cx.span_err(span, "`deriving` has been renamed to `derive`");
|
83 | 87 | }
|
84 | 88 |
|
85 |
| -pub fn expand_meta_derive(cx: &mut ExtCtxt, |
86 |
| - _span: Span, |
87 |
| - mitem: &MetaItem, |
88 |
| - item: &Item, |
89 |
| - push: &mut FnMut(P<Item>)) { |
90 |
| - match mitem.node { |
91 |
| - MetaNameValue(_, ref l) => { |
92 |
| - cx.span_err(l.span, "unexpected value in `derive`"); |
| 89 | +fn expand_derive(cx: &mut ExtCtxt, |
| 90 | + _: Span, |
| 91 | + mitem: &MetaItem, |
| 92 | + item: P<Item>) -> P<Item> { |
| 93 | + item.map(|mut item| { |
| 94 | + if mitem.value_str().is_some() { |
| 95 | + cx.span_err(mitem.span, "unexpected value in `derive`"); |
93 | 96 | }
|
94 |
| - MetaWord(_) => { |
| 97 | + |
| 98 | + let traits = mitem.meta_item_list().unwrap_or(&[]); |
| 99 | + if traits.is_empty() { |
95 | 100 | cx.span_warn(mitem.span, "empty trait list in `derive`");
|
96 | 101 | }
|
97 |
| - MetaList(_, ref titems) if titems.len() == 0 => { |
98 |
| - cx.span_warn(mitem.span, "empty trait list in `derive`"); |
| 102 | + |
| 103 | + for titem in traits.iter().rev() { |
| 104 | + let tname = match titem.node { |
| 105 | + MetaWord(ref tname) => tname, |
| 106 | + _ => { |
| 107 | + cx.span_err(titem.span, "malformed `derive` entry"); |
| 108 | + continue; |
| 109 | + } |
| 110 | + }; |
| 111 | + |
| 112 | + if !(is_builtin_trait(tname) || cx.ecfg.enable_custom_derive()) { |
| 113 | + feature_gate::emit_feature_err(&cx.parse_sess.span_diagnostic, |
| 114 | + "custom_derive", |
| 115 | + titem.span, |
| 116 | + feature_gate::EXPLAIN_CUSTOM_DERIVE); |
| 117 | + continue; |
| 118 | + } |
| 119 | + |
| 120 | + // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar] |
| 121 | + item.attrs.push(cx.attribute(titem.span, cx.meta_word(titem.span, |
| 122 | + intern_and_get_ident(&format!("derive_{}", tname))))); |
99 | 123 | }
|
100 |
| - MetaList(_, ref titems) => { |
101 |
| - for titem in titems.iter().rev() { |
102 |
| - match titem.node { |
103 |
| - MetaNameValue(ref tname, _) | |
104 |
| - MetaList(ref tname, _) | |
105 |
| - MetaWord(ref tname) => { |
106 |
| - macro_rules! expand { |
107 |
| - ($func:path) => ($func(cx, titem.span, &**titem, item, |
108 |
| - |i| push(i))) |
109 |
| - } |
110 |
| - |
111 |
| - match &tname[..] { |
112 |
| - "Clone" => expand!(clone::expand_deriving_clone), |
113 |
| - |
114 |
| - "Hash" => expand!(hash::expand_deriving_hash), |
115 |
| - |
116 |
| - "RustcEncodable" => { |
117 |
| - expand!(encodable::expand_deriving_rustc_encodable) |
118 |
| - } |
119 |
| - "RustcDecodable" => { |
120 |
| - expand!(decodable::expand_deriving_rustc_decodable) |
121 |
| - } |
122 |
| - "Encodable" => { |
123 |
| - cx.span_warn(titem.span, |
124 |
| - "derive(Encodable) is deprecated \ |
125 |
| - in favor of derive(RustcEncodable)"); |
126 |
| - |
127 |
| - expand!(encodable::expand_deriving_encodable) |
128 |
| - } |
129 |
| - "Decodable" => { |
130 |
| - cx.span_warn(titem.span, |
131 |
| - "derive(Decodable) is deprecated \ |
132 |
| - in favor of derive(RustcDecodable)"); |
133 |
| - |
134 |
| - expand!(decodable::expand_deriving_decodable) |
135 |
| - } |
136 |
| - |
137 |
| - "PartialEq" => expand!(eq::expand_deriving_eq), |
138 |
| - "Eq" => expand!(totaleq::expand_deriving_totaleq), |
139 |
| - "PartialOrd" => expand!(ord::expand_deriving_ord), |
140 |
| - "Ord" => expand!(totalord::expand_deriving_totalord), |
141 |
| - |
142 |
| - "Rand" => expand!(rand::expand_deriving_rand), |
143 |
| - |
144 |
| - "Show" => { |
145 |
| - cx.span_warn(titem.span, |
146 |
| - "derive(Show) is deprecated \ |
147 |
| - in favor of derive(Debug)"); |
148 |
| - |
149 |
| - expand!(show::expand_deriving_show) |
150 |
| - }, |
151 |
| - |
152 |
| - "Debug" => expand!(show::expand_deriving_show), |
153 |
| - |
154 |
| - "Default" => expand!(default::expand_deriving_default), |
155 |
| - |
156 |
| - "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive), |
157 |
| - |
158 |
| - "Send" => expand!(bounds::expand_deriving_bound), |
159 |
| - "Sync" => expand!(bounds::expand_deriving_bound), |
160 |
| - "Copy" => expand!(bounds::expand_deriving_bound), |
161 |
| - |
162 |
| - ref tname => { |
163 |
| - cx.span_err(titem.span, |
164 |
| - &format!("unknown `derive` \ |
165 |
| - trait: `{}`", |
166 |
| - *tname)); |
167 |
| - } |
168 |
| - }; |
| 124 | + |
| 125 | + item |
| 126 | + }) |
| 127 | +} |
| 128 | + |
| 129 | +macro_rules! derive_traits { |
| 130 | + ($( $name:expr => $func:path, )*) => { |
| 131 | + pub fn register_all(env: &mut SyntaxEnv) { |
| 132 | + // Define the #[derive_*] extensions. |
| 133 | + $({ |
| 134 | + struct DeriveExtension; |
| 135 | + |
| 136 | + impl ItemDecorator for DeriveExtension { |
| 137 | + fn expand(&self, |
| 138 | + ecx: &mut ExtCtxt, |
| 139 | + sp: Span, |
| 140 | + mitem: &MetaItem, |
| 141 | + item: &Item, |
| 142 | + push: &mut FnMut(P<Item>)) { |
| 143 | + warn_if_deprecated(ecx, sp, $name); |
| 144 | + $func(ecx, sp, mitem, item, |i| push(i)); |
169 | 145 | }
|
170 | 146 | }
|
| 147 | + |
| 148 | + env.insert(intern(concat!("derive_", $name)), |
| 149 | + Decorator(Box::new(DeriveExtension))); |
| 150 | + })* |
| 151 | + |
| 152 | + env.insert(intern("derive"), |
| 153 | + Modifier(Box::new(expand_derive))); |
| 154 | + env.insert(intern("deriving"), |
| 155 | + Decorator(Box::new(expand_deprecated_deriving))); |
| 156 | + } |
| 157 | + |
| 158 | + fn is_builtin_trait(name: &str) -> bool { |
| 159 | + match name { |
| 160 | + $( $name )|* => true, |
| 161 | + _ => false, |
171 | 162 | }
|
172 | 163 | }
|
173 | 164 | }
|
174 | 165 | }
|
| 166 | + |
| 167 | +derive_traits! { |
| 168 | + "Clone" => clone::expand_deriving_clone, |
| 169 | + |
| 170 | + "Hash" => hash::expand_deriving_hash, |
| 171 | + |
| 172 | + "RustcEncodable" => encodable::expand_deriving_rustc_encodable, |
| 173 | + |
| 174 | + "RustcDecodable" => decodable::expand_deriving_rustc_decodable, |
| 175 | + |
| 176 | + "PartialEq" => eq::expand_deriving_eq, |
| 177 | + "Eq" => totaleq::expand_deriving_totaleq, |
| 178 | + "PartialOrd" => ord::expand_deriving_ord, |
| 179 | + "Ord" => totalord::expand_deriving_totalord, |
| 180 | + |
| 181 | + "Rand" => rand::expand_deriving_rand, |
| 182 | + |
| 183 | + "Debug" => show::expand_deriving_show, |
| 184 | + |
| 185 | + "Default" => default::expand_deriving_default, |
| 186 | + |
| 187 | + "FromPrimitive" => primitive::expand_deriving_from_primitive, |
| 188 | + |
| 189 | + "Send" => bounds::expand_deriving_unsafe_bound, |
| 190 | + "Sync" => bounds::expand_deriving_unsafe_bound, |
| 191 | + "Copy" => bounds::expand_deriving_copy, |
| 192 | + |
| 193 | + // deprecated |
| 194 | + "Show" => show::expand_deriving_show, |
| 195 | + "Encodable" => encodable::expand_deriving_encodable, |
| 196 | + "Decodable" => decodable::expand_deriving_decodable, |
| 197 | +} |
| 198 | + |
| 199 | +#[inline] // because `name` is a compile-time constant |
| 200 | +fn warn_if_deprecated(ecx: &mut ExtCtxt, sp: Span, name: &str) { |
| 201 | + if let Some(replacement) = match name { |
| 202 | + "Show" => Some("Debug"), |
| 203 | + "Encodable" => Some("RustcEncodable"), |
| 204 | + "Decodable" => Some("RustcDecodable"), |
| 205 | + _ => None, |
| 206 | + } { |
| 207 | + ecx.span_warn(sp, &format!("derive({}) is deprecated in favor of derive({})", |
| 208 | + name, replacement)); |
| 209 | + } |
| 210 | +} |
0 commit comments