@@ -5,7 +5,7 @@ use rustc_ast::attr;
55use rustc_ast:: unwrap_or;
66use rustc_ast_pretty:: pprust;
77use rustc_data_structures:: fx:: FxHashMap ;
8- use rustc_errors:: { struct_span_err, Applicability } ;
8+ use rustc_errors:: { struct_span_err, Applicability , DiagnosticBuilder } ;
99use rustc_hir as hir;
1010use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
1111use rustc_hir:: { intravisit, HirId } ;
@@ -17,11 +17,15 @@ use rustc_middle::lint::{
1717} ;
1818use rustc_middle:: ty:: query:: Providers ;
1919use 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+ } ;
2124use rustc_session:: parse:: feature_err;
2225use rustc_session:: Session ;
2326use rustc_span:: symbol:: { sym, Symbol } ;
2427use rustc_span:: { source_map:: MultiSpan , Span , DUMMY_SP } ;
28+ use tracing:: debug;
2529
2630use std:: cmp;
2731
@@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> {
5155 id_to_set : FxHashMap < HirId , u32 > ,
5256 cur : u32 ,
5357 warn_about_weird_lints : bool ,
58+ store : & ' s LintStore ,
5459}
5560
5661pub struct BuilderPush {
@@ -59,13 +64,14 @@ pub struct BuilderPush {
5964}
6065
6166impl < ' 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 {
6368 let mut builder = LintLevelsBuilder {
6469 sess,
6570 sets : LintLevelSets :: new ( ) ,
6671 cur : 0 ,
6772 id_to_set : Default :: default ( ) ,
6873 warn_about_weird_lints,
74+ store,
6975 } ;
7076 builder. process_command_line ( sess, store) ;
7177 assert_eq ! ( builder. sets. list. len( ) , 1 ) ;
@@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> {
120126 if let ( Level :: Forbid , old_src) =
121127 self . sets . get_lint_level ( id. lint , self . cur , Some ( & specs) , & self . sess )
122128 {
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
130144 ) ;
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" ) ;
143163 }
144164 }
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+ ) ;
148190 }
149- diag_builder. emit ( ) ;
150191
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+ }
153198 }
154199 }
155200 specs. insert ( id, ( level, src) ) ;
0 commit comments