@@ -143,7 +143,7 @@ impl ExpansionKind {
143143 }
144144
145145 fn expect_from_annotatables < I : IntoIterator < Item = Annotatable > > ( self , items : I ) -> Expansion {
146- let items = items. into_iter ( ) ;
146+ let mut items = items. into_iter ( ) ;
147147 match self {
148148 ExpansionKind :: Items =>
149149 Expansion :: Items ( items. map ( Annotatable :: expect_item) . collect ( ) ) ,
@@ -153,7 +153,14 @@ impl ExpansionKind {
153153 Expansion :: TraitItems ( items. map ( Annotatable :: expect_trait_item) . collect ( ) ) ,
154154 ExpansionKind :: ForeignItems =>
155155 Expansion :: ForeignItems ( items. map ( Annotatable :: expect_foreign_item) . collect ( ) ) ,
156- _ => unreachable ! ( ) ,
156+ ExpansionKind :: Stmts => Expansion :: Stmts ( items. map ( Annotatable :: expect_stmt) . collect ( ) ) ,
157+ ExpansionKind :: Expr => Expansion :: Expr (
158+ items. next ( ) . expect ( "expected exactly one expression" ) . expect_expr ( )
159+ ) ,
160+ ExpansionKind :: OptExpr =>
161+ Expansion :: OptExpr ( items. next ( ) . map ( Annotatable :: expect_expr) ) ,
162+ ExpansionKind :: Pat | ExpansionKind :: Ty =>
163+ panic ! ( "patterns and types aren't annotatable" ) ,
157164 }
158165 }
159166}
@@ -956,14 +963,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
956963 self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
957964 }
958965
959- // If `item` is an attr invocation, remove and return the macro attribute.
966+ /// If `item` is an attr invocation, remove and return the macro attribute and derive traits .
960967 fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
961968 where T : HasAttrs ,
962969 {
963970 let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
964971
965972 item = item. map_attrs ( |mut attrs| {
966- if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs) {
973+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
974+ true ) {
967975 attr = Some ( legacy_attr_invoc) ;
968976 return attrs;
969977 }
@@ -978,6 +986,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
978986 ( attr, traits, item)
979987 }
980988
989+ /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
990+ /// to the unused-attributes lint (making it an error on statements and expressions
991+ /// is a breaking change)
992+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
993+ let mut attr = None ;
994+
995+ item = item. map_attrs ( |mut attrs| {
996+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
997+ false ) {
998+ attr = Some ( legacy_attr_invoc) ;
999+ return attrs;
1000+ }
1001+
1002+ if self . cx . ecfg . proc_macro_enabled ( ) {
1003+ attr = find_attr_invoc ( & mut attrs) ;
1004+ }
1005+ attrs
1006+ } ) ;
1007+
1008+ ( attr, item)
1009+ }
1010+
9811011 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
9821012 self . cfg . configure ( node)
9831013 }
@@ -988,6 +1018,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
9881018 let features = self . cx . ecfg . features . unwrap ( ) ;
9891019 for attr in attrs. iter ( ) {
9901020 feature_gate:: check_attribute ( attr, self . cx . parse_sess , features) ;
1021+
1022+ // macros are expanded before any lint passes so this warning has to be hardcoded
1023+ if attr. path == "derive" {
1024+ self . cx . struct_span_warn ( attr. span , "`#[derive]` does nothing on macro invocations" )
1025+ . note ( "this may become a hard error in a future release" )
1026+ . emit ( ) ;
1027+ }
9911028 }
9921029 }
9931030
@@ -1008,15 +1045,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
10081045 let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
10091046 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
10101047
1011- let ( attr, derives, expr) = self . classify_item ( expr) ;
1048+ // ignore derives so they remain unused
1049+ let ( attr, expr) = self . classify_nonitem ( expr) ;
10121050
1013- if attr. is_some ( ) || !derives . is_empty ( ) {
1051+ if attr. is_some ( ) {
10141052 // collect the invoc regardless of whether or not attributes are permitted here
10151053 // expansion will eat the attribute so it won't error later
10161054 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
10171055
10181056 // ExpansionKind::Expr requires the macro to emit an expression
1019- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
1057+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
10201058 . make_expr ( ) ;
10211059 }
10221060
@@ -1032,12 +1070,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
10321070 let mut expr = configure ! ( self , expr) . into_inner ( ) ;
10331071 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
10341072
1035- let ( attr, derives, expr) = self . classify_item ( expr) ;
1073+ // ignore derives so they remain unused
1074+ let ( attr, expr) = self . classify_nonitem ( expr) ;
10361075
1037- if attr. is_some ( ) || !derives . is_empty ( ) {
1076+ if attr. is_some ( ) {
10381077 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
10391078
1040- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
1079+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
10411080 ExpansionKind :: OptExpr )
10421081 . make_opt_expr ( ) ;
10431082 }
@@ -1071,7 +1110,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
10711110
10721111 // we'll expand attributes on expressions separately
10731112 if !stmt. is_expr ( ) {
1074- let ( attr, derives, stmt_) = self . classify_item ( stmt) ;
1113+ let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1114+ self . classify_item ( stmt)
1115+ } else {
1116+ // ignore derives on non-item statements so it falls through
1117+ // to the unused-attributes lint
1118+ let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1119+ ( attr, vec ! [ ] , stmt)
1120+ } ;
10751121
10761122 if attr. is_some ( ) || !derives. is_empty ( ) {
10771123 return self . collect_attr ( attr, derives,
0 commit comments