diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 4e0ba376b7d..ca3941c06f4 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -421,6 +421,7 @@ lint_non_local_definitions_impl = non-local `impl` definition, they should be av } .non_local = an `impl` definition is non-local if it is nested inside an item and neither the type nor the trait are at the same nesting level as the `impl` block .exception = one exception to the rule are anon-const (`const _: () = {"{"} ... {"}"}`) at top-level module and anon-const at the same nesting as the trait or type + .const_anon = use a const-anon item to suppress this lint lint_non_local_definitions_macro_rules = non-local `macro_rules!` definition, they should be avoided as they go against expectation .help = diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 15f158961d0..1a56fa751c2 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1301,7 +1301,13 @@ pub enum NonLocalDefinitionsDiag { #[note(lint_non_local)] #[note(lint_exception)] #[note(lint_non_local_definitions_deprecation)] - Impl { depth: u32, body_kind_descr: &'static str, body_name: String }, + Impl { + depth: u32, + body_kind_descr: &'static str, + body_name: String, + #[suggestion(lint_const_anon, code = "_", applicability = "machine-applicable")] + const_anon: Option, + }, #[diag(lint_non_local_definitions_macro_rules)] #[help] #[note(lint_non_local)] diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs index 28bd49f36a0..bfd7b4a72f9 100644 --- a/compiler/rustc_lint/src/non_local_def.rs +++ b/compiler/rustc_lint/src/non_local_def.rs @@ -1,4 +1,4 @@ -use rustc_hir::{def::DefKind, Body, Item, ItemKind, Path, QPath, TyKind}; +use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, Path, QPath, TyKind}; use rustc_span::{def_id::DefId, sym, symbol::kw, MacroKind}; use smallvec::{smallvec, SmallVec}; @@ -140,6 +140,19 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { // If none of them have a local parent (LOGICAL NOR) this means that // this impl definition is a non-local definition and so we lint on it. if !(self_ty_has_local_parent || of_trait_has_local_parent) { + let const_anon = if self.body_depth == 1 + && parent_def_kind == DefKind::Const + && parent_opt_item_name != Some(kw::Underscore) + && let Some(parent) = parent.as_local() + && let Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) + && let ItemKind::Const(ty, _, _) = item.kind + && let TyKind::Tup(&[]) = ty.kind + { + Some(item.ident.span) + } else { + None + }; + cx.emit_span_lint( NON_LOCAL_DEFINITIONS, item.span, @@ -149,6 +162,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions { body_name: parent_opt_item_name .map(|s| s.to_ident_string()) .unwrap_or_else(|| "".to_string()), + const_anon, }, ) } diff --git a/tests/ui/lint/non_local_definitions.stderr b/tests/ui/lint/non_local_definitions.stderr index f15457734bc..8403357b115 100644 --- a/tests/ui/lint/non_local_definitions.stderr +++ b/tests/ui/lint/non_local_definitions.stderr @@ -1,6 +1,9 @@ warning: non-local `impl` definition, they should be avoided as they go against expectation --> $DIR/non_local_definitions.rs:32:5 | +LL | const Z: () = { + | - help: use a const-anon item to suppress this lint: `_` +... LL | impl Uto for &Test {} | ^^^^^^^^^^^^^^^^^^^^^ |