@@ -141,15 +141,22 @@ impl ExpansionKind {
141
141
}
142
142
143
143
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 ( ) ;
145
145
match self {
146
146
ExpansionKind :: Items =>
147
147
Expansion :: Items ( items. map ( Annotatable :: expect_item) . collect ( ) ) ,
148
148
ExpansionKind :: ImplItems =>
149
149
Expansion :: ImplItems ( items. map ( Annotatable :: expect_impl_item) . collect ( ) ) ,
150
150
ExpansionKind :: TraitItems =>
151
151
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" ) ,
153
160
}
154
161
}
155
162
}
@@ -867,14 +874,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
867
874
self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
868
875
}
869
876
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 .
871
878
fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
872
879
where T : HasAttrs ,
873
880
{
874
881
let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
875
882
876
883
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 ) {
878
886
attr = Some ( legacy_attr_invoc) ;
879
887
return attrs;
880
888
}
@@ -889,6 +897,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
889
897
( attr, traits, item)
890
898
}
891
899
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
+
892
922
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
893
923
self . cfg . configure ( node)
894
924
}
@@ -899,6 +929,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
899
929
let features = self . cx . ecfg . features . unwrap ( ) ;
900
930
for attr in attrs. iter ( ) {
901
931
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
+ }
902
939
}
903
940
}
904
941
@@ -919,15 +956,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
919
956
let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
920
957
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
921
958
922
- let ( attr, derives, expr) = self . classify_item ( expr) ;
959
+ // ignore derives so they remain unused
960
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
923
961
924
- if attr. is_some ( ) || !derives . is_empty ( ) {
962
+ if attr. is_some ( ) {
925
963
// collect the invoc regardless of whether or not attributes are permitted here
926
964
// expansion will eat the attribute so it won't error later
927
965
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
928
966
929
967
// 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 )
931
969
. make_expr ( ) ;
932
970
}
933
971
@@ -943,12 +981,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
943
981
let mut expr = configure ! ( self , expr) . into_inner ( ) ;
944
982
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
945
983
946
- let ( attr, derives, expr) = self . classify_item ( expr) ;
984
+ // ignore derives so they remain unused
985
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
947
986
948
- if attr. is_some ( ) || !derives . is_empty ( ) {
987
+ if attr. is_some ( ) {
949
988
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
950
989
951
- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
990
+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
952
991
ExpansionKind :: OptExpr )
953
992
. make_opt_expr ( ) ;
954
993
}
@@ -982,7 +1021,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
982
1021
983
1022
// we'll expand attributes on expressions separately
984
1023
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
+ } ;
986
1032
987
1033
if attr. is_some ( ) || !derives. is_empty ( ) {
988
1034
return self . collect_attr ( attr, derives,
0 commit comments