@@ -141,15 +141,24 @@ 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 :: ForeignItems =>
153+ Expansion :: ForeignItems ( items. map ( Annotatable :: expect_foreign_item) . collect ( ) ) ,
154+ ExpansionKind :: Stmts => Expansion :: Stmts ( items. map ( Annotatable :: expect_stmt) . collect ( ) ) ,
155+ ExpansionKind :: Expr => Expansion :: Expr (
156+ items. next ( ) . expect ( "expected exactly one expression" ) . expect_expr ( )
157+ ) ,
158+ ExpansionKind :: OptExpr =>
159+ Expansion :: OptExpr ( items. next ( ) . map ( Annotatable :: expect_expr) ) ,
160+ ExpansionKind :: Pat | ExpansionKind :: Ty =>
161+ panic ! ( "patterns and types aren't annotatable" ) ,
153162 }
154163 }
155164}
@@ -867,14 +876,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
867876 self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
868877 }
869878
870- // If `item` is an attr invocation, remove and return the macro attribute.
879+ /// If `item` is an attr invocation, remove and return the macro attribute and derive traits .
871880 fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
872881 where T : HasAttrs ,
873882 {
874883 let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
875884
876885 item = item. map_attrs ( |mut attrs| {
877- if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs) {
886+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
887+ true ) {
878888 attr = Some ( legacy_attr_invoc) ;
879889 return attrs;
880890 }
@@ -889,6 +899,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
889899 ( attr, traits, item)
890900 }
891901
902+ /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
903+ /// to the unused-attributes lint (making it an error on statements and expressions
904+ /// is a breaking change)
905+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
906+ let mut attr = None ;
907+
908+ item = item. map_attrs ( |mut attrs| {
909+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
910+ false ) {
911+ attr = Some ( legacy_attr_invoc) ;
912+ return attrs;
913+ }
914+
915+ if self . cx . ecfg . proc_macro_enabled ( ) {
916+ attr = find_attr_invoc ( & mut attrs) ;
917+ }
918+ attrs
919+ } ) ;
920+
921+ ( attr, item)
922+ }
923+
892924 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
893925 self . cfg . configure ( node)
894926 }
@@ -899,6 +931,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
899931 let features = self . cx . ecfg . features . unwrap ( ) ;
900932 for attr in attrs. iter ( ) {
901933 feature_gate:: check_attribute ( attr, self . cx . parse_sess , features) ;
934+
935+ // macros are expanded before any lint passes so this warning has to be hardcoded
936+ if attr. path == "derive" {
937+ self . cx . struct_span_warn ( attr. span , "`#[derive]` does nothing on macro invocations" )
938+ . note ( "this may become a hard error in a future release" )
939+ . emit ( ) ;
940+ }
902941 }
903942 }
904943
@@ -919,15 +958,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
919958 let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
920959 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
921960
922- let ( attr, derives, expr) = self . classify_item ( expr) ;
961+ // ignore derives so they remain unused
962+ let ( attr, expr) = self . classify_nonitem ( expr) ;
923963
924- if attr. is_some ( ) || !derives . is_empty ( ) {
964+ if attr. is_some ( ) {
925965 // collect the invoc regardless of whether or not attributes are permitted here
926966 // expansion will eat the attribute so it won't error later
927967 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
928968
929969 // ExpansionKind::Expr requires the macro to emit an expression
930- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
970+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
931971 . make_expr ( ) ;
932972 }
933973
@@ -943,12 +983,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
943983 let mut expr = configure ! ( self , expr) . into_inner ( ) ;
944984 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
945985
946- let ( attr, derives, expr) = self . classify_item ( expr) ;
986+ // ignore derives so they remain unused
987+ let ( attr, expr) = self . classify_nonitem ( expr) ;
947988
948- if attr. is_some ( ) || !derives . is_empty ( ) {
989+ if attr. is_some ( ) {
949990 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
950991
951- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
992+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
952993 ExpansionKind :: OptExpr )
953994 . make_opt_expr ( ) ;
954995 }
@@ -982,7 +1023,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
9821023
9831024 // we'll expand attributes on expressions separately
9841025 if !stmt. is_expr ( ) {
985- let ( attr, derives, stmt_) = self . classify_item ( stmt) ;
1026+ let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1027+ self . classify_item ( stmt)
1028+ } else {
1029+ // ignore derives on non-item statements so it falls through
1030+ // to the unused-attributes lint
1031+ let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1032+ ( attr, vec ! [ ] , stmt)
1033+ } ;
9861034
9871035 if attr. is_some ( ) || !derives. is_empty ( ) {
9881036 return self . collect_attr ( attr, derives,
0 commit comments