Skip to content

Commit fe58d49

Browse files
authored
Rollup merge of rust-lang#73379 - pnkfelix:issue-70819-disallow-override-forbid-in-same-scope, r=petrochenkov
Disallow later override of forbid lint in same scope Fix rust-lang#70819 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. 3. Rewrote old test so that its use of lint attributes are consistent with what we want in the language. (Note that the fact this test existed is a slight sign that we may need a crater run on this bugfix...)
2 parents c03c213 + 4ec4c4f commit fe58d49

File tree

5 files changed

+146
-11
lines changed

5 files changed

+146
-11
lines changed

src/librustc_lint/levels.rs

+43-4
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

+19-1
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::{symbol, 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::kw::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 {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// This test is checking that you cannot override a `forbid` by adding in other
2+
// attributes later in the same scope. (We already ensure that you cannot
3+
// override it in nested scopes).
4+
5+
// If you turn off deduplicate diagnostics (which rustc turns on by default but
6+
// compiletest turns off when it runs ui tests), then the errors are
7+
// (unfortunately) repeated here because the checking is done as we read in the
8+
// errors, and curretly that happens two or three different times, depending on
9+
// compiler flags.
10+
//
11+
// I decided avoiding the redundant output was not worth the time in engineering
12+
// effort for bug like this, which 1. end users are unlikely to run into in the
13+
// first place, and 2. they won't see the redundant output anyway.
14+
15+
// compile-flags: -Z deduplicate-diagnostics=yes
16+
17+
fn forbid_first(num: i32) -> i32 {
18+
#![forbid(unused)]
19+
#![deny(unused)]
20+
//~^ ERROR: deny(unused) incompatible with previous forbid in same scope [E0453]
21+
#![warn(unused)]
22+
//~^ ERROR: warn(unused) incompatible with previous forbid in same scope [E0453]
23+
#![allow(unused)]
24+
//~^ ERROR: allow(unused) incompatible with previous forbid in same scope [E0453]
25+
26+
num * num
27+
}
28+
29+
fn forbid_last(num: i32) -> i32 {
30+
#![deny(unused)]
31+
#![warn(unused)]
32+
#![allow(unused)]
33+
#![forbid(unused)]
34+
35+
num * num
36+
}
37+
38+
fn forbid_multiple(num: i32) -> i32 {
39+
#![forbid(unused)]
40+
#![forbid(unused)]
41+
42+
num * num
43+
}
44+
45+
fn main() {
46+
forbid_first(10);
47+
forbid_last(10);
48+
forbid_multiple(10);
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
error[E0453]: deny(unused) incompatible with previous forbid in same scope
2+
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13
3+
|
4+
LL | #![forbid(unused)]
5+
| ------ `forbid` level set here
6+
LL | #![deny(unused)]
7+
| ^^^^^^
8+
9+
error[E0453]: warn(unused) incompatible with previous forbid in same scope
10+
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13
11+
|
12+
LL | #![forbid(unused)]
13+
| ------ `forbid` level set here
14+
...
15+
LL | #![warn(unused)]
16+
| ^^^^^^
17+
18+
error[E0453]: allow(unused) incompatible with previous forbid in same scope
19+
--> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14
20+
|
21+
LL | #![forbid(unused)]
22+
| ------ `forbid` level set here
23+
...
24+
LL | #![allow(unused)]
25+
| ^^^^^^
26+
27+
error: aborting due to 3 previous errors
28+
29+
For more information about this error, try `rustc --explain E0453`.

src/test/ui/rfc-2565-param-attrs/param-attrs-allowed.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,25 @@ extern "C" {
88
#[allow(unused_mut)] a: i32,
99
#[cfg(something)] b: i32,
1010
#[cfg_attr(something, cfg(nothing))] c: i32,
11-
#[deny(unused_mut)] d: i32,
12-
#[forbid(unused_mut)] #[warn(unused_mut)] ...
11+
#[forbid(unused_mut)] d: i32,
12+
#[deny(unused_mut)] #[warn(unused_mut)] ...
1313
);
1414
}
1515

1616
type FnType = fn(
1717
#[allow(unused_mut)] a: i32,
1818
#[cfg(something)] b: i32,
1919
#[cfg_attr(something, cfg(nothing))] c: i32,
20-
#[deny(unused_mut)] d: i32,
21-
#[forbid(unused_mut)] #[warn(unused_mut)] e: i32
20+
#[forbid(unused_mut)] d: i32,
21+
#[deny(unused_mut)] #[warn(unused_mut)] e: i32
2222
);
2323

2424
pub fn foo(
2525
#[allow(unused_mut)] a: i32,
2626
#[cfg(something)] b: i32,
2727
#[cfg_attr(something, cfg(nothing))] c: i32,
28-
#[deny(unused_mut)] d: i32,
29-
#[forbid(unused_mut)] #[warn(unused_mut)] _e: i32
28+
#[forbid(unused_mut)] d: i32,
29+
#[deny(unused_mut)] #[warn(unused_mut)] _e: i32
3030
) {}
3131

3232
// self

0 commit comments

Comments
 (0)