@@ -745,9 +745,17 @@ impl SyntaxExtension {
745
745
}
746
746
}
747
747
748
- let builtin_name = sess
748
+ let ( builtin_name, helper_attrs ) = sess
749
749
. find_by_name ( attrs, sym:: rustc_builtin_macro)
750
- . map ( |a| a. value_str ( ) . unwrap_or ( name) ) ;
750
+ . map ( |attr| {
751
+ // Override `helper_attrs` passed above if it's a built-in macro,
752
+ // marking `proc_macro_derive` macros as built-in is not a realistic use case.
753
+ parse_macro_name_and_helper_attrs ( sess. diagnostic ( ) , attr, "built-in" ) . map_or_else (
754
+ || ( Some ( name) , Vec :: new ( ) ) ,
755
+ |( name, helper_attrs) | ( Some ( name) , helper_attrs) ,
756
+ )
757
+ } )
758
+ . unwrap_or_else ( || ( None , helper_attrs) ) ;
751
759
let ( stability, const_stability) = attr:: find_stability ( & sess, attrs, span) ;
752
760
if let Some ( ( _, sp) ) = const_stability {
753
761
sess. parse_sess
@@ -1213,6 +1221,88 @@ pub fn get_exprs_from_tts(
1213
1221
Some ( es)
1214
1222
}
1215
1223
1224
+ pub fn parse_macro_name_and_helper_attrs (
1225
+ diag : & rustc_errors:: Handler ,
1226
+ attr : & Attribute ,
1227
+ descr : & str ,
1228
+ ) -> Option < ( Symbol , Vec < Symbol > ) > {
1229
+ // Once we've located the `#[proc_macro_derive]` attribute, verify
1230
+ // that it's of the form `#[proc_macro_derive(Foo)]` or
1231
+ // `#[proc_macro_derive(Foo, attributes(A, ..))]`
1232
+ let list = match attr. meta_item_list ( ) {
1233
+ Some ( list) => list,
1234
+ None => return None ,
1235
+ } ;
1236
+ if list. len ( ) != 1 && list. len ( ) != 2 {
1237
+ diag. span_err ( attr. span , "attribute must have either one or two arguments" ) ;
1238
+ return None ;
1239
+ }
1240
+ let trait_attr = match list[ 0 ] . meta_item ( ) {
1241
+ Some ( meta_item) => meta_item,
1242
+ _ => {
1243
+ diag. span_err ( list[ 0 ] . span ( ) , "not a meta item" ) ;
1244
+ return None ;
1245
+ }
1246
+ } ;
1247
+ let trait_ident = match trait_attr. ident ( ) {
1248
+ Some ( trait_ident) if trait_attr. is_word ( ) => trait_ident,
1249
+ _ => {
1250
+ diag. span_err ( trait_attr. span , "must only be one word" ) ;
1251
+ return None ;
1252
+ }
1253
+ } ;
1254
+
1255
+ if !trait_ident. name . can_be_raw ( ) {
1256
+ diag. span_err (
1257
+ trait_attr. span ,
1258
+ & format ! ( "`{}` cannot be a name of {} macro" , trait_ident, descr) ,
1259
+ ) ;
1260
+ }
1261
+
1262
+ let attributes_attr = list. get ( 1 ) ;
1263
+ let proc_attrs: Vec < _ > = if let Some ( attr) = attributes_attr {
1264
+ if !attr. has_name ( sym:: attributes) {
1265
+ diag. span_err ( attr. span ( ) , "second argument must be `attributes`" )
1266
+ }
1267
+ attr. meta_item_list ( )
1268
+ . unwrap_or_else ( || {
1269
+ diag. span_err ( attr. span ( ) , "attribute must be of form: `attributes(foo, bar)`" ) ;
1270
+ & [ ]
1271
+ } )
1272
+ . iter ( )
1273
+ . filter_map ( |attr| {
1274
+ let attr = match attr. meta_item ( ) {
1275
+ Some ( meta_item) => meta_item,
1276
+ _ => {
1277
+ diag. span_err ( attr. span ( ) , "not a meta item" ) ;
1278
+ return None ;
1279
+ }
1280
+ } ;
1281
+
1282
+ let ident = match attr. ident ( ) {
1283
+ Some ( ident) if attr. is_word ( ) => ident,
1284
+ _ => {
1285
+ diag. span_err ( attr. span , "must only be one word" ) ;
1286
+ return None ;
1287
+ }
1288
+ } ;
1289
+ if !ident. name . can_be_raw ( ) {
1290
+ diag. span_err (
1291
+ attr. span ,
1292
+ & format ! ( "`{}` cannot be a name of derive helper attribute" , ident) ,
1293
+ ) ;
1294
+ }
1295
+
1296
+ Some ( ident. name )
1297
+ } )
1298
+ . collect ( )
1299
+ } else {
1300
+ Vec :: new ( )
1301
+ } ;
1302
+
1303
+ Some ( ( trait_ident. name , proc_attrs) )
1304
+ }
1305
+
1216
1306
/// This nonterminal looks like some specific enums from
1217
1307
/// `proc-macro-hack` and `procedural-masquerade` crates.
1218
1308
/// We need to maintain some special pretty-printing behavior for them due to incorrect
0 commit comments