From 975741c29417034e9026e53fba16f3b7d5c5721b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 11:59:42 +0200 Subject: [PATCH 1/2] add test for dead code caused by enum variants shadowing an associated function --- .../ui/enum/dead-code-associated-function.rs | 20 +++++++++++++++++++ .../enum/dead-code-associated-function.stderr | 20 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/ui/enum/dead-code-associated-function.rs create mode 100644 tests/ui/enum/dead-code-associated-function.stderr diff --git a/tests/ui/enum/dead-code-associated-function.rs b/tests/ui/enum/dead-code-associated-function.rs new file mode 100644 index 0000000000000..d172ceb41dde4 --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.rs @@ -0,0 +1,20 @@ +//@ check-pass +#![warn(dead_code)] + +enum E { + F(), + C(), +} + +impl E { + #[expect(non_snake_case)] + fn F() {} + //~^ WARN: associated items `F` and `C` are never used + + const C: () = (); +} + +fn main() { + let _: E = E::F(); + let _: E = E::C(); +} diff --git a/tests/ui/enum/dead-code-associated-function.stderr b/tests/ui/enum/dead-code-associated-function.stderr new file mode 100644 index 0000000000000..df968783c27af --- /dev/null +++ b/tests/ui/enum/dead-code-associated-function.stderr @@ -0,0 +1,20 @@ +warning: associated items `F` and `C` are never used + --> $DIR/dead-code-associated-function.rs:11:8 + | +LL | impl E { + | ------ associated items in this implementation +LL | #[expect(non_snake_case)] +LL | fn F() {} + | ^ +... +LL | const C: () = (); + | ^ + | +note: the lint level is defined here + --> $DIR/dead-code-associated-function.rs:2:9 + | +LL | #![warn(dead_code)] + | ^^^^^^^^^ + +warning: 1 warning emitted + From 2e7e52e07cec3adb2b14ce17faffe039216ed9d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Thu, 12 Jun 2025 10:21:30 +0200 Subject: [PATCH 2/2] detect when variants have the same name as an associated function --- compiler/rustc_passes/messages.ftl | 3 ++ compiler/rustc_passes/src/dead.rs | 30 ++++++++++++++++++- compiler/rustc_passes/src/errors.rs | 12 ++++++++ .../enum/dead-code-associated-function.stderr | 10 +++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index a4ef065ea2c83..81c7b42b105b5 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -290,6 +290,9 @@ passes_duplicate_lang_item_crate_depends = .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path} .second_definition_path = second definition in `{$crate_name}` loaded from {$path} +passes_enum_variant_same_name = + it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name + passes_export_name = attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index e597c819a3aae..4257d8e8d16bd 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -14,7 +14,7 @@ use rustc_errors::MultiSpan; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{self as hir, Node, PatKind, QPath, TyKind}; +use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; use rustc_middle::query::Providers; @@ -936,7 +936,9 @@ enum ShouldWarnAboutField { #[derive(Debug, Copy, Clone, PartialEq, Eq)] enum ReportOn { + /// Report on something that hasn't got a proper name to refer to TupleField, + /// Report on something that has got a name, which could be a field but also a method NamedField, } @@ -1061,6 +1063,31 @@ impl<'tcx> DeadVisitor<'tcx> { None }; + let enum_variants_with_same_name = dead_codes + .iter() + .filter_map(|dead_item| { + if let Node::ImplItem(ImplItem { + kind: ImplItemKind::Fn(..) | ImplItemKind::Const(..), + .. + }) = tcx.hir_node_by_def_id(dead_item.def_id) + && let Some(impl_did) = tcx.opt_parent(dead_item.def_id.to_def_id()) + && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did) + && let ty::Adt(maybe_enum, _) = tcx.type_of(impl_did).skip_binder().kind() + && maybe_enum.is_enum() + && let Some(variant) = + maybe_enum.variants().iter().find(|i| i.name == dead_item.name) + { + Some(crate::errors::EnumVariantSameName { + descr: tcx.def_descr(dead_item.def_id.to_def_id()), + dead_name: dead_item.name, + variant_span: tcx.def_span(variant.def_id), + }) + } else { + None + } + }) + .collect(); + let diag = match report_on { ReportOn::TupleField => { let tuple_fields = if let Some(parent_id) = parent_item @@ -1114,6 +1141,7 @@ impl<'tcx> DeadVisitor<'tcx> { name_list, parent_info, ignored_derived_impls, + enum_variants_with_same_name, }, }; diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 74ce92624bd49..74c89f0c698b5 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1478,6 +1478,9 @@ pub(crate) enum MultipleDeadCodes<'tcx> { participle: &'tcx str, name_list: DiagSymbolList, #[subdiagnostic] + // only on DeadCodes since it's never a problem for tuple struct fields + enum_variants_with_same_name: Vec>, + #[subdiagnostic] parent_info: Option>, #[subdiagnostic] ignored_derived_impls: Option, @@ -1498,6 +1501,15 @@ pub(crate) enum MultipleDeadCodes<'tcx> { }, } +#[derive(Subdiagnostic)] +#[note(passes_enum_variant_same_name)] +pub(crate) struct EnumVariantSameName<'tcx> { + #[primary_span] + pub variant_span: Span, + pub dead_name: Symbol, + pub descr: &'tcx str, +} + #[derive(Subdiagnostic)] #[label(passes_parent_info)] pub(crate) struct ParentInfo<'tcx> { diff --git a/tests/ui/enum/dead-code-associated-function.stderr b/tests/ui/enum/dead-code-associated-function.stderr index df968783c27af..e3c1a4c81a491 100644 --- a/tests/ui/enum/dead-code-associated-function.stderr +++ b/tests/ui/enum/dead-code-associated-function.stderr @@ -10,6 +10,16 @@ LL | fn F() {} LL | const C: () = (); | ^ | +note: it is impossible to refer to the associated function `F` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:5:5 + | +LL | F(), + | ^ +note: it is impossible to refer to the associated constant `C` because it is shadowed by this enum variant with the same name + --> $DIR/dead-code-associated-function.rs:6:5 + | +LL | C(), + | ^ note: the lint level is defined here --> $DIR/dead-code-associated-function.rs:2:9 |