@@ -143,7 +143,7 @@ impl ExpansionKind {
143
143
}
144
144
145
145
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 ( ) ;
147
147
match self {
148
148
ExpansionKind :: Items =>
149
149
Expansion :: Items ( items. map ( Annotatable :: expect_item) . collect ( ) ) ,
@@ -153,7 +153,14 @@ impl ExpansionKind {
153
153
Expansion :: TraitItems ( items. map ( Annotatable :: expect_trait_item) . collect ( ) ) ,
154
154
ExpansionKind :: ForeignItems =>
155
155
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" ) ,
157
164
}
158
165
}
159
166
}
@@ -886,14 +893,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
886
893
self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
887
894
}
888
895
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 .
890
897
fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
891
898
where T : HasAttrs ,
892
899
{
893
900
let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
894
901
895
902
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 ) {
897
905
attr = Some ( legacy_attr_invoc) ;
898
906
return attrs;
899
907
}
@@ -908,6 +916,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
908
916
( attr, traits, item)
909
917
}
910
918
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
+
911
941
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
912
942
self . cfg . configure ( node)
913
943
}
@@ -918,6 +948,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
918
948
let features = self . cx . ecfg . features . unwrap ( ) ;
919
949
for attr in attrs. iter ( ) {
920
950
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
+ }
921
958
}
922
959
}
923
960
@@ -938,15 +975,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
938
975
let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
939
976
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
940
977
941
- let ( attr, derives, expr) = self . classify_item ( expr) ;
978
+ // ignore derives so they remain unused
979
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
942
980
943
- if attr. is_some ( ) || !derives . is_empty ( ) {
981
+ if attr. is_some ( ) {
944
982
// collect the invoc regardless of whether or not attributes are permitted here
945
983
// expansion will eat the attribute so it won't error later
946
984
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
947
985
948
986
// 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 )
950
988
. make_expr ( ) ;
951
989
}
952
990
@@ -962,12 +1000,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
962
1000
let mut expr = configure ! ( self , expr) . into_inner ( ) ;
963
1001
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
964
1002
965
- let ( attr, derives, expr) = self . classify_item ( expr) ;
1003
+ // ignore derives so they remain unused
1004
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
966
1005
967
- if attr. is_some ( ) || !derives . is_empty ( ) {
1006
+ if attr. is_some ( ) {
968
1007
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
969
1008
970
- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
1009
+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
971
1010
ExpansionKind :: OptExpr )
972
1011
. make_opt_expr ( ) ;
973
1012
}
@@ -1001,7 +1040,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1001
1040
1002
1041
// we'll expand attributes on expressions separately
1003
1042
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
+ } ;
1005
1051
1006
1052
if attr. is_some ( ) || !derives. is_empty ( ) {
1007
1053
return self . collect_attr ( attr, derives,
0 commit comments