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