From e42271db0d8ee14f0599e7b72625bb2f133f5cac Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Fri, 4 Jun 2021 23:21:43 +0200
Subject: [PATCH] Make ForceWarn a lint level.

---
 compiler/rustc_lint/src/context.rs            | 38 +++++++------------
 compiler/rustc_lint/src/levels.rs             | 31 +++++++--------
 compiler/rustc_lint_defs/src/lib.rs           |  2 +
 compiler/rustc_middle/src/lint.rs             | 35 ++++-------------
 .../force-allowed-by-default-lint.stderr      |  2 +-
 .../force-allowed-deny-by-default-lint.stderr |  2 +-
 .../force-warn/force-allowed-warning.stderr   |  2 +-
 .../force-deny-by-default-lint.stderr         |  2 +-
 .../force-lint-allow-all-warnings.stderr      |  2 +-
 ...force-lint-group-allow-all-warnings.stderr |  2 +-
 .../force-lint-in-allowed-group.stderr        |  2 +-
 .../force-warn-group-allow-warning.stderr     |  2 +-
 .../lint/force-warn/force-warn-group.stderr   |  2 +-
 13 files changed, 48 insertions(+), 76 deletions(-)

diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 2dc04d57d1e..697ab44d90b 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -334,14 +334,8 @@ impl LintStore {
         }
     }
 
-    /// Checks the validity of lint names derived from the command line. Returns
-    /// true if the lint is valid, false otherwise.
-    pub fn check_lint_name_cmdline(
-        &self,
-        sess: &Session,
-        lint_name: &str,
-        level: Option<Level>,
-    ) -> bool {
+    /// Checks the validity of lint names derived from the command line
+    pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) {
         let db = match self.check_lint_name(lint_name, None) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
@@ -367,23 +361,19 @@ impl LintStore {
         };
 
         if let Some(mut db) = db {
-            if let Some(level) = level {
-                let msg = format!(
-                    "requested on the command line with `{} {}`",
-                    match level {
-                        Level::Allow => "-A",
-                        Level::Warn => "-W",
-                        Level::Deny => "-D",
-                        Level::Forbid => "-F",
-                    },
-                    lint_name
-                );
-                db.note(&msg);
-            }
+            let msg = format!(
+                "requested on the command line with `{} {}`",
+                match level {
+                    Level::Allow => "-A",
+                    Level::Warn => "-W",
+                    Level::ForceWarn => "--force-warns",
+                    Level::Deny => "-D",
+                    Level::Forbid => "-F",
+                },
+                lint_name
+            );
+            db.note(&msg);
             db.emit();
-            false
-        } else {
-            true
         }
     }
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 0ee434f5fb5..c0a059b92aa 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> {
         self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid);
 
         for &(ref lint_name, level) in &sess.opts.lint_opts {
-            store.check_lint_name_cmdline(sess, &lint_name, Some(level));
+            store.check_lint_name_cmdline(sess, &lint_name, level);
             let orig_level = level;
 
             // If the cap is less than this specified level, e.g., if we've got
@@ -110,12 +110,13 @@ impl<'s> LintLevelsBuilder<'s> {
         }
 
         for lint_name in &sess.opts.force_warns {
-            let valid = store.check_lint_name_cmdline(sess, lint_name, None);
-            if valid {
-                let lints = store
-                    .find_lints(lint_name)
-                    .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
-                self.sets.force_warns.extend(&lints);
+            store.check_lint_name_cmdline(sess, lint_name, Level::ForceWarn);
+            let lints = store
+                .find_lints(lint_name)
+                .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids"));
+            for id in lints {
+                let src = LintLevelSource::CommandLine(Symbol::intern(lint_name), Level::ForceWarn);
+                specs.insert(id, (Level::ForceWarn, src));
             }
         }
 
@@ -131,6 +132,8 @@ impl<'s> LintLevelsBuilder<'s> {
         id: LintId,
         (level, src): LevelAndSource,
     ) {
+        let (old_level, old_src) =
+            self.sets.get_lint_level(id.lint, self.cur, Some(&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`.
@@ -138,9 +141,7 @@ impl<'s> LintLevelsBuilder<'s> {
         // This means that this only errors if we're truly lowering the lint
         // level from forbid.
         if level != Level::Forbid {
-            if let (Level::Forbid, old_src) =
-                self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess)
-            {
+            if let Level::Forbid = old_level {
                 // Backwards compatibility check:
                 //
                 // We used to not consider `forbid(lint_group)`
@@ -152,9 +153,6 @@ impl<'s> LintLevelsBuilder<'s> {
                     LintLevelSource::Default => false,
                     LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol),
                     LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol),
-                    LintLevelSource::ForceWarn(_symbol) => {
-                        bug!("forced warn lint returned a forbid lint level")
-                    }
                 };
                 debug!(
                     "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}",
@@ -179,7 +177,6 @@ impl<'s> LintLevelsBuilder<'s> {
                         LintLevelSource::CommandLine(_, _) => {
                             diag_builder.note("`forbid` lint level was set on command line");
                         }
-                        _ => bug!("forced warn lint returned a forbid lint level"),
                     }
                     diag_builder.emit();
                 };
@@ -216,7 +213,11 @@ impl<'s> LintLevelsBuilder<'s> {
                 }
             }
         }
-        specs.insert(id, (level, src));
+        if let Level::ForceWarn = old_level {
+            specs.insert(id, (old_level, old_src));
+        } else {
+            specs.insert(id, (level, src));
+        }
     }
 
     /// Pushes a list of AST lint attributes onto this context.
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index b3d98747dcf..d855d7de2a5 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -51,6 +51,7 @@ pub enum Applicability {
 pub enum Level {
     Allow,
     Warn,
+    ForceWarn,
     Deny,
     Forbid,
 }
@@ -63,6 +64,7 @@ impl Level {
         match self {
             Level::Allow => "allow",
             Level::Warn => "warn",
+            Level::ForceWarn => "force-warns",
             Level::Deny => "deny",
             Level::Forbid => "forbid",
         }
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 8180d853f60..69d0f53230c 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -1,7 +1,7 @@
 use std::cmp;
 
 use crate::ich::StableHashingContext;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_errors::{DiagnosticBuilder, DiagnosticId};
 use rustc_hir::HirId;
@@ -28,9 +28,6 @@ pub enum LintLevelSource {
     /// The provided `Level` is the level specified on the command line.
     /// (The actual level may be lower due to `--cap-lints`.)
     CommandLine(Symbol, Level),
-
-    /// Lint is being forced to warn no matter what.
-    ForceWarn(Symbol),
 }
 
 impl LintLevelSource {
@@ -39,7 +36,6 @@ impl LintLevelSource {
             LintLevelSource::Default => symbol::kw::Default,
             LintLevelSource::Node(name, _, _) => name,
             LintLevelSource::CommandLine(name, _) => name,
-            LintLevelSource::ForceWarn(name) => name,
         }
     }
 
@@ -48,7 +44,6 @@ impl LintLevelSource {
             LintLevelSource::Default => DUMMY_SP,
             LintLevelSource::Node(_, span, _) => span,
             LintLevelSource::CommandLine(_, _) => DUMMY_SP,
-            LintLevelSource::ForceWarn(_) => DUMMY_SP,
         }
     }
 }
@@ -60,7 +55,6 @@ pub type LevelAndSource = (Level, LintLevelSource);
 pub struct LintLevelSets {
     pub list: Vec<LintSet>,
     pub lint_cap: Level,
-    pub force_warns: FxHashSet<LintId>,
 }
 
 #[derive(Debug)]
@@ -79,11 +73,7 @@ pub enum LintSet {
 
 impl LintLevelSets {
     pub fn new() -> Self {
-        LintLevelSets {
-            list: Vec::new(),
-            lint_cap: Level::Forbid,
-            force_warns: FxHashSet::default(),
-        }
+        LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid }
     }
 
     pub fn get_lint_level(
@@ -93,11 +83,6 @@ impl LintLevelSets {
         aux: Option<&FxHashMap<LintId, LevelAndSource>>,
         sess: &Session,
     ) -> LevelAndSource {
-        // Check whether we should always warn
-        if self.force_warns.contains(&LintId::of(lint)) {
-            return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name)));
-        }
-
         let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
 
         // If `level` is none then we actually assume the default level for this
@@ -191,11 +176,11 @@ impl LintLevelMap {
 impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap {
     #[inline]
     fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        let LintLevelMap { ref sets, ref id_to_set, .. } = *self;
+        let LintLevelMap { ref sets, ref id_to_set } = *self;
 
         id_to_set.hash_stable(hcx, hasher);
 
-        let LintLevelSets { ref list, lint_cap, .. } = *sets;
+        let LintLevelSets { ref list, lint_cap } = *sets;
 
         lint_cap.hash_stable(hcx, hasher);
 
@@ -273,8 +258,8 @@ pub fn struct_lint_level<'s, 'd>(
                     return;
                 }
             }
-            (Level::Warn, Some(span)) => sess.struct_span_warn(span, ""),
-            (Level::Warn, None) => sess.struct_warn(""),
+            (Level::Warn | Level::ForceWarn, Some(span)) => sess.struct_span_warn(span, ""),
+            (Level::Warn | Level::ForceWarn, None) => sess.struct_warn(""),
             (Level::Deny | Level::Forbid, Some(span)) => sess.struct_span_err(span, ""),
             (Level::Deny | Level::Forbid, None) => sess.struct_err(""),
         };
@@ -316,6 +301,7 @@ pub fn struct_lint_level<'s, 'd>(
                     Level::Deny => "-D",
                     Level::Forbid => "-F",
                     Level::Allow => "-A",
+                    Level::ForceWarn => "--force-warns",
                 };
                 let hyphen_case_lint_name = name.replace("_", "-");
                 if lint_flag_val.as_str() == name {
@@ -361,13 +347,6 @@ pub fn struct_lint_level<'s, 'd>(
                     );
                 }
             }
-            LintLevelSource::ForceWarn(_) => {
-                sess.diag_note_once(
-                    &mut err,
-                    DiagnosticMessageId::from(lint),
-                    "warning forced by `force-warns` commandline option",
-                );
-            }
         }
 
         err.code(DiagnosticId::Lint { name, has_future_breakage });
diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
index 0e0e934c765..37c61e614f3 100644
--- a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr
@@ -4,7 +4,7 @@ warning: hidden lifetime parameters in types are deprecated
 LL | fn foo(x: &Foo) {}
    |            ^^^- help: indicate the anonymous lifetime: `<'_>`
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns elided-lifetimes-in-paths`
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
index bad12f94b18..56b2f0236a5 100644
--- a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr
@@ -6,7 +6,7 @@ LL | const C: i32 = 1 / 0;
    |                |
    |                attempt to divide `1_i32` by zero
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns const-err`
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/force-allowed-warning.stderr
index 145798a32a9..7eb980a1297 100644
--- a/src/test/ui/lint/force-warn/force-allowed-warning.stderr
+++ b/src/test/ui/lint/force-warn/force-allowed-warning.stderr
@@ -4,7 +4,7 @@ warning: function is never used: `dead_function`
 LL | fn dead_function() {}
    |    ^^^^^^^^^^^^^
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns dead-code`
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
index 4b004cf367d..8b9bb5a74cf 100644
--- a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
+++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr
@@ -6,7 +6,7 @@ LL | const C: i32 = 1 / 0;
    |                |
    |                attempt to divide `1_i32` by zero
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns const-err`
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
 
diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
index 577dbe1fea8..ebdb022f2a2 100644
--- a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
+++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr
@@ -4,7 +4,7 @@ warning: function is never used: `dead_function`
 LL | fn dead_function() {}
    |    ^^^^^^^^^^^^^
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns dead-code`
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
index 8665fa2610a..7429e77fe83 100644
--- a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
+++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr
@@ -4,7 +4,7 @@ warning: function `FUNCTION` should have a snake case name
 LL | pub fn FUNCTION() {}
    |        ^^^^^^^^ help: convert the identifier to snake case: `function`
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: `--force-warns non-snake-case` implied by `--force-warns nonstandard-style`
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
index 8ecfe3a15b8..4f7bba6bba1 100644
--- a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
+++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr
@@ -4,7 +4,7 @@ warning: trait objects without an explicit `dyn` are deprecated
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: requested on the command line with `--force-warns bare-trait-objects`
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
index 232edf4f1ef..65de6c9e287 100644
--- a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
+++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr
@@ -4,7 +4,7 @@ warning: trait objects without an explicit `dyn` are deprecated
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: `--force-warns bare-trait-objects` implied by `--force-warns rust-2018-idioms`
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>
 
diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/force-warn-group.stderr
index 82781984f0c..fd3397c916a 100644
--- a/src/test/ui/lint/force-warn/force-warn-group.stderr
+++ b/src/test/ui/lint/force-warn/force-warn-group.stderr
@@ -4,7 +4,7 @@ warning: trait objects without an explicit `dyn` are deprecated
 LL | pub fn function(_x: Box<SomeTrait>) {}
    |                         ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait`
    |
-   = note: warning forced by `force-warns` commandline option
+   = note: `--force-warns bare-trait-objects` implied by `--force-warns rust-2018-idioms`
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165>