@@ -745,9 +745,17 @@ impl SyntaxExtension {
745745 }
746746 }
747747
748- let builtin_name = sess
748+ let ( builtin_name, helper_attrs ) = sess
749749 . 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) ) ;
751759 let ( stability, const_stability) = attr:: find_stability ( & sess, attrs, span) ;
752760 if let Some ( ( _, sp) ) = const_stability {
753761 sess. parse_sess
@@ -1213,6 +1221,88 @@ pub fn get_exprs_from_tts(
12131221 Some ( es)
12141222}
12151223
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+
12161306/// This nonterminal looks like some specific enums from
12171307/// `proc-macro-hack` and `procedural-masquerade` crates.
12181308/// We need to maintain some special pretty-printing behavior for them due to incorrect
0 commit comments