@@ -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
}
@@ -956,14 +963,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
956
963
self . collect ( kind, InvocationKind :: Attr { attr, traits, item } )
957
964
}
958
965
959
- // If `item` is an attr invocation, remove and return the macro attribute.
966
+ /// If `item` is an attr invocation, remove and return the macro attribute and derive traits .
960
967
fn classify_item < T > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , Vec < Path > , T )
961
968
where T : HasAttrs ,
962
969
{
963
970
let ( mut attr, mut traits) = ( None , Vec :: new ( ) ) ;
964
971
965
972
item = item. map_attrs ( |mut attrs| {
966
- if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs) {
973
+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
974
+ true ) {
967
975
attr = Some ( legacy_attr_invoc) ;
968
976
return attrs;
969
977
}
@@ -978,6 +986,28 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
978
986
( attr, traits, item)
979
987
}
980
988
989
+ /// Alternative of `classify_item()` that ignores `#[derive]` so invocations fallthrough
990
+ /// to the unused-attributes lint (making it an error on statements and expressions
991
+ /// is a breaking change)
992
+ fn classify_nonitem < T : HasAttrs > ( & mut self , mut item : T ) -> ( Option < ast:: Attribute > , T ) {
993
+ let mut attr = None ;
994
+
995
+ item = item. map_attrs ( |mut attrs| {
996
+ if let Some ( legacy_attr_invoc) = self . cx . resolver . find_legacy_attr_invoc ( & mut attrs,
997
+ false ) {
998
+ attr = Some ( legacy_attr_invoc) ;
999
+ return attrs;
1000
+ }
1001
+
1002
+ if self . cx . ecfg . proc_macro_enabled ( ) {
1003
+ attr = find_attr_invoc ( & mut attrs) ;
1004
+ }
1005
+ attrs
1006
+ } ) ;
1007
+
1008
+ ( attr, item)
1009
+ }
1010
+
981
1011
fn configure < T : HasAttrs > ( & mut self , node : T ) -> Option < T > {
982
1012
self . cfg . configure ( node)
983
1013
}
@@ -988,6 +1018,13 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
988
1018
let features = self . cx . ecfg . features . unwrap ( ) ;
989
1019
for attr in attrs. iter ( ) {
990
1020
feature_gate:: check_attribute ( attr, self . cx . parse_sess , features) ;
1021
+
1022
+ // macros are expanded before any lint passes so this warning has to be hardcoded
1023
+ if attr. path == "derive" {
1024
+ self . cx . struct_span_warn ( attr. span , "`#[derive]` does nothing on macro invocations" )
1025
+ . note ( "this may become a hard error in a future release" )
1026
+ . emit ( ) ;
1027
+ }
991
1028
}
992
1029
}
993
1030
@@ -1008,15 +1045,16 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1008
1045
let mut expr = self . cfg . configure_expr ( expr) . into_inner ( ) ;
1009
1046
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
1010
1047
1011
- let ( attr, derives, expr) = self . classify_item ( expr) ;
1048
+ // ignore derives so they remain unused
1049
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
1012
1050
1013
- if attr. is_some ( ) || !derives . is_empty ( ) {
1051
+ if attr. is_some ( ) {
1014
1052
// collect the invoc regardless of whether or not attributes are permitted here
1015
1053
// expansion will eat the attribute so it won't error later
1016
1054
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
1017
1055
1018
1056
// ExpansionKind::Expr requires the macro to emit an expression
1019
- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
1057
+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) , ExpansionKind :: Expr )
1020
1058
. make_expr ( ) ;
1021
1059
}
1022
1060
@@ -1032,12 +1070,13 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1032
1070
let mut expr = configure ! ( self , expr) . into_inner ( ) ;
1033
1071
expr. node = self . cfg . configure_expr_kind ( expr. node ) ;
1034
1072
1035
- let ( attr, derives, expr) = self . classify_item ( expr) ;
1073
+ // ignore derives so they remain unused
1074
+ let ( attr, expr) = self . classify_nonitem ( expr) ;
1036
1075
1037
- if attr. is_some ( ) || !derives . is_empty ( ) {
1076
+ if attr. is_some ( ) {
1038
1077
attr. as_ref ( ) . map ( |a| self . cfg . maybe_emit_expr_attr_err ( a) ) ;
1039
1078
1040
- return self . collect_attr ( attr, derives , Annotatable :: Expr ( P ( expr) ) ,
1079
+ return self . collect_attr ( attr, vec ! [ ] , Annotatable :: Expr ( P ( expr) ) ,
1041
1080
ExpansionKind :: OptExpr )
1042
1081
. make_opt_expr ( ) ;
1043
1082
}
@@ -1071,7 +1110,14 @@ impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
1071
1110
1072
1111
// we'll expand attributes on expressions separately
1073
1112
if !stmt. is_expr ( ) {
1074
- let ( attr, derives, stmt_) = self . classify_item ( stmt) ;
1113
+ let ( attr, derives, stmt_) = if stmt. is_item ( ) {
1114
+ self . classify_item ( stmt)
1115
+ } else {
1116
+ // ignore derives on non-item statements so it falls through
1117
+ // to the unused-attributes lint
1118
+ let ( attr, stmt) = self . classify_nonitem ( stmt) ;
1119
+ ( attr, vec ! [ ] , stmt)
1120
+ } ;
1075
1121
1076
1122
if attr. is_some ( ) || !derives. is_empty ( ) {
1077
1123
return self . collect_attr ( attr, derives,
0 commit comments