@@ -108,11 +108,109 @@ pub fn expand_derive(cx: &mut ExtCtxt,
108
108
cx. span_err ( mitem. span , "unexpected value in `derive`" ) ;
109
109
}
110
110
111
- let traits = mitem. meta_item_list ( ) . unwrap_or ( & [ ] ) ;
111
+ let mut traits = mitem. meta_item_list ( ) . unwrap_or ( & [ ] ) . to_owned ( ) ;
112
112
if traits. is_empty ( ) {
113
113
cx. span_warn ( mitem. span , "empty trait list in `derive`" ) ;
114
114
}
115
115
116
+ // First, weed out malformed #[derive]
117
+ traits. retain ( |titem| {
118
+ if titem. word ( ) . is_none ( ) {
119
+ cx. span_err ( titem. span , "malformed `derive` entry" ) ;
120
+ false
121
+ } else {
122
+ true
123
+ }
124
+ } ) ;
125
+
126
+ // Next, check for old-style #[derive(Foo)]
127
+ //
128
+ // These all get expanded to `#[derive_Foo]` and will get expanded first. If
129
+ // we actually add any attributes here then we return to get those expanded
130
+ // and then eventually we'll come back to finish off the other derive modes.
131
+ let mut new_attributes = Vec :: new ( ) ;
132
+ traits. retain ( |titem| {
133
+ let tword = titem. word ( ) . unwrap ( ) ;
134
+ let tname = tword. name ( ) ;
135
+
136
+ let derive_mode = ast:: Ident :: with_empty_ctxt ( intern ( & tname) ) ;
137
+ let derive_mode = cx. resolver . resolve_derive_mode ( derive_mode) ;
138
+ if is_builtin_trait ( & tname) || derive_mode. is_some ( ) {
139
+ return true
140
+ }
141
+
142
+ if !cx. ecfg . enable_custom_derive ( ) {
143
+ feature_gate:: emit_feature_err ( & cx. parse_sess ,
144
+ "custom_derive" ,
145
+ titem. span ,
146
+ feature_gate:: GateIssue :: Language ,
147
+ feature_gate:: EXPLAIN_CUSTOM_DERIVE ) ;
148
+ } else {
149
+ let name = intern_and_get_ident ( & format ! ( "derive_{}" , tname) ) ;
150
+ let mitem = cx. meta_word ( titem. span , name) ;
151
+ new_attributes. push ( cx. attribute ( mitem. span , mitem) ) ;
152
+ }
153
+ false
154
+ } ) ;
155
+ if new_attributes. len ( ) > 0 {
156
+ item = item. map ( |mut i| {
157
+ let list = cx. meta_list ( mitem. span ,
158
+ intern_and_get_ident ( "derive" ) ,
159
+ traits) ;
160
+ i. attrs . extend ( new_attributes) ;
161
+ i. attrs . push ( cx. attribute ( mitem. span , list) ) ;
162
+ i
163
+ } ) ;
164
+ return vec ! [ Annotatable :: Item ( item) ]
165
+ }
166
+
167
+ // Now check for macros-1.1 style custom #[derive].
168
+ //
169
+ // Expand each of them in order given, but *before* we expand any built-in
170
+ // derive modes. The logic here is to:
171
+ //
172
+ // 1. Collect the remaining `#[derive]` annotations into a list. If
173
+ // there are any left, attach a `#[derive]` attribute to the item
174
+ // that we're currently expanding with the remaining derive modes.
175
+ // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
176
+ // 3. Expand the current item we're expanding, getting back a list of
177
+ // items that replace it.
178
+ // 4. Extend the returned list with the current list of items we've
179
+ // collected so far.
180
+ // 5. Return everything!
181
+ //
182
+ // If custom derive extensions end up threading through the `#[derive]`
183
+ // attribute, we'll get called again later on to continue expanding
184
+ // those modes.
185
+ let macros_11_derive = traits. iter ( )
186
+ . cloned ( )
187
+ . enumerate ( )
188
+ . filter ( |& ( _, ref name) | !is_builtin_trait ( & name. name ( ) . unwrap ( ) ) )
189
+ . next ( ) ;
190
+ if let Some ( ( i, titem) ) = macros_11_derive {
191
+ let tname = ast:: Ident :: with_empty_ctxt ( intern ( & titem. name ( ) . unwrap ( ) ) ) ;
192
+ let ext = cx. resolver . resolve_derive_mode ( tname) . unwrap ( ) ;
193
+ traits. remove ( i) ;
194
+ if traits. len ( ) > 0 {
195
+ item = item. map ( |mut i| {
196
+ let list = cx. meta_list ( mitem. span ,
197
+ intern_and_get_ident ( "derive" ) ,
198
+ traits) ;
199
+ i. attrs . push ( cx. attribute ( mitem. span , list) ) ;
200
+ i
201
+ } ) ;
202
+ }
203
+ let titem = cx. meta_list_item_word ( titem. span , titem. name ( ) . unwrap ( ) ) ;
204
+ let mitem = cx. meta_list ( titem. span ,
205
+ intern_and_get_ident ( "derive" ) ,
206
+ vec ! [ titem] ) ;
207
+ let item = Annotatable :: Item ( item) ;
208
+ return ext. expand ( cx, mitem. span , & mitem, item)
209
+ }
210
+
211
+ // Ok, at this point we know that there are no old-style `#[derive_Foo]` nor
212
+ // any macros-1.1 style `#[derive(Foo)]`. Expand all built-in traits here.
213
+
116
214
// RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
117
215
// `#[structural_match]` attribute.
118
216
if traits. iter ( ) . filter_map ( |t| t. name ( ) ) . any ( |t| t == "PartialEq" ) &&
@@ -141,103 +239,33 @@ pub fn expand_derive(cx: &mut ExtCtxt,
141
239
} ) ;
142
240
}
143
241
144
- let mut other_items = Vec :: new ( ) ;
145
-
146
- let mut iter = traits. iter ( ) ;
147
- while let Some ( titem) = iter. next ( ) {
148
-
149
- let tword = match titem. word ( ) {
150
- Some ( name) => name,
151
- None => {
152
- cx. span_err ( titem. span , "malformed `derive` entry" ) ;
153
- continue
154
- }
242
+ let mut items = Vec :: new ( ) ;
243
+ for titem in traits. iter ( ) {
244
+ let tname = titem. word ( ) . unwrap ( ) . name ( ) ;
245
+ let name = intern_and_get_ident ( & format ! ( "derive({})" , tname) ) ;
246
+ let mitem = cx. meta_word ( titem. span , name) ;
247
+
248
+ let span = Span {
249
+ expn_id : cx. codemap ( ) . record_expansion ( codemap:: ExpnInfo {
250
+ call_site : titem. span ,
251
+ callee : codemap:: NameAndSpan {
252
+ format : codemap:: MacroAttribute ( intern ( & format ! ( "derive({})" , tname) ) ) ,
253
+ span : Some ( titem. span ) ,
254
+ allow_internal_unstable : true ,
255
+ } ,
256
+ } ) ,
257
+ ..titem. span
155
258
} ;
156
- let tname = tword. name ( ) ;
157
259
158
- // If this is a built-in derive mode, then we expand it immediately
159
- // here.
160
- if is_builtin_trait ( & tname) {
161
- let name = intern_and_get_ident ( & format ! ( "derive({})" , tname) ) ;
162
- let mitem = cx. meta_word ( titem. span , name) ;
163
-
164
- let span = Span {
165
- expn_id : cx. codemap ( ) . record_expansion ( codemap:: ExpnInfo {
166
- call_site : titem. span ,
167
- callee : codemap:: NameAndSpan {
168
- format : codemap:: MacroAttribute ( intern ( & format ! ( "derive({})" , tname) ) ) ,
169
- span : Some ( titem. span ) ,
170
- allow_internal_unstable : true ,
171
- } ,
172
- } ) ,
173
- ..titem. span
174
- } ;
175
-
176
- let my_item = Annotatable :: Item ( item) ;
177
- expand_builtin ( & tname, cx, span, & mitem, & my_item, & mut |a| {
178
- other_items. push ( a) ;
179
- } ) ;
180
- item = my_item. expect_item ( ) ;
181
-
182
- // Otherwise if this is a `rustc_macro`-style derive mode, we process it
183
- // here. The logic here is to:
184
- //
185
- // 1. Collect the remaining `#[derive]` annotations into a list. If
186
- // there are any left, attach a `#[derive]` attribute to the item
187
- // that we're currently expanding with the remaining derive modes.
188
- // 2. Manufacture a `#[derive(Foo)]` attribute to pass to the expander.
189
- // 3. Expand the current item we're expanding, getting back a list of
190
- // items that replace it.
191
- // 4. Extend the returned list with the current list of items we've
192
- // collected so far.
193
- // 5. Return everything!
194
- //
195
- // If custom derive extensions end up threading through the `#[derive]`
196
- // attribute, we'll get called again later on to continue expanding
197
- // those modes.
198
- } else if let Some ( ext) =
199
- cx. resolver . resolve_derive_mode ( ast:: Ident :: with_empty_ctxt ( intern ( & tname) ) ) {
200
- let remaining_derives = iter. cloned ( ) . collect :: < Vec < _ > > ( ) ;
201
- if remaining_derives. len ( ) > 0 {
202
- let list = cx. meta_list ( titem. span ,
203
- intern_and_get_ident ( "derive" ) ,
204
- remaining_derives) ;
205
- let attr = cx. attribute ( titem. span , list) ;
206
- item = item. map ( |mut i| {
207
- i. attrs . push ( attr) ;
208
- i
209
- } ) ;
210
- }
211
- let titem = cx. meta_list_item_word ( titem. span , tname. clone ( ) ) ;
212
- let mitem = cx. meta_list ( titem. span ,
213
- intern_and_get_ident ( "derive" ) ,
214
- vec ! [ titem] ) ;
215
- let item = Annotatable :: Item ( item) ;
216
- let mut items = ext. expand ( cx, mitem. span , & mitem, item) ;
217
- items. extend ( other_items) ;
218
- return items
219
-
220
- // If we've gotten this far then it means that we're in the territory of
221
- // the old custom derive mechanism. If the feature isn't enabled, we
222
- // issue an error, otherwise manufacture the `derive_Foo` attribute.
223
- } else if !cx. ecfg . enable_custom_derive ( ) {
224
- feature_gate:: emit_feature_err ( & cx. parse_sess ,
225
- "custom_derive" ,
226
- titem. span ,
227
- feature_gate:: GateIssue :: Language ,
228
- feature_gate:: EXPLAIN_CUSTOM_DERIVE ) ;
229
- } else {
230
- let name = intern_and_get_ident ( & format ! ( "derive_{}" , tname) ) ;
231
- let mitem = cx. meta_word ( titem. span , name) ;
232
- item = item. map ( |mut i| {
233
- i. attrs . push ( cx. attribute ( mitem. span , mitem) ) ;
234
- i
235
- } ) ;
236
- }
260
+ let my_item = Annotatable :: Item ( item) ;
261
+ expand_builtin ( & tname, cx, span, & mitem, & my_item, & mut |a| {
262
+ items. push ( a) ;
263
+ } ) ;
264
+ item = my_item. expect_item ( ) ;
237
265
}
238
266
239
- other_items . insert ( 0 , Annotatable :: Item ( item) ) ;
240
- return other_items
267
+ items . insert ( 0 , Annotatable :: Item ( item) ) ;
268
+ return items
241
269
}
242
270
243
271
macro_rules! derive_traits {
0 commit comments