From 4fd61dd4a8e51cc26dd972b649a0a63b459b4a5c Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 28 Sep 2025 18:12:17 -0400 Subject: [PATCH 1/2] Add warn-by-default lint for visibility on `const _` declarations Add a warn-by-default `unused_visibility` lint for visibility qualifiers on `const _` declarations - e.g. `pub const _: () = ();`. These have no effect. --- .../rustc_ast_passes/src/ast_validation.rs | 15 +++++++++++-- compiler/rustc_lint/messages.ftl | 3 +++ compiler/rustc_lint/src/early/diagnostics.rs | 3 +++ compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_lint/src/lints.rs | 7 +++++++ compiler/rustc_lint_defs/src/builtin.rs | 21 +++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 1 + .../absolute_paths.no_short.stderr | 6 +++--- .../ui-toml/absolute_paths/absolute_paths.rs | 2 +- tests/ui/consts/promoted_const_call3.rs | 4 ++-- tests/ui/consts/ptr_is_null.rs | 10 ++++----- ...-dont-override-forbid-in-same-scope.stderr | 18 ++++++++++++++++ tests/ui/lint/outer-forbid.stderr | 18 ++++++++++++++++ tests/ui/lint/unused-visibilities.fixed | 12 +++++++++++ tests/ui/lint/unused-visibilities.rs | 12 +++++++++++ tests/ui/lint/unused-visibilities.stderr | 20 ++++++++++++++++++ tests/ui/traits/const-traits/call.rs | 2 +- 17 files changed, 141 insertions(+), 14 deletions(-) create mode 100644 tests/ui/lint/unused-visibilities.fixed create mode 100644 tests/ui/lint/unused-visibilities.rs create mode 100644 tests/ui/lint/unused-visibilities.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index f773b02058ef1..bad53abc3691a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -33,7 +33,7 @@ use rustc_session::Session; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN, - PATTERNS_IN_FNS_WITHOUT_BODY, + PATTERNS_IN_FNS_WITHOUT_BODY, UNUSED_VISIBILITIES, }; use rustc_span::{Ident, Span, kw, sym}; use rustc_target::spec::{AbiMap, AbiMapping}; @@ -1236,7 +1236,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { } }); } - ItemKind::Const(box ConstItem { defaultness, expr, .. }) => { + ItemKind::Const(box ConstItem { defaultness, ident, expr, .. }) => { self.check_defaultness(item.span, *defaultness); if expr.is_none() { self.dcx().emit_err(errors::ConstWithoutBody { @@ -1244,6 +1244,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { replace_span: self.ending_semi_or_hi(item.span), }); } + if ident.name == kw::Underscore + && !matches!(item.vis.kind, VisibilityKind::Inherited) + { + self.lint_buffer.buffer_lint( + UNUSED_VISIBILITIES, + item.id, + item.vis.span, + BuiltinLintDiag::UnusedVisibility(item.vis.span), + ) + } + visit::walk_item(self, item); } ItemKind::Static(box StaticItem { expr, safety, .. }) => { diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 5b98c9fafaad4..2ae607abd04bb 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -956,6 +956,9 @@ lint_unused_op = unused {$op} that must be used lint_unused_result = unused result of type `{$ty}` +lint_unused_visibilities = visibility qualifiers have no effect on `const _` declarations + .suggestion = remove the qualifier + lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result lint_useless_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 9029ee0447110..67599a95fbcc9 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -361,5 +361,8 @@ pub fn decorate_builtin_lint( BuiltinLintDiag::OutOfScopeMacroCalls { span, path, location } => { lints::OutOfScopeMacroCalls { span, path, location }.decorate_lint(diag) } + BuiltinLintDiag::UnusedVisibility(span) => { + lints::UnusedVisibility { span }.decorate_lint(diag) + } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 9bb53fea54a18..eb18a612a62ae 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -288,6 +288,7 @@ fn register_builtins(store: &mut LintStore) { "unused", UNUSED_IMPORTS, UNUSED_VARIABLES, + UNUSED_VISIBILITIES, UNUSED_ASSIGNMENTS, DEAD_CODE, UNUSED_MUT, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b7312484de5cd..30608d3d8d8b5 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -3188,3 +3188,10 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } } + +#[derive(LintDiagnostic)] +#[diag(lint_unused_visibilities)] +pub(crate) struct UnusedVisibility { + #[suggestion(style = "short", code = "", applicability = "machine-applicable")] + pub span: Span, +} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 939f3d088b12f..05b6db94766d9 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -141,6 +141,7 @@ declare_lint_pass! { UNUSED_QUALIFICATIONS, UNUSED_UNSAFE, UNUSED_VARIABLES, + UNUSED_VISIBILITIES, USELESS_DEPRECATED, WARNINGS, // tidy-alphabetical-end @@ -690,6 +691,26 @@ declare_lint! { "detect variables which are not used in any way" } +declare_lint! { + /// The `unused_visibilities` lint detects visibility qualifiers (like `pub`) + /// on a `const _` item. + /// + /// ### Example + /// + /// ```rust + /// pub const _: () = {}; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// These qualifiers have no effect. + pub UNUSED_VISIBILITIES, + Warn, + "detect visibility qualifiers on `const _` items" +} + declare_lint! { /// The `unused_assignments` lint detects assignments that will never be read. /// diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 40a818a3c9dc7..94c90eba1212d 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -748,6 +748,7 @@ pub enum BuiltinLintDiag { path: String, location: String, }, + UnusedVisibility(Span), } pub type RegisteredTools = FxIndexSet; diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr index 70d71f6c4ea16..c94b7777f3e9f 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.no_short.stderr @@ -71,10 +71,10 @@ LL | impl core::fmt::Display for X | ^^^^^^^^^^^^^^^^^^ error: consider bringing this path into scope with the `use` keyword - --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:14 + --> tests/ui-toml/absolute_paths/absolute_paths.rs:113:10 | -LL | pub const _: crate::S = { - | ^^^^^^^^ +LL | const _: crate::S = { + | ^^^^^^^^ error: consider bringing this path into scope with the `use` keyword --> tests/ui-toml/absolute_paths/absolute_paths.rs:114:9 diff --git a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs index c024f2f513ced..a3982b8f6540d 100644 --- a/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs +++ b/src/tools/clippy/tests/ui-toml/absolute_paths/absolute_paths.rs @@ -110,7 +110,7 @@ mod m1 { } //~[no_short]v absolute_paths -pub const _: crate::S = { +const _: crate::S = { let crate::S = m1::S; //~[no_short] absolute_paths crate::m1::S diff --git a/tests/ui/consts/promoted_const_call3.rs b/tests/ui/consts/promoted_const_call3.rs index dc05a3b584424..82e9eac31d5cc 100644 --- a/tests/ui/consts/promoted_const_call3.rs +++ b/tests/ui/consts/promoted_const_call3.rs @@ -4,12 +4,12 @@ pub const C: () = { //~^ ERROR: destructor of `String` cannot be evaluated at compile-time }; -pub const _: () = { +const _: () = { let _: &'static _ = &id(&String::new()); //~^ ERROR: destructor of `String` cannot be evaluated at compile-time }; -pub const _: () = { +const _: () = { let _: &'static _ = &std::mem::ManuallyDrop::new(String::new()); //~^ ERROR: temporary value dropped while borrowed }; diff --git a/tests/ui/consts/ptr_is_null.rs b/tests/ui/consts/ptr_is_null.rs index 8b41f5718e8db..9f8a1697fd70e 100644 --- a/tests/ui/consts/ptr_is_null.rs +++ b/tests/ui/consts/ptr_is_null.rs @@ -5,12 +5,12 @@ const FOO: &usize = &42; -pub const _: () = assert!(!(FOO as *const usize).is_null()); +const _: () = assert!(!(FOO as *const usize).is_null()); -pub const _: () = assert!(!(42 as *const usize).is_null()); +const _: () = assert!(!(42 as *const usize).is_null()); -pub const _: () = assert!((0 as *const usize).is_null()); +const _: () = assert!((0 as *const usize).is_null()); -pub const _: () = assert!(std::ptr::null::().is_null()); +const _: () = assert!(std::ptr::null::().is_null()); -pub const _: () = assert!(!("foo" as *const str).is_null()); +const _: () = assert!(!("foo" as *const str).is_null()); diff --git a/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr index 77c8d1eab5845..506791fd17269 100644 --- a/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr +++ b/tests/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -413,3 +413,21 @@ note: the lint level is defined here LL | #![forbid(forbidden_lint_groups)] | ^^^^^^^^^^^^^^^^^^^^^ +Future breakage diagnostic: +error: warn(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:22:13 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | #![deny(unused)] +LL | #![warn(unused)] + | ^^^^^^ overruled by previous forbid + | + = 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 #81670 +note: the lint level is defined here + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/lint/outer-forbid.stderr b/tests/ui/lint/outer-forbid.stderr index 64a1077462abe..7810ca223f8ad 100644 --- a/tests/ui/lint/outer-forbid.stderr +++ b/tests/ui/lint/outer-forbid.stderr @@ -453,3 +453,21 @@ note: the lint level is defined here LL | #![forbid(forbidden_lint_groups)] | ^^^^^^^^^^^^^^^^^^^^^ +Future breakage diagnostic: +error: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:25:9 + | +LL | #![forbid(unused, non_snake_case)] + | ------ `forbid` level set here +... +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + | + = 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 #81670 +note: the lint level is defined here + --> $DIR/outer-forbid.rs:18:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + diff --git a/tests/ui/lint/unused-visibilities.fixed b/tests/ui/lint/unused-visibilities.fixed new file mode 100644 index 0000000000000..3dd7cde0c9e2a --- /dev/null +++ b/tests/ui/lint/unused-visibilities.fixed @@ -0,0 +1,12 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused_visibilities)] + + const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + + const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +fn main() {} diff --git a/tests/ui/lint/unused-visibilities.rs b/tests/ui/lint/unused-visibilities.rs new file mode 100644 index 0000000000000..51bcd34599ad2 --- /dev/null +++ b/tests/ui/lint/unused-visibilities.rs @@ -0,0 +1,12 @@ +//@ check-pass +//@ run-rustfix + +#![warn(unused_visibilities)] + +pub const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +pub(self) const _: () = {}; +//~^WARN visibility qualifiers have no effect on `const _` declarations + +fn main() {} diff --git a/tests/ui/lint/unused-visibilities.stderr b/tests/ui/lint/unused-visibilities.stderr new file mode 100644 index 0000000000000..032e2821d9873 --- /dev/null +++ b/tests/ui/lint/unused-visibilities.stderr @@ -0,0 +1,20 @@ +warning: visibility qualifiers have no effect on `const _` declarations + --> $DIR/unused-visibilities.rs:6:1 + | +LL | pub const _: () = {}; + | ^^^ help: remove the qualifier + | +note: the lint level is defined here + --> $DIR/unused-visibilities.rs:4:9 + | +LL | #![warn(unused_visibilities)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: visibility qualifiers have no effect on `const _` declarations + --> $DIR/unused-visibilities.rs:9:1 + | +LL | pub(self) const _: () = {}; + | ^^^^^^^^^ help: remove the qualifier + +warning: 2 warnings emitted + diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index b1080fe78bb5f..360c08e1b7fe9 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -3,7 +3,7 @@ #![feature(const_closures, const_trait_impl)] #![allow(incomplete_features)] -pub const _: () = { +const _: () = { assert!((const || true)()); //~^ ERROR }: [const] Fn()` is not satisfied }; From 481d3a1293b04575d947abfa6a022fd3461d3b80 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Tue, 30 Sep 2025 10:05:20 -0400 Subject: [PATCH 2/2] Elaborate lint explanation --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 05b6db94766d9..43be28a6c6eed 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -705,7 +705,7 @@ declare_lint! { /// /// ### Explanation /// - /// These qualifiers have no effect. + /// These qualifiers have no effect, as `const _` items are unnameable. pub UNUSED_VISIBILITIES, Warn, "detect visibility qualifiers on `const _` items"