about summary refs log tree commit diff
diff options
context:
space:
mode:
authorKarol Zwolak <karolzwolak7@gmail.com>2025-04-28 09:21:10 +0200
committerKarol Zwolak <karolzwolak7@gmail.com>2025-08-19 21:27:10 +0200
commit9a29e1693d5122990dcd6c87a5a7b2b2b85f10da (patch)
treec432161cb7aaeb9df6c1661ed5b48810cef5a475
parent16ad385579cebb6f7d53367c552661b6b51a4a02 (diff)
downloadrust-9a29e1693d5122990dcd6c87a5a7b2b2b85f10da.tar.gz
rust-9a29e1693d5122990dcd6c87a5a7b2b2b85f10da.zip
mention lint group in default level lint note
-rw-r--r--compiler/rustc_lint/src/context.rs10
-rw-r--r--compiler/rustc_middle/src/lint.rs29
-rw-r--r--compiler/rustc_session/src/session.rs21
-rw-r--r--tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs22
-rw-r--r--tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr23
5 files changed, 99 insertions, 6 deletions
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index cb159a0b914..e9bd9dccdf1 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -24,7 +24,7 @@ use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::{PrintError, PrintTraitRefExt as _, Printer, with_no_trimmed_paths};
 use rustc_middle::ty::{self, GenericArg, RegisteredTools, Ty, TyCtxt, TypingEnv, TypingMode};
 use rustc_session::lint::{FutureIncompatibleInfo, Lint, LintBuffer, LintExpectationId, LintId};
-use rustc_session::{LintStoreMarker, Session};
+use rustc_session::{DynLintStore, Session};
 use rustc_span::edit_distance::find_best_match_for_names;
 use rustc_span::{Ident, Span, Symbol, sym};
 use tracing::debug;
@@ -62,7 +62,13 @@ pub struct LintStore {
     lint_groups: FxIndexMap<&'static str, LintGroup>,
 }
 
-impl LintStoreMarker for LintStore {}
+impl DynLintStore for LintStore {
+    fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = rustc_session::LintGroup> + '_> {
+        Box::new(self.get_lint_groups().map(|(name, lints, is_externally_loaded)| {
+            rustc_session::LintGroup { name, lints, is_externally_loaded }
+        }))
+    }
+}
 
 /// The target of the `by_name` map, which accounts for renaming/deprecation.
 #[derive(Debug)]
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 341a735f88f..f70b7b6fad7 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -211,11 +211,28 @@ impl LintExpectation {
 }
 
 fn explain_lint_level_source(
+    sess: &Session,
     lint: &'static Lint,
     level: Level,
     src: LintLevelSource,
     err: &mut Diag<'_, ()>,
 ) {
+    // Find the name of the lint group that contains the given lint.
+    // Assumes the lint only belongs to one group.
+    let lint_group_name = |lint| {
+        let lint_groups_iter = sess.lint_groups_iter();
+        let lint_id = LintId::of(lint);
+        lint_groups_iter
+            .filter(|lint_group| !lint_group.is_externally_loaded)
+            .find(|lint_group| {
+                lint_group
+                    .lints
+                    .iter()
+                    .find(|lint_group_lint| **lint_group_lint == lint_id)
+                    .is_some()
+            })
+            .map(|lint_group| lint_group.name)
+    };
     let name = lint.name_lower();
     if let Level::Allow = level {
         // Do not point at `#[allow(compat_lint)]` as the reason for a compatibility lint
@@ -224,7 +241,15 @@ fn explain_lint_level_source(
     }
     match src {
         LintLevelSource::Default => {
-            err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name));
+            let level_str = level.as_str();
+            match lint_group_name(lint) {
+                Some(group_name) => {
+                    err.note_once(format!("`#[{level_str}({name})]` (part of `#[{level_str}({group_name})]`) on by default"));
+                }
+                None => {
+                    err.note_once(format!("`#[{level_str}({name})]` on by default"));
+                }
+            }
         }
         LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
             let flag = orig_level.to_cmd_flag();
@@ -427,7 +452,7 @@ pub fn lint_level(
             decorate(&mut err);
         }
 
-        explain_lint_level_source(lint, level, src, &mut err);
+        explain_lint_level_source(sess, lint, level, src, &mut err);
         err.emit()
     }
     lint_level_impl(sess, lint, level, span, Box::new(decorate))
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index c8f4b511a7e..bb7ffa2a85d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -44,6 +44,7 @@ use crate::config::{
     SwitchWithOptPath,
 };
 use crate::filesearch::FileSearch;
+use crate::lint::LintId;
 use crate::parse::{ParseSess, add_feature_diagnostics};
 use crate::search_paths::SearchPath;
 use crate::{errors, filesearch, lint};
@@ -139,7 +140,10 @@ pub struct CompilerIO {
     pub temps_dir: Option<PathBuf>,
 }
 
-pub trait LintStoreMarker: Any + DynSync + DynSend {}
+pub trait DynLintStore: Any + DynSync + DynSend {
+    /// Provides a way to access lint groups without depending on `rustc_lint`
+    fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_>;
+}
 
 /// Represents the data associated with a compilation
 /// session for a single crate.
@@ -164,7 +168,7 @@ pub struct Session {
     pub code_stats: CodeStats,
 
     /// This only ever stores a `LintStore` but we don't want a dependency on that type here.
-    pub lint_store: Option<Arc<dyn LintStoreMarker>>,
+    pub lint_store: Option<Arc<dyn DynLintStore>>,
 
     /// Cap lint level specified by a driver specifically.
     pub driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
@@ -240,6 +244,12 @@ impl CodegenUnits {
     }
 }
 
+pub struct LintGroup {
+    pub name: &'static str,
+    pub lints: Vec<LintId>,
+    pub is_externally_loaded: bool,
+}
+
 impl Session {
     pub fn miri_unleashed_feature(&self, span: Span, feature_gate: Option<Symbol>) {
         self.miri_unleashed_features.lock().push((span, feature_gate));
@@ -596,6 +606,13 @@ impl Session {
             (&*self.target.staticlib_prefix, &*self.target.staticlib_suffix)
         }
     }
+
+    pub fn lint_groups_iter(&self) -> Box<dyn Iterator<Item = LintGroup> + '_> {
+        match self.lint_store {
+            Some(ref lint_store) => lint_store.lint_groups_iter(),
+            None => Box::new(std::iter::empty()),
+        }
+    }
 }
 
 // JUSTIFICATION: defn of the suggested wrapper fns
diff --git a/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs
new file mode 100644
index 00000000000..5db7cc02baa
--- /dev/null
+++ b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+
+// Verify information about membership to builtin lint group is included in the lint message when
+// explaining lint level and source for builtin lints with default settings.
+//
+// Ideally, we'd like to use lints that are part of `unused` group as shown in the issue.
+// This is not possible in a ui test, because `unused` lints are enabled with `-A unused`
+// in such tests, and the we're testing a scenario with no modification to the default settings.
+
+fn main() {
+    // additional context is provided only if the level is not explicitly set
+    let WrongCase = 1;
+    //~^ WARN [non_snake_case]
+    //~| NOTE `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
+
+    // unchanged message if the level is explicitly set
+    // even if the level is the same as the default
+    #[warn(nonstandard_style)] //~ NOTE the lint level is defined here
+    let WrongCase = 2;
+    //~^ WARN [non_snake_case]
+    //~| NOTE `#[warn(non_snake_case)]` implied by `#[warn(nonstandard_style)]`
+}
diff --git a/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr
new file mode 100644
index 00000000000..86ec59220f0
--- /dev/null
+++ b/tests/ui/lint/mention-lint-group-in-default-level-lint-note-issue-65464.stderr
@@ -0,0 +1,23 @@
+warning: variable `WrongCase` should have a snake case name
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:12:9
+   |
+LL |     let WrongCase = 1;
+   |         ^^^^^^^^^ help: convert the identifier to snake case: `wrong_case`
+   |
+   = note: `#[warn(non_snake_case)]` (part of `#[warn(nonstandard_style)]`) on by default
+
+warning: variable `WrongCase` should have a snake case name
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:19:9
+   |
+LL |     let WrongCase = 2;
+   |         ^^^^^^^^^ help: convert the identifier to snake case: `wrong_case`
+   |
+note: the lint level is defined here
+  --> $DIR/mention-lint-group-in-default-level-lint-note-issue-65464.rs:18:12
+   |
+LL |     #[warn(nonstandard_style)]
+   |            ^^^^^^^^^^^^^^^^^
+   = note: `#[warn(non_snake_case)]` implied by `#[warn(nonstandard_style)]`
+
+warning: 2 warnings emitted
+