@@ -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}
@@ -886,14 +893,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
886893 self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
887894 }
888895
889- // If `item` is an attr invocation, remove and return the macro attribute.
896+ /// If `item` is an attr invocation, remove and return the macro attribute and derive traits .
890897 fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
891898 where T : HasAttrs ,
892899 {
893900 let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
894901
895902 item = item. map_attrs ( |mut attrs| {
896- if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs) {
903+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
904+ true ) {
897905 attr = Some ( legacy_attr_invoc) ;
898906 return attrs;
899907 }
@@ -908,6 +916,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
908916 ( attr, traits, item)
909917 }
910918
919+ /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
920+ /// to the unused-attributes lint (making it an error on statements and expressions
921+ /// is a breaking change)
922+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
923+ let mut attr = None ;
924+
925+ item = item. map_attrs ( |mut attrs| {
926+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
927+ false ) {
928+ attr = Some ( legacy_attr_invoc) ;
929+ return attrs;
930+ }
931+
932+ if self . cx . ecfg . proc_macro_enabled ( ) {
933+ attr = find_attr_invoc ( & mut attrs) ;
934+ }
935+ attrs
936+ } ) ;
937+
938+ ( attr, item)
939+ }
940+
911941 fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
912942 self . cfg . configure ( node)
913943 }
@@ -918,6 +948,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
918948 let features = self . cx . ecfg . features . unwrap ( ) ;
919949 for attr in attrs. iter ( ) {
920950 feature_gate:: check_attribute ( attr, self . cx . parse_sess , features) ;
951+
952+ // macros are expanded before any lint passes so this warning has to be hardcoded
953+ if attr. path == "derive" {
954+ self . cx . struct_span_warn ( attr. span , "`#[derive]` does nothing on macro invocations" )
955+ . note ( "this may become a hard error in a future release" )
956+ . emit ( ) ;
957+ }
921958 }
922959 }
923960
@@ -938,15 +975,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
938975 let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
939976 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
940977
941- let ( attr, derives, expr) = self . classify_item ( expr) ;
978+ // ignore derives so they remain unused
979+ let ( attr, expr) = self . classify_nonitem ( expr) ;
942980
943- if attr. is_some ( ) || !derives . is_empty ( ) {
981+ if attr. is_some ( ) {
944982 // collect the invoc regardless of whether or not attributes are permitted here
945983 // expansion will eat the attribute so it won't error later
946984 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
947985
948986 // ExpansionKind::Expr requires the macro to emit an expression
949- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
987+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
950988 . make_expr ( ) ;
951989 }
952990
@@ -962,12 +1000,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
9621000 let mut expr = configure ! ( self , expr) . into_inner ( ) ;
9631001 expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
9641002
965- let ( attr, derives, expr) = self . classify_item ( expr) ;
1003+ // ignore derives so they remain unused
1004+ let ( attr, expr) = self . classify_nonitem ( expr) ;
9661005
967- if attr. is_some ( ) || !derives . is_empty ( ) {
1006+ if attr. is_some ( ) {
9681007 attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
9691008
970- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
1009+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
9711010 ExpansionKind :: OptExpr )
9721011 . make_opt_expr ( ) ;
9731012 }
@@ -1001,7 +1040,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
10011040
10021041 // we'll expand attributes on expressions separately
10031042 if !stmt. is_expr ( ) {
1004- let ( attr, derives, stmt_) = self . classify_item ( stmt) ;
1043+ let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1044+ self . classify_item ( stmt)
1045+ } else {
1046+ // ignore derives on non-item statements so it falls through
1047+ // to the unused-attributes lint
1048+ let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1049+ ( attr, vec ! [ ] , stmt)
1050+ } ;
10051051
10061052 if attr. is_some ( ) || !derives. is_empty ( ) {
10071053 return self . collect_attr ( attr, derives,
0 commit comments