diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 637052eb87530..f5a07840a3322 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -603,7 +603,10 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { return ImplItemCheckResult::Dead { require: adt_def_id }; } - return match trait_comes_from_allow { + let comes_from_allow = trait_comes_from_allow + .or_else(|| has_allow_dead_code_or_lang_attr(self.tcx, adt_def_id)); + + return match comes_from_allow { Some(comes_from_allow) => ImplItemCheckResult::Live(comes_from_allow), None => ImplItemCheckResult::Dead { require: adt_def_id }, }; @@ -940,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. @@ -981,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/allow-adt-propagation-to-impls.rs b/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.rs index 72d68c3e91396..26496dbad4323 100644 --- a/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.rs +++ b/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![deny(dead_code)] pub trait Tr { @@ -13,6 +15,6 @@ impl Tr for Foo { } } -fn bar() {} //~ ERROR function `bar` is never used +fn bar() {} fn main() {} diff --git a/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.stderr b/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.stderr deleted file mode 100644 index ba0fe951e4e59..0000000000000 --- a/tests/ui/lint/dead-code/allow-adt-propagation-to-impls.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: function `bar` is never used - --> $DIR/allow-adt-propagation-to-impls.rs:16:4 - | -LL | fn bar() {} - | ^^^ - | -note: the lint level is defined here - --> $DIR/allow-adt-propagation-to-impls.rs:1:9 - | -LL | #![deny(dead_code)] - | ^^^^^^^^^ - -error: aborting due to 1 previous error - 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() {}