From 13aaa5ef733dd0860b4cc69d9280e3b15e900226 Mon Sep 17 00:00:00 2001 From: mu001999 Date: Sun, 14 Jun 2026 22:42:09 +0800 Subject: [PATCH] Propagate `#[allow(dead_code)]` on adts to their inherent impls --- compiler/rustc_passes/src/dead.rs | 83 ++++++++++++------- .../unused-impl-for-allow-dead-type.rs | 24 ++++++ 2 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 tests/ui/lint/dead-code/unused-impl-for-allow-dead-type.rs diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index d6a8b2c2f5eb6..b8e3e7bb2d26f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -943,38 +943,63 @@ fn maybe_record_as_seed<'tcx>( }); } + let self_comes_from_allow = |impl_did| { + if let ty::Adt(adt, _) = + tcx.type_of(impl_did).instantiate_identity().skip_normalization().kind() + && let Some(adt_def_id) = adt.did().as_local() + { + has_allow_dead_code_or_lang_attr(tcx, adt_def_id) + } else { + None + } + }; + match tcx.def_kind(owner_id) { - DefKind::Enum => { - if let Some(comes_from_allow) = allow_dead_code { - let adt = tcx.adt_def(owner_id); - for variant in adt.variants().iter() { - push_into_worklist(WorkItem { - id: variant.def_id.expect_local(), - propagated: comes_from_allow, - own: comes_from_allow, - }); - } + DefKind::Enum if let Some(comes_from_allow) = allow_dead_code => { + let adt = tcx.adt_def(owner_id); + for variant in adt.variants().iter() { + push_into_worklist(WorkItem { + id: variant.def_id.expect_local(), + propagated: comes_from_allow, + own: comes_from_allow, + }); } } - DefKind::AssocFn | DefKind::AssocConst { .. } | DefKind::AssocTy => { - if allow_dead_code.is_none() { - let parent = tcx.local_parent(owner_id.def_id); - match tcx.def_kind(parent) { - DefKind::Impl { of_trait: false } | DefKind::Trait => {} - DefKind::Impl { of_trait: true } => { + DefKind::AssocFn | DefKind::AssocConst { .. } | DefKind::AssocTy + if allow_dead_code.is_none() => + { + let parent = tcx.local_parent(owner_id.def_id); + match tcx.def_kind(parent) { + DefKind::Trait => {} + DefKind::Impl { of_trait } => { + if of_trait { // We only care about associated items of traits, // because they cannot be visited directly, // so we later mark them as live if their corresponding traits // or trait items and self types are both live, // but inherent associated items can be visited and marked directly. unsolved_items.push(owner_id.def_id); + } else if let Some(comes_from_allow) = self_comes_from_allow(parent) { + push_into_worklist(WorkItem { + id: owner_id.def_id, + propagated: comes_from_allow, + own: ComesFromAllowExpect::No, + }); } - _ => bug!(), } + _ => bug!(), } } - DefKind::Impl { of_trait: true } if allow_dead_code.is_none() => { - unsolved_items.push(owner_id.def_id); + DefKind::Impl { of_trait } if allow_dead_code.is_none() => { + if of_trait { + unsolved_items.push(owner_id.def_id); + } else if let Some(comes_from_allow) = self_comes_from_allow(owner_id.def_id) { + push_into_worklist(WorkItem { + id: owner_id.def_id, + propagated: comes_from_allow, + own: ComesFromAllowExpect::No, + }); + } } DefKind::GlobalAsm => { // global_asm! is always live. @@ -984,17 +1009,15 @@ fn maybe_record_as_seed<'tcx>( own: ComesFromAllowExpect::No, }); } - DefKind::Const { .. } => { - if tcx.item_name(owner_id.def_id) == kw::Underscore { - // `const _` is always live, as that syntax only exists for the side effects - // of type checking and evaluating the constant expression, and marking them - // as dead code would defeat that purpose. - push_into_worklist(WorkItem { - id: owner_id.def_id, - propagated: ComesFromAllowExpect::No, - own: ComesFromAllowExpect::No, - }); - } + DefKind::Const { .. } if tcx.item_name(owner_id.def_id) == kw::Underscore => { + // `const _` is always live, as that syntax only exists for the side effects + // of type checking and evaluating the constant expression, and marking them + // as dead code would defeat that purpose. + push_into_worklist(WorkItem { + id: owner_id.def_id, + propagated: ComesFromAllowExpect::No, + own: ComesFromAllowExpect::No, + }); } _ => {} } diff --git a/tests/ui/lint/dead-code/unused-impl-for-allow-dead-type.rs b/tests/ui/lint/dead-code/unused-impl-for-allow-dead-type.rs new file mode 100644 index 0000000000000..6167cfaef3e60 --- /dev/null +++ b/tests/ui/lint/dead-code/unused-impl-for-allow-dead-type.rs @@ -0,0 +1,24 @@ +//@ check-pass + +#![deny(dead_code)] + +#[allow(dead_code)] +struct Foo; + +impl Foo { + fn foo(&self) {} +} + +pub trait Tr { + fn foo(&self); +} + +impl Tr for Foo { + fn foo(&self) { + bar() + } +} + +fn bar() {} + +fn main() {}