@@ -108,11 +108,109 @@ pub fn expand_derive(cx: &mut ExtCtxt,
108108 cx. span_err ( mitem. span , "unexpected value in `derive`" ) ;
109109 }
110110
111- let traits = mitem. meta_item_list ( ) . unwrap_or ( & [ ] ) ;
111+ let mut traits = mitem. meta_item_list ( ) . unwrap_or ( & [ ] ) . to_owned ( ) ;
112112 if traits. is_empty ( ) {
113113 cx. span_warn ( mitem. span , "empty trait list in `derive`" ) ;
114114 }
115115
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+
116214 // RFC #1445. `#[derive(PartialEq, Eq)]` adds a (trusted)
117215 // `#[structural_match]` attribute.
118216 if traits. iter ( ) . filter_map ( |t| t. name ( ) ) . any ( |t| t == "PartialEq" ) &&
@@ -141,103 +239,33 @@ pub fn expand_derive(cx: &mut ExtCtxt,
141239 } ) ;
142240 }
143241
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
155258 } ;
156- let tname = tword. name ( ) ;
157259
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 ( ) ;
237265 }
238266
239- other_items . insert ( 0 , Annotatable :: Item ( item) ) ;
240- return other_items
267+ items . insert ( 0 , Annotatable :: Item ( item) ) ;
268+ return items
241269}
242270
243271macro_rules! derive_traits {
0 commit comments