Skip to content

Commit 01e8e9f

Browse files
committed
When building lint specs map for a given scope, check if forbid present on each insert.
Drive-by changes: 1. make `LintLevelsBuilder::push` private to the crate. 2. Add methods to `LintSource` for extracting its name symbol or its span.
1 parent e24aa73 commit 01e8e9f

File tree

2 files changed

+62
-5
lines changed

2 files changed

+62
-5
lines changed

src/librustc_lint/levels.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use rustc_hir as hir;
1010
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
1111
use rustc_hir::{intravisit, HirId};
1212
use rustc_middle::hir::map::Map;
13+
use rustc_middle::lint::LevelSource;
1314
use rustc_middle::lint::LintDiagnosticBuilder;
1415
use rustc_middle::lint::{struct_lint_level, LintLevelMap, LintLevelSets, LintSet, LintSource};
1516
use 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, _)) => {

src/librustc_middle/lint.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_session::lint::{builtin, Level, Lint, LintId};
99
use rustc_session::{DiagnosticMessageId, Session};
1010
use rustc_span::hygiene::MacroKind;
1111
use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan};
12-
use rustc_span::{Span, Symbol};
12+
use rustc_span::{Span, Symbol, DUMMY_SP};
1313

1414
/// How a lint level was set.
1515
#[derive(Clone, Copy, PartialEq, Eq, HashStable)]
@@ -25,6 +25,24 @@ pub enum LintSource {
2525
CommandLine(Symbol),
2626
}
2727

28+
impl LintSource {
29+
pub fn name(&self) -> Symbol {
30+
match *self {
31+
LintSource::Default => Symbol::intern("default"),
32+
LintSource::Node(name, _, _) => name,
33+
LintSource::CommandLine(name) => name,
34+
}
35+
}
36+
37+
pub fn span(&self) -> Span {
38+
match *self {
39+
LintSource::Default => DUMMY_SP,
40+
LintSource::Node(_, span, _) => span,
41+
LintSource::CommandLine(_) => DUMMY_SP,
42+
}
43+
}
44+
}
45+
2846
pub type LevelSource = (Level, LintSource);
2947

3048
pub struct LintLevelSets {

0 commit comments

Comments
 (0)