@@ -10,6 +10,7 @@ use rustc_hir as hir;
1010use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
1111use rustc_hir:: { intravisit, HirId } ;
1212use rustc_middle:: hir:: map:: Map ;
13+ use rustc_middle:: lint:: LevelSource ;
1314use rustc_middle:: lint:: LintDiagnosticBuilder ;
1415use rustc_middle:: lint:: { struct_lint_level, LintLevelMap , LintLevelSets , LintSet , LintSource } ;
1516use rustc_middle:: ty:: query:: Providers ;
@@ -95,6 +96,44 @@ impl<'s> LintLevelsBuilder<'s> {
9596 self . sets . list . push ( LintSet :: CommandLine { specs } ) ;
9697 }
9798
99+ /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
100+ /// (e.g. if a forbid was already inserted on the same scope), then emits a
101+ /// diagnostic with no change to `specs`.
102+ fn insert_spec (
103+ & mut self ,
104+ specs : & mut FxHashMap < LintId , LevelSource > ,
105+ id : LintId ,
106+ ( level, src) : LevelSource ,
107+ ) {
108+ if let Some ( ( old_level, old_src) ) = specs. get ( & id) {
109+ if old_level == & Level :: Forbid && level != Level :: Forbid {
110+ let mut diag_builder = struct_span_err ! (
111+ self . sess,
112+ src. span( ) ,
113+ E0453 ,
114+ "{}({}) incompatible with previous forbid in same scope" ,
115+ level. as_str( ) ,
116+ src. name( ) ,
117+ ) ;
118+ match * old_src {
119+ LintSource :: Default => { }
120+ LintSource :: Node ( _, forbid_source_span, reason) => {
121+ diag_builder. span_label ( forbid_source_span, "`forbid` level set here" ) ;
122+ if let Some ( rationale) = reason {
123+ diag_builder. note ( & rationale. as_str ( ) ) ;
124+ }
125+ }
126+ LintSource :: CommandLine ( _) => {
127+ diag_builder. note ( "`forbid` lint level was set on command line" ) ;
128+ }
129+ }
130+ diag_builder. emit ( ) ;
131+ return ;
132+ }
133+ }
134+ specs. insert ( id, ( level, src) ) ;
135+ }
136+
98137 /// Pushes a list of AST lint attributes onto this context.
99138 ///
100139 /// This function will return a `BuilderPush` object which should be passed
@@ -109,7 +148,7 @@ impl<'s> LintLevelsBuilder<'s> {
109148 /// `#[allow]`
110149 ///
111150 /// Don't forget to call `pop`!
112- pub fn push (
151+ pub ( crate ) fn push (
113152 & mut self ,
114153 attrs : & [ ast:: Attribute ] ,
115154 store : & LintStore ,
@@ -221,7 +260,7 @@ impl<'s> LintLevelsBuilder<'s> {
221260 let src = LintSource :: Node ( name, li. span ( ) , reason) ;
222261 for & id in ids {
223262 self . check_gated_lint ( id, attr. span ) ;
224- specs . insert ( id, ( level, src) ) ;
263+ self . insert_spec ( & mut specs , id, ( level, src) ) ;
225264 }
226265 }
227266
@@ -235,7 +274,7 @@ impl<'s> LintLevelsBuilder<'s> {
235274 reason,
236275 ) ;
237276 for id in ids {
238- specs . insert ( * id, ( level, src) ) ;
277+ self . insert_spec ( & mut specs , * id, ( level, src) ) ;
239278 }
240279 }
241280 Err ( ( Some ( ids) , new_lint_name) ) => {
@@ -272,7 +311,7 @@ impl<'s> LintLevelsBuilder<'s> {
272311 reason,
273312 ) ;
274313 for id in ids {
275- specs . insert ( * id, ( level, src) ) ;
314+ self . insert_spec ( & mut specs , * id, ( level, src) ) ;
276315 }
277316 }
278317 Err ( ( None , _) ) => {
0 commit comments