@@ -141,15 +141,22 @@ impl ExpansionKind {
141141 }
142142
143143 fn expect_from_annotatables < I : IntoIterator < Item = Annotatable > > ( self , items : I ) -> Expansion {
144- let items = items. into_iter ( ) ;
144+ let mut items = items. into_iter ( ) ;
145145 match self {
146146 ExpansionKind :: Items =>
147147 Expansion :: Items ( items. map ( Annotatable :: expect_item) . collect ( ) ) ,
148148 ExpansionKind :: ImplItems =>
149149 Expansion :: ImplItems ( items. map ( Annotatable :: expect_impl_item) . collect ( ) ) ,
150150 ExpansionKind :: TraitItems =>
151151 Expansion :: TraitItems ( items. map ( Annotatable :: expect_trait_item) . collect ( ) ) ,
152- _ => unreachable ! ( ) ,
152+ ExpansionKind :: Stmts => Expansion :: Stmts ( items. map ( Annotatable :: expect_stmt) . collect ( ) ) ,
153+ ExpansionKind :: Expr => Expansion :: Expr (
154+ items. next ( ) . expect ( "expected exactly one expression" ) . expect_expr ( )
155+ ) ,
156+ ExpansionKind :: OptExpr =>
157+ Expansion :: OptExpr ( items. next ( ) . map ( Annotatable :: expect_expr) ) ,
158+ ExpansionKind :: Pat | ExpansionKind :: Ty =>
159+ panic ! ( "patterns and types aren't annotatable" ) ,
153160 }
154161 }
155162}
@@ -867,14 +874,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
867874 self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
868875 }
869876
870- // If `item` is an attr invocation, remove and return the macro attribute.
877+ /// If `item` is an attr invocation, remove and return the macro attribute and derive traits .
871878 fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
872879 where T : HasAttrs ,
873880 {
874881 let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
875882
876883 item = item. map_attrs ( |mut attrs| {
877- if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs) {
884+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
885+ true ) {
878886 attr = Some ( legacy_attr_invoc) ;
879887 return attrs;
880888 }
@@ -889,6 +897,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
889897 ( attr, traits, item)
890898 }
891899
900+ /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
901+ /// to the unused-attributes lint (making it an error on statements and expressions
902+ /// is a breaking change)
903+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
904+ let mut attr = None ;
905+
906+ item = item. map_attrs ( |mut attrs| {
907+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
908+ false ) {
909+ attr = Some ( legacy_attr_invoc) ;
910+ return attrs;
911+ }
912+
913+ if self . cx . ecfg . proc_macro_enabled ( ) {
914+ attr = find_attr_invoc ( & mut attrs) ;
915+ }
916+ attrs
917+ } ) ;
918+
919+ ( attr, item)
920+ }
921+
892922 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
893923 self . cfg . configure ( node)
894924 }
@@ -899,6 +929,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
899929 let features = self . cx . ecfg . features . unwrap ( ) ;
900930 for attr in attrs. iter ( ) {
901931 feature_gate:: check_attribute ( attr, self . cx . parse_sess , features) ;
932+
933+ // macros are expanded before any lint passes so this warning has to be hardcoded
934+ if attr. path == "derive" {
935+ self . cx . struct_span_warn ( attr. span , "`#[derive]` does nothing on macro invocations" )
936+ . note ( "this may become a hard error in a future release" )
937+ . emit ( ) ;
938+ }
902939 }
903940 }
904941
@@ -919,15 +956,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
919956 let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
920957 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
921958
922- let ( attr, derives, expr) = self . classify_item ( expr) ;
959+ // ignore derives so they remain unused
960+ let ( attr, expr) = self . classify_nonitem ( expr) ;
923961
924- if attr. is_some ( ) || !derives . is_empty ( ) {
962+ if attr. is_some ( ) {
925963 // collect the invoc regardless of whether or not attributes are permitted here
926964 // expansion will eat the attribute so it won't error later
927965 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
928966
929967 // ExpansionKind::Expr requires the macro to emit an expression
930- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
968+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
931969 . make_expr ( ) ;
932970 }
933971
@@ -943,12 +981,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
943981 let mut expr = configure ! ( self , expr) . into_inner ( ) ;
944982 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
945983
946- let ( attr, derives, expr) = self . classify_item ( expr) ;
984+ // ignore derives so they remain unused
985+ let ( attr, expr) = self . classify_nonitem ( expr) ;
947986
948- if attr. is_some ( ) || !derives . is_empty ( ) {
987+ if attr. is_some ( ) {
949988 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
950989
951- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
990+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
952991 ExpansionKind :: OptExpr )
953992 . make_opt_expr ( ) ;
954993 }
@@ -982,7 +1021,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
9821021
9831022 // we'll expand attributes on expressions separately
9841023 if !stmt. is_expr ( ) {
985- let ( attr, derives, stmt_) = self . classify_item ( stmt) ;
1024+ let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1025+ self . classify_item ( stmt)
1026+ } else {
1027+ // ignore derives on non-item statements so it falls through
1028+ // to the unused-attributes lint
1029+ let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1030+ ( attr, vec ! [ ] , stmt)
1031+ } ;
9861032
9871033 if attr. is_some ( ) || !derives. is_empty ( ) {
9881034 return self . collect_attr ( attr, derives,
0 commit comments