@@ -96,6 +96,10 @@ fn expand_derive(cx: &mut ExtCtxt,
9696 let mut found_partial_eq = false ;
9797 let mut found_eq = false ;
9898
99+ // See below for how this is used with #[structural_match].
100+ let unstable_span = Span { expn_id : cx. backtrace ( ) , .. span } ;
101+ assert ! ( cx. parse_sess. codemap( ) . span_allows_unstable( unstable_span) ) ;
102+
99103 for titem in traits. iter ( ) . rev ( ) {
100104 let tname = match titem. node {
101105 MetaItemKind :: Word ( ref tname) => tname,
@@ -120,8 +124,18 @@ fn expand_derive(cx: &mut ExtCtxt,
120124 found_partial_eq = true ;
121125 }
122126
127+ // Mark the attributes we generate as allowing unstable code,
128+ // to bypass the feature-gating of #[derive_*] attributes.
129+ let mut tspan = titem. span ;
130+ tspan. expn_id = unstable_span. expn_id ;
131+ if !cx. parse_sess . codemap ( ) . span_allows_unstable ( tspan) {
132+ // If we can't use the trait span, use the full #[...] span.
133+ // See below for how this works with #[structural_match].
134+ tspan = unstable_span;
135+ }
136+
123137 // #[derive(Foo, Bar)] expands to #[derive_Foo] #[derive_Bar]
124- item. attrs . push ( cx. attribute ( titem . span , cx. meta_word ( titem . span ,
138+ item. attrs . push ( cx. attribute ( tspan , cx. meta_word ( tspan ,
125139 intern_and_get_ident ( & format ! ( "derive_{}" , tname) ) ) ) ) ;
126140 }
127141
@@ -155,12 +169,10 @@ fn expand_derive(cx: &mut ExtCtxt,
155169 //
156170 // See tests src/run-pass/rfc1445 for
157171 // examples. --nmatsakis
158- let span = Span { expn_id : cx. backtrace ( ) , .. span } ;
159- assert ! ( cx. parse_sess. codemap( ) . span_allows_unstable( span) ) ;
160- debug ! ( "inserting structural_match with span {:?}" , span) ;
172+ debug ! ( "inserting structural_match with span {:?}" , unstable_span) ;
161173 let structural_match = intern_and_get_ident ( "structural_match" ) ;
162- item. attrs . push ( cx. attribute ( span ,
163- cx. meta_word ( span ,
174+ item. attrs . push ( cx. attribute ( unstable_span ,
175+ cx. meta_word ( unstable_span ,
164176 structural_match) ) ) ;
165177 }
166178
@@ -188,7 +200,7 @@ macro_rules! derive_traits {
188200 mitem: & MetaItem ,
189201 annotatable: & Annotatable ,
190202 push: & mut FnMut ( Annotatable ) ) {
191- warn_if_deprecated ( ecx, sp, $name) ;
203+ check_builtin_derive ( ecx, sp, $name) ;
192204 $func( ecx, sp, mitem, annotatable, push) ;
193205 }
194206 }
@@ -238,7 +250,15 @@ derive_traits! {
238250}
239251
240252#[ inline] // because `name` is a compile-time constant
241- fn warn_if_deprecated ( ecx : & mut ExtCtxt , sp : Span , name : & str ) {
253+ fn check_builtin_derive ( ecx : & mut ExtCtxt , sp : Span , name : & str ) {
254+ let allows_unstable = ecx. parse_sess . codemap ( ) . span_allows_unstable ( sp) ;
255+ if !( allows_unstable || ecx. ecfg . enable_custom_derive ( ) ) {
256+ feature_gate:: emit_feature_err ( & ecx. parse_sess . span_diagnostic ,
257+ "custom_derive" ,
258+ sp,
259+ feature_gate:: GateIssue :: Language ,
260+ feature_gate:: EXPLAIN_DERIVE_UNDERSCORE ) ;
261+ }
242262 if let Some ( replacement) = match name {
243263 "Encodable" => Some ( "RustcEncodable" ) ,
244264 "Decodable" => Some ( "RustcDecodable" ) ,
0 commit comments