@@ -5,7 +5,7 @@ use rustc_ast::attr;
5
5
use rustc_ast:: unwrap_or;
6
6
use rustc_ast_pretty:: pprust;
7
7
use rustc_data_structures:: fx:: FxHashMap ;
8
- use rustc_errors:: { struct_span_err, Applicability } ;
8
+ use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
9
9
use rustc_hir as hir;
10
10
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
11
11
use rustc_hir:: { intravisit, HirId } ;
@@ -17,11 +17,15 @@ use rustc_middle::lint::{
17
17
} ;
18
18
use rustc_middle:: ty:: query:: Providers ;
19
19
use rustc_middle:: ty:: TyCtxt ;
20
- use rustc_session:: lint:: { builtin, Level , Lint , LintId } ;
20
+ use rustc_session:: lint:: {
21
+ builtin:: { self , FORBIDDEN_LINT_GROUPS } ,
22
+ Level , Lint , LintId ,
23
+ } ;
21
24
use rustc_session:: parse:: feature_err;
22
25
use rustc_session:: Session ;
23
26
use rustc_span:: symbol:: { sym, Symbol } ;
24
27
use rustc_span:: { source_map:: MultiSpan , Span , DUMMY_SP } ;
28
+ use tracing:: debug;
25
29
26
30
use std:: cmp;
27
31
@@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> {
51
55
id_to_set : FxHashMap < HirId , u32 > ,
52
56
cur : u32 ,
53
57
warn_about_weird_lints : bool ,
58
+ store : & ' s LintStore ,
54
59
}
55
60
56
61
pub struct BuilderPush {
@@ -59,13 +64,14 @@ pub struct BuilderPush {
59
64
}
60
65
61
66
impl < ' s > LintLevelsBuilder < ' s > {
62
- pub fn new ( sess : & ' s Session , warn_about_weird_lints : bool , store : & LintStore ) -> Self {
67
+ pub fn new ( sess : & ' s Session , warn_about_weird_lints : bool , store : & ' s LintStore ) -> Self {
63
68
let mut builder = LintLevelsBuilder {
64
69
sess,
65
70
sets : LintLevelSets :: new ( ) ,
66
71
cur : 0 ,
67
72
id_to_set : Default :: default ( ) ,
68
73
warn_about_weird_lints,
74
+ store,
69
75
} ;
70
76
builder. process_command_line ( sess, store) ;
71
77
assert_eq ! ( builder. sets. list. len( ) , 1 ) ;
@@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> {
120
126
if let ( Level :: Forbid , old_src) =
121
127
self . sets . get_lint_level ( id. lint , self . cur , Some ( & specs) , & self . sess )
122
128
{
123
- let mut diag_builder = struct_span_err ! (
124
- self . sess,
125
- src. span( ) ,
126
- E0453 ,
127
- "{}({}) incompatible with previous forbid" ,
128
- level. as_str( ) ,
129
- src. name( ) ,
129
+ // Backwards compatibility check:
130
+ //
131
+ // We used to not consider `forbid(lint_group)`
132
+ // as preventing `allow(lint)` for some lint `lint` in
133
+ // `lint_group`. For now, issue a future-compatibility
134
+ // warning for this case.
135
+ let id_name = id. lint . name_lower ( ) ;
136
+ let fcw_warning = match old_src {
137
+ LintLevelSource :: Default => false ,
138
+ LintLevelSource :: Node ( symbol, _, _) => self . store . is_lint_group ( symbol) ,
139
+ LintLevelSource :: CommandLine ( symbol, _) => self . store . is_lint_group ( symbol) ,
140
+ } ;
141
+ debug ! (
142
+ "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}" ,
143
+ fcw_warning, specs, old_src, id_name
130
144
) ;
131
- diag_builder. span_label ( src. span ( ) , "overruled by previous forbid" ) ;
132
- match old_src {
133
- LintLevelSource :: Default => {
134
- diag_builder. note ( & format ! (
135
- "`forbid` lint level is the default for {}" ,
136
- id. to_string( )
137
- ) ) ;
138
- }
139
- LintLevelSource :: Node ( _, forbid_source_span, reason) => {
140
- diag_builder. span_label ( forbid_source_span, "`forbid` level set here" ) ;
141
- if let Some ( rationale) = reason {
142
- diag_builder. note ( & rationale. as_str ( ) ) ;
145
+
146
+ let decorate_diag_builder = |mut diag_builder : DiagnosticBuilder < ' _ > | {
147
+ diag_builder. span_label ( src. span ( ) , "overruled by previous forbid" ) ;
148
+ match old_src {
149
+ LintLevelSource :: Default => {
150
+ diag_builder. note ( & format ! (
151
+ "`forbid` lint level is the default for {}" ,
152
+ id. to_string( )
153
+ ) ) ;
154
+ }
155
+ LintLevelSource :: Node ( _, forbid_source_span, reason) => {
156
+ diag_builder. span_label ( forbid_source_span, "`forbid` level set here" ) ;
157
+ if let Some ( rationale) = reason {
158
+ diag_builder. note ( & rationale. as_str ( ) ) ;
159
+ }
160
+ }
161
+ LintLevelSource :: CommandLine ( _, _) => {
162
+ diag_builder. note ( "`forbid` lint level was set on command line" ) ;
143
163
}
144
164
}
145
- LintLevelSource :: CommandLine ( _, _) => {
146
- diag_builder. note ( "`forbid` lint level was set on command line" ) ;
147
- }
165
+ diag_builder. emit ( ) ;
166
+ } ;
167
+ if !fcw_warning {
168
+ let diag_builder = struct_span_err ! (
169
+ self . sess,
170
+ src. span( ) ,
171
+ E0453 ,
172
+ "{}({}) incompatible with previous forbid" ,
173
+ level. as_str( ) ,
174
+ src. name( ) ,
175
+ ) ;
176
+ decorate_diag_builder ( diag_builder) ;
177
+ } else {
178
+ self . struct_lint (
179
+ FORBIDDEN_LINT_GROUPS ,
180
+ Some ( src. span ( ) . into ( ) ) ,
181
+ |diag_builder| {
182
+ let diag_builder = diag_builder. build ( & format ! (
183
+ "{}({}) incompatible with previous forbid" ,
184
+ level. as_str( ) ,
185
+ src. name( ) ,
186
+ ) ) ;
187
+ decorate_diag_builder ( diag_builder) ;
188
+ } ,
189
+ ) ;
148
190
}
149
- diag_builder. emit ( ) ;
150
191
151
- // Retain the forbid lint level
152
- return ;
192
+ // Retain the forbid lint level, unless we are
193
+ // issuing a FCW. In the FCW case, we want to
194
+ // respect the new setting.
195
+ if !fcw_warning {
196
+ return ;
197
+ }
153
198
}
154
199
}
155
200
specs. insert ( id, ( level, src) ) ;
0 commit comments