@@ -20,8 +20,11 @@ use rustc_middle::ty::TyCtxt;
20
20
use rustc_session:: lint:: { builtin, Level , Lint , LintId } ;
21
21
use rustc_session:: parse:: feature_err;
22
22
use rustc_session:: Session ;
23
- use rustc_span:: symbol:: { sym, Symbol } ;
24
23
use rustc_span:: { source_map:: MultiSpan , Span , DUMMY_SP } ;
24
+ use rustc_span:: {
25
+ symbol:: { sym, Symbol } ,
26
+ ExpnId ,
27
+ } ;
25
28
26
29
use std:: cmp;
27
30
@@ -58,6 +61,15 @@ pub struct BuilderPush {
58
61
pub changed : bool ,
59
62
}
60
63
64
+ /// Returns true when a lint level can override a previously set forbid.
65
+ fn can_overrule_forbidden ( span : Span , expn : Option < ExpnId > ) -> bool {
66
+ if let Some ( expn_id) = expn {
67
+ !span. in_derive_expansion ( ) || span. ctxt ( ) . outer_expn ( ) != expn_id
68
+ } else {
69
+ false
70
+ }
71
+ }
72
+
61
73
impl < ' s > LintLevelsBuilder < ' s > {
62
74
pub fn new ( sess : & ' s Session , warn_about_weird_lints : bool , store : & LintStore ) -> Self {
63
75
let mut builder = LintLevelsBuilder {
@@ -109,16 +121,23 @@ impl<'s> LintLevelsBuilder<'s> {
109
121
specs : & mut FxHashMap < LintId , LevelAndSource > ,
110
122
id : LintId ,
111
123
( level, src) : LevelAndSource ,
124
+ derive_expansion : Option < ExpnId > ,
112
125
) {
113
126
// Setting to a non-forbid level is an error if the lint previously had
114
127
// a forbid level. Note that this is not necessarily true even with a
115
128
// `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
116
129
//
117
130
// This means that this only errors if we're truly lowering the lint
118
131
// level from forbid.
132
+ //
133
+ // An exception to this is when the lint comes from a different derive macro
134
+ // expansion than the previous forbid level.
119
135
if level != Level :: Forbid {
120
- if let ( Level :: Forbid , old_src) =
121
- self . sets . get_lint_level ( id. lint , self . cur , Some ( & specs) , & self . sess )
136
+ let ( old_level, old_src) =
137
+ self . sets . get_lint_level ( id. lint , self . cur , Some ( & specs) , & self . sess ) ;
138
+
139
+ if old_level == Level :: Forbid
140
+ && !can_overrule_forbidden ( old_src. span ( ) , derive_expansion)
122
141
{
123
142
let mut diag_builder = struct_span_err ! (
124
143
self . sess,
@@ -178,7 +197,13 @@ impl<'s> LintLevelsBuilder<'s> {
178
197
let mut specs = FxHashMap :: default ( ) ;
179
198
let sess = self . sess ;
180
199
let bad_attr = |span| struct_span_err ! ( sess, span, E0452 , "malformed lint attribute input" ) ;
200
+
181
201
for attr in attrs {
202
+ let derive_expansion = if attr. span . in_derive_expansion ( ) {
203
+ Some ( attr. span . ctxt ( ) . outer_expn ( ) )
204
+ } else {
205
+ None
206
+ } ;
182
207
let level = match Level :: from_symbol ( attr. name_or_empty ( ) ) {
183
208
None => continue ,
184
209
Some ( lvl) => lvl,
@@ -281,7 +306,7 @@ impl<'s> LintLevelsBuilder<'s> {
281
306
let src = LintLevelSource :: Node ( name, li. span ( ) , reason) ;
282
307
for & id in ids {
283
308
self . check_gated_lint ( id, attr. span ) ;
284
- self . insert_spec ( & mut specs, id, ( level, src) ) ;
309
+ self . insert_spec ( & mut specs, id, ( level, src) , derive_expansion ) ;
285
310
}
286
311
}
287
312
@@ -295,7 +320,12 @@ impl<'s> LintLevelsBuilder<'s> {
295
320
reason,
296
321
) ;
297
322
for id in ids {
298
- self . insert_spec ( & mut specs, * id, ( level, src) ) ;
323
+ self . insert_spec (
324
+ & mut specs,
325
+ * id,
326
+ ( level, src) ,
327
+ derive_expansion,
328
+ ) ;
299
329
}
300
330
}
301
331
Err ( ( Some ( ids) , new_lint_name) ) => {
@@ -332,7 +362,12 @@ impl<'s> LintLevelsBuilder<'s> {
332
362
reason,
333
363
) ;
334
364
for id in ids {
335
- self . insert_spec ( & mut specs, * id, ( level, src) ) ;
365
+ self . insert_spec (
366
+ & mut specs,
367
+ * id,
368
+ ( level, src) ,
369
+ derive_expansion,
370
+ ) ;
336
371
}
337
372
}
338
373
Err ( ( None , _) ) => {
0 commit comments