about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDylan DPC <99973273+Dylan-DPC@users.noreply.github.com>2022-03-10 23:12:57 +0100
committerGitHub <noreply@github.com>2022-03-10 23:12:57 +0100
commit1ed2a94fd2d7e1440531e07932bb85bddcc4c1b1 (patch)
treec7611875d9d9b5cdd9722f9e6f3d06d3999df942
parent5a7f09d9a3e56e2370731d1cdab78cbcb3451d0f (diff)
parent1c31a95df7de66dc7842b43facf185ef8a776e6f (diff)
downloadrust-1ed2a94fd2d7e1440531e07932bb85bddcc4c1b1.tar.gz
rust-1ed2a94fd2d7e1440531e07932bb85bddcc4c1b1.zip
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 https://github.com/rust-lang/compiler-team/issues/469
-rw-r--r--compiler/rustc_feature/src/active.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs116
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs23
-rw-r--r--compiler/rustc_session/src/parse.rs21
-rw-r--r--compiler/rustc_span/src/symbol.rs1
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs23
-rw-r--r--src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr75
-rw-r--r--src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs9
-rw-r--r--src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr30
-rw-r--r--src/test/ui/lint/must_not_suspend/gated.rs11
-rw-r--r--src/test/ui/lint/must_not_suspend/gated.stderr43
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs4
-rw-r--r--src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs5
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs6
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr18
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs9
-rw-r--r--src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr34
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs6
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr18
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs9
-rw-r--r--src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr34
21 files changed, 383 insertions, 114 deletions
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 1899e837eea..66eb3bcf7ce 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -169,6 +169,8 @@ declare_features! (
     (active, staged_api, "1.0.0", None, None),
     /// Added for testing E0705; perma-unstable.
     (active, test_2018_feature, "1.31.0", None, Some(Edition::Edition2018)),
+    /// Added for testing unstable lints; perma-unstable.
+    (active, test_unstable_lint, "1.60.0", None, None),
     /// Allows non-`unsafe` —and thus, unsound— access to `Pin` constructions.
     /// Marked `incomplete` since perma-unstable and unsound.
     (incomplete, unsafe_pin_internals, "1.60.0", None, None),
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index bbfbf61f486..7b018e7f75f 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -17,7 +17,7 @@ use rustc_session::lint::{
     builtin::{self, FORBIDDEN_LINT_GROUPS},
     Level, Lint, LintExpectationId, LintId,
 };
-use rustc_session::parse::feature_err;
+use rustc_session::parse::{add_feature_diagnostics, feature_err};
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP};
@@ -93,10 +93,19 @@ impl<'s> LintLevelsBuilder<'s> {
         self.store
     }
 
+    fn current_specs(&self) -> &FxHashMap<LintId, LevelAndSource> {
+        &self.sets.list[self.cur].specs
+    }
+
+    fn current_specs_mut(&mut self) -> &mut FxHashMap<LintId, LevelAndSource> {
+        &mut self.sets.list[self.cur].specs
+    }
+
     fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
-        let mut specs = FxHashMap::default();
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
+        self.cur =
+            self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: COMMAND_LINE });
         for &(ref lint_name, level) in &sess.opts.lint_opts {
             store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
             let orig_level = level;
@@ -108,30 +117,24 @@ impl<'s> LintLevelsBuilder<'s> {
             };
             for id in ids {
                 // ForceWarn and Forbid cannot be overriden
-                if let Some((Level::ForceWarn | Level::Forbid, _)) = specs.get(&id) {
+                if let Some((Level::ForceWarn | Level::Forbid, _)) = self.current_specs().get(&id) {
                     continue;
                 }
 
-                self.check_gated_lint(id, DUMMY_SP);
-                let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
-                specs.insert(id, (level, src));
+                if self.check_gated_lint(id, DUMMY_SP) {
+                    let src = LintLevelSource::CommandLine(lint_flag_val, orig_level);
+                    self.current_specs_mut().insert(id, (level, src));
+                }
             }
         }
-
-        self.cur = self.sets.list.push(LintSet { specs, parent: COMMAND_LINE });
     }
 
     /// Attempts to insert the `id` to `level_src` map entry. If unsuccessful
     /// (e.g. if a forbid was already inserted on the same scope), then emits a
     /// diagnostic with no change to `specs`.
-    fn insert_spec(
-        &mut self,
-        specs: &mut FxHashMap<LintId, LevelAndSource>,
-        id: LintId,
-        (level, src): LevelAndSource,
-    ) {
+    fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
         let (old_level, old_src) =
-            self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess);
+            self.sets.get_lint_level(id.lint, self.cur, Some(self.current_specs()), &self.sess);
         // Setting to a non-forbid level is an error if the lint previously had
         // a forbid level. Note that this is not necessarily true even with a
         // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
@@ -154,7 +157,10 @@ impl<'s> LintLevelsBuilder<'s> {
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
-                    fcw_warning, specs, old_src, id_name
+                    fcw_warning,
+                    self.current_specs(),
+                    old_src,
+                    id_name
                 );
 
                 let decorate_diag = |diag: &mut Diagnostic| {
@@ -213,9 +219,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
         if let Level::ForceWarn = old_level {
-            specs.insert(id, (old_level, old_src));
+            self.current_specs_mut().insert(id, (old_level, old_src));
         } else {
-            specs.insert(id, (level, src));
+            self.current_specs_mut().insert(id, (level, src));
         }
     }
 
@@ -239,7 +245,9 @@ impl<'s> LintLevelsBuilder<'s> {
         is_crate_node: bool,
         source_hir_id: Option<HirId>,
     ) -> BuilderPush {
-        let mut specs = FxHashMap::default();
+        let prev = self.cur;
+        self.cur = self.sets.list.push(LintSet { specs: FxHashMap::default(), parent: prev });
+
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
         for (attr_index, attr) in attrs.iter().enumerate() {
@@ -348,8 +356,9 @@ impl<'s> LintLevelsBuilder<'s> {
                             reason,
                         );
                         for &id in *ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -368,7 +377,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -377,8 +386,12 @@ impl<'s> LintLevelsBuilder<'s> {
                             }
                             Err((Some(ids), ref new_lint_name)) => {
                                 let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                                let (lvl, src) =
-                                    self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                                let (lvl, src) = self.sets.get_lint_level(
+                                    lint,
+                                    self.cur,
+                                    Some(self.current_specs()),
+                                    &sess,
+                                );
                                 struct_lint_level(
                                     self.sess,
                                     lint,
@@ -408,7 +421,7 @@ impl<'s> LintLevelsBuilder<'s> {
                                     reason,
                                 );
                                 for id in ids {
-                                    self.insert_spec(&mut specs, *id, (level, src));
+                                    self.insert_spec(*id, (level, src));
                                 }
                                 if let Level::Expect(expect_id) = level {
                                     self.lint_expectations
@@ -448,8 +461,12 @@ impl<'s> LintLevelsBuilder<'s> {
 
                     CheckLintNameResult::Warning(msg, renamed) => {
                         let lint = builtin::RENAMED_AND_REMOVED_LINTS;
-                        let (renamed_lint_level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess);
+                        let (renamed_lint_level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            &sess,
+                        );
                         struct_lint_level(
                             self.sess,
                             lint,
@@ -472,8 +489,12 @@ impl<'s> LintLevelsBuilder<'s> {
                     }
                     CheckLintNameResult::NoLint(suggestion) => {
                         let lint = builtin::UNKNOWN_LINTS;
-                        let (level, src) =
-                            self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                        let (level, src) = self.sets.get_lint_level(
+                            lint,
+                            self.cur,
+                            Some(self.current_specs()),
+                            self.sess,
+                        );
                         struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
                             let name = if let Some(tool_ident) = tool_ident {
                                 format!("{}::{}", tool_ident.name, name)
@@ -504,8 +525,9 @@ impl<'s> LintLevelsBuilder<'s> {
                     {
                         let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
                         for &id in ids {
-                            self.check_gated_lint(id, attr.span);
-                            self.insert_spec(&mut specs, id, (level, src));
+                            if self.check_gated_lint(id, attr.span) {
+                                self.insert_spec(id, (level, src));
+                            }
                         }
                         if let Level::Expect(expect_id) = level {
                             self.lint_expectations
@@ -519,7 +541,7 @@ impl<'s> LintLevelsBuilder<'s> {
         }
 
         if !is_crate_node {
-            for (id, &(level, ref src)) in specs.iter() {
+            for (id, &(level, ref src)) in self.current_specs().iter() {
                 if !id.lint.crate_level_only {
                     continue;
                 }
@@ -530,7 +552,7 @@ impl<'s> LintLevelsBuilder<'s> {
 
                 let lint = builtin::UNUSED_ATTRIBUTES;
                 let (lint_level, lint_src) =
-                    self.sets.get_lint_level(lint, self.cur, Some(&specs), self.sess);
+                    self.sets.get_lint_level(lint, self.cur, Some(self.current_specs()), self.sess);
                 struct_lint_level(
                     self.sess,
                     lint,
@@ -551,9 +573,9 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
 
-        let prev = self.cur;
-        if !specs.is_empty() {
-            self.cur = self.sets.list.push(LintSet { specs, parent: prev });
+        if self.current_specs().is_empty() {
+            self.sets.list.pop();
+            self.cur = prev;
         }
 
         BuilderPush { prev, changed: prev != self.cur }
@@ -574,18 +596,24 @@ impl<'s> LintLevelsBuilder<'s> {
     }
 
     /// Checks if the lint is gated on a feature that is not enabled.
-    fn check_gated_lint(&self, lint_id: LintId, span: Span) {
+    ///
+    /// Returns `true` if the lint's feature is enabled.
+    fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
             if !self.sess.features_untracked().enabled(feature) {
-                feature_err(
-                    &self.sess.parse_sess,
-                    feature,
-                    span,
-                    &format!("the `{}` lint is unstable", lint_id.lint.name_lower()),
-                )
-                .emit();
+                let lint = builtin::UNKNOWN_LINTS;
+                let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
+                struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
+                    let mut db =
+                        lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
+                    db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
+                    add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
+                    db.emit();
+                });
+                return false;
             }
         }
+        true
     }
 
     /// Called after `push` when the scope of a set of attributes are exited.
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 0f80ccaf6ad..8539e8868e2 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3128,6 +3128,7 @@ declare_lint_pass! {
         SUSPICIOUS_AUTO_TRAIT_IMPLS,
         UNEXPECTED_CFGS,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
+        TEST_UNSTABLE_LINT,
     ]
 }
 
@@ -3771,3 +3772,25 @@ declare_lint! {
     Warn,
     "deprecated where clause location"
 }
+
+declare_lint! {
+    /// The `test_unstable_lint` lint tests unstable lints and is perma-unstable.
+    ///
+    /// ### Example
+    ///
+    /// ```
+    /// #![allow(test_unstable_lint)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order to test the behavior of unstable lints, a permanently-unstable
+    /// lint is required. This lint can be used to trigger warnings and errors
+    /// from the compiler related to unstable lints.
+    pub TEST_UNSTABLE_LINT,
+    Deny,
+    "this unstable lint is only for testing",
+    @feature_gate = sym::test_unstable_lint;
+}
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 38ddb841d96..d34a3360a83 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -98,7 +98,26 @@ pub fn feature_err_issue<'a>(
     explain: &str,
 ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
     let mut err = sess.span_diagnostic.struct_span_err_with_code(span, explain, error_code!(E0658));
+    add_feature_diagnostics_for_issue(&mut err, sess, feature, issue);
+    err
+}
+
+/// Adds the diagnostics for a feature to an existing error.
+pub fn add_feature_diagnostics<'a>(err: &mut Diagnostic, sess: &'a ParseSess, feature: Symbol) {
+    add_feature_diagnostics_for_issue(err, sess, feature, GateIssue::Language);
+}
 
+/// Adds the diagnostics for a feature to an existing error.
+///
+/// This variant allows you to control whether it is a library or language feature.
+/// Almost always, you want to use this for a language feature. If so, prefer
+/// `add_feature_diagnostics`.
+pub fn add_feature_diagnostics_for_issue<'a>(
+    err: &mut Diagnostic,
+    sess: &'a ParseSess,
+    feature: Symbol,
+    issue: GateIssue,
+) {
     if let Some(n) = find_feature_issue(feature, issue) {
         err.note(&format!(
             "see issue #{} <https://github.com/rust-lang/rust/issues/{}> for more information",
@@ -110,8 +129,6 @@ pub fn feature_err_issue<'a>(
     if sess.unstable_features.is_nightly_build() {
         err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature));
     }
-
-    err
 }
 
 /// Info about a parsing session.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6b5dcacd12b..e820cb28552 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1385,6 +1385,7 @@ symbols! {
         test_case,
         test_removed_feature,
         test_runner,
+        test_unstable_lint,
         then_with,
         thread,
         thread_local,
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
index 2a34ed4d4f6..29a6e1f8a01 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.rs
@@ -1,9 +1,11 @@
+// check-fail
+
 #![deny(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 #![allow(non_exhaustive_omitted_patterns)]
-//~^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-//~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+//~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+//~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 
 fn main() {
     enum Foo {
@@ -11,14 +13,15 @@ fn main() {
     }
 
     #[allow(non_exhaustive_omitted_patterns)]
+    //~^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
     match Foo::A {
         Foo::A => {}
         Foo::B => {}
     }
-    //~^^^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^^ ERROR non-exhaustive patterns: `C` not covered
 
     match Foo::A {
         Foo::A => {}
@@ -26,6 +29,6 @@ fn main() {
         #[warn(non_exhaustive_omitted_patterns)]
         _ => {}
     }
-    //~^^^ ERROR the `non_exhaustive_omitted_patterns` lint is unstable
-    //~| ERROR the `non_exhaustive_omitted_patterns` lint is unstable
+    //~^^^ WARNING unknown lint: `non_exhaustive_omitted_patterns`
+    //~| WARNING unknown lint: `non_exhaustive_omitted_patterns`
 }
diff --git a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
index 691f64cf0ad..dbeef6c2d2a 100644
--- a/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
+++ b/src/test/ui/feature-gates/feature-gate-non_exhaustive_omitted_patterns_lint.stderr
@@ -1,93 +1,124 @@
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:1:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:3:1
    |
 LL | #![deny(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:4:1
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:6:1
    |
 LL | #![allow(non_exhaustive_omitted_patterns)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:13:5
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:15:5
    |
 LL |     #[allow(non_exhaustive_omitted_patterns)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error[E0658]: the `non_exhaustive_omitted_patterns` lint is unstable
-  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:26:9
+warning: unknown lint: `non_exhaustive_omitted_patterns`
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:29:9
    |
 LL |         #[warn(non_exhaustive_omitted_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `non_exhaustive_omitted_patterns` lint is unstable
    = note: see issue #89554 <https://github.com/rust-lang/rust/issues/89554> for more information
    = help: add `#![feature(non_exhaustive_omitted_patterns_lint)]` to the crate attributes to enable
 
-error: aborting due to 10 previous errors
+error[E0004]: non-exhaustive patterns: `C` not covered
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:20:11
+   |
+LL |     match Foo::A {
+   |           ^^^^^^ pattern `C` not covered
+   |
+note: `Foo` defined here
+  --> $DIR/feature-gate-non_exhaustive_omitted_patterns_lint.rs:12:15
+   |
+LL |     enum Foo {
+   |          ---
+LL |         A, B, C,
+   |               ^ not covered
+   = note: the matched value is of type `Foo`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         Foo::B => {}
+LL +         C => todo!()
+   |
+
+error: aborting due to previous error; 10 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs
new file mode 100644
index 00000000000..c398394cbe1
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+// `test_unstable_lint` is for testing and should never be stabilized.
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr
new file mode 100644
index 00000000000..a29322443ea
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-test_unstable_lint.stderr
@@ -0,0 +1,30 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/feature-gate-test_unstable_lint.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/lint/must_not_suspend/gated.rs b/src/test/ui/lint/must_not_suspend/gated.rs
index acb81b0bf9d..b73a7655529 100644
--- a/src/test/ui/lint/must_not_suspend/gated.rs
+++ b/src/test/ui/lint/must_not_suspend/gated.rs
@@ -1,12 +1,15 @@
+// check-pass
+
 // edition:2018
-#![deny(must_not_suspend)]  //~ ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
-//~| ERROR the `must_not_suspend`
+#![deny(must_not_suspend)]
+//~^ WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
+//~| WARNING unknown lint: `must_not_suspend`
 
 async fn other() {}
 
 pub async fn uhoh(m: std::sync::Mutex<()>) {
-    let _guard = m.lock().unwrap(); //~ ERROR `MutexGuard` held across
+    let _guard = m.lock().unwrap();
     other().await;
 }
 
diff --git a/src/test/ui/lint/must_not_suspend/gated.stderr b/src/test/ui/lint/must_not_suspend/gated.stderr
index 0d4319670e6..b58ecb55596 100644
--- a/src/test/ui/lint/must_not_suspend/gated.stderr
+++ b/src/test/ui/lint/must_not_suspend/gated.stderr
@@ -1,54 +1,33 @@
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: `#[warn(unknown_lints)]` on by default
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error[E0658]: the `must_not_suspend` lint is unstable
-  --> $DIR/gated.rs:2:1
+warning: unknown lint: `must_not_suspend`
+  --> $DIR/gated.rs:4:1
    |
 LL | #![deny(must_not_suspend)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: the `must_not_suspend` lint is unstable
    = note: see issue #83310 <https://github.com/rust-lang/rust/issues/83310> for more information
    = help: add `#![feature(must_not_suspend)]` to the crate attributes to enable
 
-error: `MutexGuard` held across a suspend point, but should not be
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-LL |     other().await;
-   |            ------ the value is held across this suspend point
-   |
-note: the lint level is defined here
-  --> $DIR/gated.rs:2:9
-   |
-LL | #![deny(must_not_suspend)]
-   |         ^^^^^^^^^^^^^^^^
-note: holding a MutexGuard across suspend points can cause deadlocks, delays, and cause Futures to not implement `Send`
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-help: consider using a block (`{ ... }`) to shrink the value's scope, ending before the suspend point
-  --> $DIR/gated.rs:9:9
-   |
-LL |     let _guard = m.lock().unwrap();
-   |         ^^^^^^
-
-error: aborting due to 4 previous errors
+warning: 3 warnings emitted
 
-For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..80e30f23993
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-command-line.rs
@@ -0,0 +1,4 @@
+// check-pass
+// compile-flags: -Aunknown_lints -Atest_unstable_lint
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
new file mode 100644
index 00000000000..992472c894a
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/allow-unknown-unstable-lint-inline.rs
@@ -0,0 +1,5 @@
+// check-pass
+
+#![allow(unknown_lints, test_unstable_lint)]
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..dcc06850de1
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
@@ -0,0 +1,6 @@
+// check-fail
+// compile-flags: -Dunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
new file mode 100644
index 00000000000..7e6885bd706
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-command-line.stderr
@@ -0,0 +1,18 @@
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-D unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
new file mode 100644
index 00000000000..c6c60b12d83
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.rs
@@ -0,0 +1,9 @@
+// check-fail
+
+#![deny(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+//~| ERROR unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
new file mode 100644
index 00000000000..2d1027dd0e0
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/deny-unstable-lint-inline.stderr
@@ -0,0 +1,34 @@
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/deny-unstable-lint-inline.rs:3:9
+   |
+LL | #![deny(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: unknown lint: `test_unstable_lint`
+  --> $DIR/deny-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
new file mode 100644
index 00000000000..3778291ebb4
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
@@ -0,0 +1,6 @@
+// check-pass
+// compile-flags: -Wunknown_lints -Atest_unstable_lint
+// error-pattern: unknown lint: `test_unstable_lint`
+// error-pattern: the `test_unstable_lint` lint is unstable
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
new file mode 100644
index 00000000000..799d740b00e
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.stderr
@@ -0,0 +1,18 @@
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: requested on the command line with `-W unknown-lints`
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
new file mode 100644
index 00000000000..f4247e4569e
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.rs
@@ -0,0 +1,9 @@
+// check-pass
+
+#![warn(unknown_lints)]
+#![allow(test_unstable_lint)]
+//~^ WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+//~| WARNING unknown lint: `test_unstable_lint`
+
+fn main() {}
diff --git a/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
new file mode 100644
index 00000000000..142558b471b
--- /dev/null
+++ b/src/test/ui/unknown-unstable-lints/warn-unknown-unstable-lint-inline.stderr
@@ -0,0 +1,34 @@
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:3:9
+   |
+LL | #![warn(unknown_lints)]
+   |         ^^^^^^^^^^^^^
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: unknown lint: `test_unstable_lint`
+  --> $DIR/warn-unknown-unstable-lint-inline.rs:4:1
+   |
+LL | #![allow(test_unstable_lint)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the `test_unstable_lint` lint is unstable
+   = help: add `#![feature(test_unstable_lint)]` to the crate attributes to enable
+
+warning: 3 warnings emitted
+