@@ -96,6 +96,10 @@ fn expand_derive(cx: &mut ExtCtxt,
96
96
let mut found_partial_eq = false ;
97
97
let mut found_eq = false ;
98
98
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
+
99
103
for titem in traits. iter ( ) . rev ( ) {
100
104
let tname = match titem. node {
101
105
MetaItemKind :: Word ( ref tname) => tname,
@@ -120,8 +124,18 @@ fn expand_derive(cx: &mut ExtCtxt,
120
124
found_partial_eq = true ;
121
125
}
122
126
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
+
123
137
// #[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 ,
125
139
intern_and_get_ident ( & format ! ( "derive_{}" , tname) ) ) ) ) ;
126
140
}
127
141
@@ -155,12 +169,10 @@ fn expand_derive(cx: &mut ExtCtxt,
155
169
//
156
170
// See tests src/run-pass/rfc1445 for
157
171
// 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) ;
161
173
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 ,
164
176
structural_match) ) ) ;
165
177
}
166
178
@@ -188,7 +200,7 @@ macro_rules! derive_traits {
188
200
mitem: & MetaItem ,
189
201
annotatable: & Annotatable ,
190
202
push: & mut FnMut ( Annotatable ) ) {
191
- warn_if_deprecated ( ecx, sp, $name) ;
203
+ check_builtin_derive ( ecx, sp, $name) ;
192
204
$func( ecx, sp, mitem, annotatable, push) ;
193
205
}
194
206
}
@@ -238,7 +250,15 @@ derive_traits! {
238
250
}
239
251
240
252
#[ 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
+ }
242
262
if let Some ( replacement) = match name {
243
263
"Encodable" => Some ( "RustcEncodable" ) ,
244
264
"Decodable" => Some ( "RustcDecodable" ) ,
0 commit comments