Skip to content

Commit 1ed2a94

Browse files
authored
Rollup merge of #94274 - djkoloski:unknown_unstable_lints, r=tmandry
Treat unstable lints as unknown This change causes unstable lints to be ignored if the `unknown_lints` lint is allowed. To achieve this, it also changes lints to apply as soon as they are processed. Previously, lints in the same set were processed as a batch and then all simultaneously applied. Implementation of rust-lang/compiler-team#469
2 parents 5a7f09d + 1c31a95 commit 1ed2a94

21 files changed

+383
-114
lines changed

compiler/rustc_feature/src/active.rs

+2
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ declare_features! (
169169
(active, staged_api, "1.0.0", None, None),
170170
/// Added for testing E0705; perma-unstable.
171171
(active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
172+
/// Added for testing unstable lints; perma-unstable.
173+
(active, test_unstable_lint, "1.60.0", None, None),
172174
/// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
173175
/// Marked `incomplete` since perma-unstable and unsound.
174176
(incomplete, unsafe_pin_internals, "1.60.0", None, None),

compiler/rustc_lint/src/levels.rs

+72-44
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_session::lint::{
1717
builtin::{self, FORBIDDEN_LINT_GROUPS},
1818
Level, Lint, LintExpectationId, LintId,
1919
};
20-
use rustc_session::parse::feature_err;
20+
use rustc_session::parse::{add_feature_diagnostics, feature_err};
2121
use rustc_session::Session;
2222
use rustc_span::symbol::{sym, Symbol};
2323
use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
@@ -93,10 +93,19 @@ impl<'s> LintLevelsBuilder<'s> {
9393
self.store
9494
}
9595

96+
fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
97+
&self.sets.list[self.cur].specs
98+
}
99+
100+
fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
101+
&mut self.sets.list[self.cur].specs
102+
}
103+
96104
fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
97-
let mut specs = FxHashMap::default();
98105
self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
99106

107+
self.cur =
108+
self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
100109
for &(ref lint_name, level) in &sess.opts.lint_opts {
101110
store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
102111
let orig_level = level;
@@ -108,30 +117,24 @@ impl<'s> LintLevelsBuilder<'s> {
108117
};
109118
for id in ids {
110119
// ForceWarn and Forbid cannot be overriden
111-
if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
120+
if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
112121
continue;
113122
}
114123

115-
self.check_gated_lint(id, DUMMY_SP);
116-
let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
117-
specs.insert(id, (level, src));
124+
if self.check_gated_lint(id, DUMMY_SP) {
125+
let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
126+
self.current_specs_mut().insert(id, (level, src));
127+
}
118128
}
119129
}
120-
121-
self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
122130
}
123131

124132
/// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
125133
/// (e.g. if a forbid was already inserted on the same scope), then emits a
126134
/// diagnostic with no change to `specs`.
127-
fn insert_spec(
128-
&mut self,
129-
specs: &mut FxHashMap<LintId, LevelAndSource>,
130-
id: LintId,
131-
(level, src): LevelAndSource,
132-
) {
135+
fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
133136
let (old_level, old_src) =
134-
self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
137+
self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
135138
// Setting to a non-forbid level is an error if the lint previously had
136139
// a forbid level. Note that this is not necessarily true even with a
137140
// `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
@@ -154,7 +157,10 @@ impl<'s> LintLevelsBuilder<'s> {
154157
};
155158
debug!(
156159
"fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
157-
fcw_warning, specs, old_src, id_name
160+
fcw_warning,
161+
self.current_specs(),
162+
old_src,
163+
id_name
158164
);
159165

160166
let decorate_diag = |diag: &mut Diagnostic| {
@@ -213,9 +219,9 @@ impl<'s> LintLevelsBuilder<'s> {
213219
}
214220
}
215221
if let Level::ForceWarn = old_level {
216-
specs.insert(id, (old_level, old_src));
222+
self.current_specs_mut().insert(id, (old_level, old_src));
217223
} else {
218-
specs.insert(id, (level, src));
224+
self.current_specs_mut().insert(id, (level, src));
219225
}
220226
}
221227

@@ -239,7 +245,9 @@ impl<'s> LintLevelsBuilder<'s> {
239245
is_crate_node: bool,
240246
source_hir_id: Option<HirId>,
241247
) -> BuilderPush {
242-
let mut specs = FxHashMap::default();
248+
let prev = self.cur;
249+
self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
250+
243251
let sess = self.sess;
244252
let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
245253
for (attr_index, attr) in attrs.iter().enumerate() {
@@ -348,8 +356,9 @@ impl<'s> LintLevelsBuilder<'s> {
348356
reason,
349357
);
350358
for &id in *ids {
351-
self.check_gated_lint(id, attr.span);
352-
self.insert_spec(&mut specs, id, (level, src));
359+
if self.check_gated_lint(id, attr.span) {
360+
self.insert_spec(id, (level, src));
361+
}
353362
}
354363
if let Level::Expect(expect_id) = level {
355364
self.lint_expectations
@@ -368,7 +377,7 @@ impl<'s> LintLevelsBuilder<'s> {
368377
reason,
369378
);
370379
for id in ids {
371-
self.insert_spec(&mut specs, *id, (level, src));
380+
self.insert_spec(*id, (level, src));
372381
}
373382
if let Level::Expect(expect_id) = level {
374383
self.lint_expectations
@@ -377,8 +386,12 @@ impl<'s> LintLevelsBuilder<'s> {
377386
}
378387
Err((Some(ids), ref new_lint_name)) => {
379388
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
380-
let (lvl, src) =
381-
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
389+
let (lvl, src) = self.sets.get_lint_level(
390+
lint,
391+
self.cur,
392+
Some(self.current_specs()),
393+
&sess,
394+
);
382395
struct_lint_level(
383396
self.sess,
384397
lint,
@@ -408,7 +421,7 @@ impl<'s> LintLevelsBuilder<'s> {
408421
reason,
409422
);
410423
for id in ids {
411-
self.insert_spec(&mut specs, *id, (level, src));
424+
self.insert_spec(*id, (level, src));
412425
}
413426
if let Level::Expect(expect_id) = level {
414427
self.lint_expectations
@@ -448,8 +461,12 @@ impl<'s> LintLevelsBuilder<'s> {
448461

449462
CheckLintNameResult::Warning(msg, renamed) => {
450463
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
451-
let (renamed_lint_level, src) =
452-
self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
464+
let (renamed_lint_level, src) = self.sets.get_lint_level(
465+
lint,
466+
self.cur,
467+
Some(self.current_specs()),
468+
&sess,
469+
);
453470
struct_lint_level(
454471
self.sess,
455472
lint,
@@ -472,8 +489,12 @@ impl<'s> LintLevelsBuilder<'s> {
472489
}
473490
CheckLintNameResult::NoLint(suggestion) => {
474491
let lint = builtin::UNKNOWN_LINTS;
475-
let (level, src) =
476-
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
492+
let (level, src) = self.sets.get_lint_level(
493+
lint,
494+
self.cur,
495+
Some(self.current_specs()),
496+
self.sess,
497+
);
477498
struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
478499
let name = if let Some(tool_ident) = tool_ident {
479500
format!("{}::{}", tool_ident.name, name)
@@ -504,8 +525,9 @@ impl<'s> LintLevelsBuilder<'s> {
504525
{
505526
let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
506527
for &id in ids {
507-
self.check_gated_lint(id, attr.span);
508-
self.insert_spec(&mut specs, id, (level, src));
528+
if self.check_gated_lint(id, attr.span) {
529+
self.insert_spec(id, (level, src));
530+
}
509531
}
510532
if let Level::Expect(expect_id) = level {
511533
self.lint_expectations
@@ -519,7 +541,7 @@ impl<'s> LintLevelsBuilder<'s> {
519541
}
520542

521543
if !is_crate_node {
522-
for (id, &(level, ref src)) in specs.iter() {
544+
for (id, &(level, ref src)) in self.current_specs().iter() {
523545
if !id.lint.crate_level_only {
524546
continue;
525547
}
@@ -530,7 +552,7 @@ impl<'s> LintLevelsBuilder<'s> {
530552

531553
let lint = builtin::UNUSED_ATTRIBUTES;
532554
let (lint_level, lint_src) =
533-
self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
555+
self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
534556
struct_lint_level(
535557
self.sess,
536558
lint,
@@ -551,9 +573,9 @@ impl<'s> LintLevelsBuilder<'s> {
551573
}
552574
}
553575

554-
let prev = self.cur;
555-
if !specs.is_empty() {
556-
self.cur = self.sets.list.push(LintSet { specs, parent: prev });
576+
if self.current_specs().is_empty() {
577+
self.sets.list.pop();
578+
self.cur = prev;
557579
}
558580

559581
BuilderPush { prev, changed: prev != self.cur }
@@ -574,18 +596,24 @@ impl<'s> LintLevelsBuilder<'s> {
574596
}
575597

576598
/// Checks if the lint is gated on a feature that is not enabled.
577-
fn check_gated_lint(&self, lint_id: LintId, span: Span) {
599+
///
600+
/// Returns `true` if the lint's feature is enabled.
601+
fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
578602
if let Some(feature) = lint_id.lint.feature_gate {
579603
if !self.sess.features_untracked().enabled(feature) {
580-
feature_err(
581-
&self.sess.parse_sess,
582-
feature,
583-
span,
584-
&format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
585-
)
586-
.emit();
604+
let lint = builtin::UNKNOWN_LINTS;
605+
let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
606+
struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
607+
let mut db =
608+
lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
609+
db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
610+
add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
611+
db.emit();
612+
});
613+
return false;
587614
}
588615
}
616+
true
589617
}
590618

591619
/// Called after `push` when the scope of a set of attributes are exited.

compiler/rustc_lint_defs/src/builtin.rs

+23
Original file line numberDiff line numberDiff line change
@@ -3128,6 +3128,7 @@ declare_lint_pass! {
31283128
SUSPICIOUS_AUTO_TRAIT_IMPLS,
31293129
UNEXPECTED_CFGS,
31303130
DEPRECATED_WHERE_CLAUSE_LOCATION,
3131+
TEST_UNSTABLE_LINT,
31313132
]
31323133
}
31333134

@@ -3771,3 +3772,25 @@ declare_lint! {
37713772
Warn,
37723773
"deprecated where clause location"
37733774
}
3775+
3776+
declare_lint! {
3777+
/// The `test_unstable_lint` lint tests unstable lints and is perma-unstable.
3778+
///
3779+
/// ### Example
3780+
///
3781+
/// ```
3782+
/// #![allow(test_unstable_lint)]
3783+
/// ```
3784+
///
3785+
/// {{produces}}
3786+
///
3787+
/// ### Explanation
3788+
///
3789+
/// In order to test the behavior of unstable lints, a permanently-unstable
3790+
/// lint is required. This lint can be used to trigger warnings and errors
3791+
/// from the compiler related to unstable lints.
3792+
pub TEST_UNSTABLE_LINT,
3793+
Deny,
3794+
"this unstable lint is only for testing",
3795+
@feature_gate = sym::test_unstable_lint;
3796+
}

compiler/rustc_session/src/parse.rs

+19-2
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,26 @@ pub fn feature_err_issue<'a>(
9898
explain: &str,
9999
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
100100
let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
101+
add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
102+
err
103+
}
104+
105+
/// Adds the diagnostics for a feature to an existing error.
106+
pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
107+
add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
108+
}
101109

110+
/// Adds the diagnostics for a feature to an existing error.
111+
///
112+
/// This variant allows you to control whether it is a library or language feature.
113+
/// Almost always, you want to use this for a language feature. If so, prefer
114+
/// `add_feature_diagnostics`.
115+
pub fn add_feature_diagnostics_for_issue<'a>(
116+
err: &mut Diagnostic,
117+
sess: &'a ParseSess,
118+
feature: Symbol,
119+
issue: GateIssue,
120+
) {
102121
if let Some(n) = find_feature_issue(feature, issue) {
103122
err.note(&format!(
104123
"see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
@@ -110,8 +129,6 @@ pub fn feature_err_issue<'a>(
110129
if sess.unstable_features.is_nightly_build() {
111130
err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
112131
}
113-
114-
err
115132
}
116133

117134
/// Info about a parsing session.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,7 @@ symbols! {
13851385
test_case,
13861386
test_removed_feature,
13871387
test_runner,
1388+
test_unstable_lint,
13881389
then_with,
13891390
thread,
13901391
thread_local,
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
1+
// check-fail
2+
13
#![deny(non_exhaustive_omitted_patterns)]
2-
//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
3-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
4+
//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
5+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
46
#![allow(non_exhaustive_omitted_patterns)]
5-
//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
6-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
7+
//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
8+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
79

810
fn main() {
911
enum Foo {
1012
A, B, C,
1113
}
1214

1315
#[allow(non_exhaustive_omitted_patterns)]
16+
//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
17+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
18+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
19+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
1420
match Foo::A {
1521
Foo::A => {}
1622
Foo::B => {}
1723
}
18-
//~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
19-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
20-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
21-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
24+
//~^^^^ ERROR non-exhaustive patterns: `C` not covered
2225

2326
match Foo::A {
2427
Foo::A => {}
2528
Foo::B => {}
2629
#[warn(non_exhaustive_omitted_patterns)]
2730
_ => {}
2831
}
29-
//~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
30-
//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
32+
//~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
33+
//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
3134
}

0 commit comments

Comments
 (0)