@@ -10,6 +10,7 @@ use rustc_hir as hir;
10
10
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
11
11
use rustc_hir:: { intravisit, HirId } ;
12
12
use rustc_middle:: hir:: map:: Map ;
13
+ use rustc_middle:: lint:: LevelSource ;
13
14
use rustc_middle:: lint:: LintDiagnosticBuilder ;
14
15
use rustc_middle:: lint:: { struct_lint_level, LintLevelMap , LintLevelSets , LintSet , LintSource } ;
15
16
use rustc_middle:: ty:: query:: Providers ;
@@ -95,6 +96,44 @@ impl<'s> LintLevelsBuilder<'s> {
95
96
self . sets . list . push ( LintSet :: CommandLine { specs } ) ;
96
97
}
97
98
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
+
98
137
/// Pushes a list of AST lint attributes onto this context.
99
138
///
100
139
/// This function will return a `BuilderPush` object which should be passed
@@ -109,7 +148,7 @@ impl<'s> LintLevelsBuilder<'s> {
109
148
/// `#[allow]`
110
149
///
111
150
/// Don't forget to call `pop`!
112
- pub fn push (
151
+ pub ( crate ) fn push (
113
152
& mut self ,
114
153
attrs : & [ ast:: Attribute ] ,
115
154
store : & LintStore ,
@@ -221,7 +260,7 @@ impl<'s> LintLevelsBuilder<'s> {
221
260
let src = LintSource :: Node ( name, li. span ( ) , reason) ;
222
261
for & id in ids {
223
262
self . check_gated_lint ( id, attr. span ) ;
224
- specs . insert ( id, ( level, src) ) ;
263
+ self . insert_spec ( & mut specs , id, ( level, src) ) ;
225
264
}
226
265
}
227
266
@@ -235,7 +274,7 @@ impl<'s> LintLevelsBuilder<'s> {
235
274
reason,
236
275
) ;
237
276
for id in ids {
238
- specs . insert ( * id, ( level, src) ) ;
277
+ self . insert_spec ( & mut specs , * id, ( level, src) ) ;
239
278
}
240
279
}
241
280
Err ( ( Some ( ids) , new_lint_name) ) => {
@@ -272,7 +311,7 @@ impl<'s> LintLevelsBuilder<'s> {
272
311
reason,
273
312
) ;
274
313
for id in ids {
275
- specs . insert ( * id, ( level, src) ) ;
314
+ self . insert_spec ( & mut specs , * id, ( level, src) ) ;
276
315
}
277
316
}
278
317
Err ( ( None , _) ) => {
0 commit comments