Skip to content

Commit 0ff50d6

Browse files
committed
Allow adt will propagate to its impls
1 parent 1f08727 commit 0ff50d6

2 files changed

Lines changed: 101 additions & 67 deletions

File tree

compiler/rustc_passes/src/dead.rs

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ struct MarkSymbolVisitor<'tcx> {
129129
// macro)
130130
ignored_derived_traits: LocalDefIdMap<FxIndexSet<DefId>>,
131131
propagated_comes_from_allow_expect: ComesFromAllowExpect,
132+
unsolved_items: Vec<LocalDefId>,
132133
}
133134

134135
impl<'tcx> MarkSymbolVisitor<'tcx> {
@@ -544,13 +545,16 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
544545
/// `local_def_id` points to an impl or an impl item,
545546
/// both impl and impl item that may be passed to this function are of a trait,
546547
/// and added into the unsolved_items during `create_and_seed_worklist`
547-
fn check_impl_or_impl_item_live(&mut self, local_def_id: LocalDefId) -> bool {
548+
fn check_impl_or_impl_item_live(
549+
&self,
550+
local_def_id: LocalDefId,
551+
) -> Option<ComesFromAllowExpect> {
548552
let (impl_block_id, trait_def_id) = match self.tcx.def_kind(local_def_id) {
549553
// assoc impl items of traits are live if the corresponding trait items are live
550554
DefKind::AssocConst { .. } | DefKind::AssocTy | DefKind::AssocFn => {
551-
let trait_item_id =
555+
let trait_def_id =
552556
self.tcx.trait_item_of(local_def_id).and_then(|def_id| def_id.as_local());
553-
(self.tcx.local_parent(local_def_id), trait_item_id)
557+
(self.tcx.local_parent(local_def_id), trait_def_id)
554558
}
555559
// impl items are live if the corresponding traits are live
556560
DefKind::Impl { of_trait: true } => {
@@ -562,7 +566,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
562566
if let Some(trait_def_id) = trait_def_id
563567
&& !self.live_symbols.contains(&trait_def_id)
564568
{
565-
return false;
569+
return has_allow_dead_code_or_lang_attr(self.tcx, trait_def_id);
566570
}
567571

568572
// The impl or impl item is used if the corresponding trait or trait item is used and the ty is used.
@@ -571,10 +575,50 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
571575
&& let Some(adt_def_id) = adt.did().as_local()
572576
&& !self.live_symbols.contains(&adt_def_id)
573577
{
574-
return false;
578+
return has_allow_dead_code_or_lang_attr(self.tcx, adt_def_id);
575579
}
576580

577-
true
581+
Some(ComesFromAllowExpect::No)
582+
}
583+
584+
fn collect_live_items_from_unsolved_items(
585+
&mut self,
586+
) -> Vec<(LocalDefId, ComesFromAllowExpect)> {
587+
let mut unsolved_items = std::mem::take(&mut self.unsolved_items);
588+
let mut items_to_check = vec![];
589+
unsolved_items.retain(|&def_id| {
590+
if let Some(comes_from_allow) = self.check_impl_or_impl_item_live(def_id) {
591+
items_to_check.push((def_id, comes_from_allow));
592+
false
593+
} else {
594+
true
595+
}
596+
});
597+
self.unsolved_items = unsolved_items;
598+
items_to_check
599+
}
600+
601+
fn mark_live_symbols_and_ignored_derived_traits(&mut self) -> Result<(), ErrorGuaranteed> {
602+
if let ControlFlow::Break(guar) = self.mark_live_symbols() {
603+
return Err(guar);
604+
}
605+
606+
// We have marked the primary seeds as live. We now need to process unsolved items from traits
607+
// and trait impls: add them to the work list if the trait or the implemented type is live.
608+
let mut items_to_check = self.collect_live_items_from_unsolved_items();
609+
610+
while !items_to_check.is_empty() {
611+
self.worklist.extend(items_to_check.into_iter().map(|(id, comes_from_allow)| {
612+
WorkItem { id, propagated: comes_from_allow, own: comes_from_allow }
613+
}));
614+
if let ControlFlow::Break(guar) = self.mark_live_symbols() {
615+
return Err(guar);
616+
}
617+
618+
items_to_check = self.collect_live_items_from_unsolved_items();
619+
}
620+
621+
Ok(())
578622
}
579623
}
580624

@@ -843,21 +887,22 @@ fn maybe_record_as_seed<'tcx>(
843887
if allow_dead_code.is_none() {
844888
let parent = tcx.local_parent(owner_id.def_id);
845889
match tcx.def_kind(parent) {
846-
DefKind::Impl { of_trait: false } | DefKind::Trait => {}
847-
DefKind::Impl { of_trait: true } => {
848-
if let Some(trait_item_def_id) =
849-
tcx.associated_item(owner_id.def_id).trait_item_def_id()
850-
&& let Some(trait_item_local_def_id) = trait_item_def_id.as_local()
890+
DefKind::Trait => {}
891+
DefKind::Impl { of_trait: false } => {
892+
if let ty::Adt(adt, _) =
893+
tcx.type_of(parent).instantiate_identity().skip_norm_wip().kind()
894+
&& let Some(adt_def_id) = adt.did().as_local()
851895
&& let Some(comes_from_allow) =
852-
has_allow_dead_code_or_lang_attr(tcx, trait_item_local_def_id)
896+
has_allow_dead_code_or_lang_attr(tcx, adt_def_id)
853897
{
854898
push_into_worklist(WorkItem {
855899
id: owner_id.def_id,
856900
propagated: comes_from_allow,
857-
own: comes_from_allow,
901+
own: ComesFromAllowExpect::No,
858902
});
859903
}
860-
904+
}
905+
DefKind::Impl { of_trait: true } => {
861906
// We only care about associated items of traits,
862907
// because they cannot be visited directly,
863908
// so we later mark them as live if their corresponding traits
@@ -869,23 +914,22 @@ fn maybe_record_as_seed<'tcx>(
869914
}
870915
}
871916
}
872-
DefKind::Impl { of_trait: true } => {
873-
if allow_dead_code.is_none() {
874-
if let Some(trait_def_id) =
875-
tcx.impl_trait_ref(owner_id.def_id).skip_binder().def_id.as_local()
876-
&& let Some(comes_from_allow) =
877-
has_allow_dead_code_or_lang_attr(tcx, trait_def_id)
878-
{
879-
push_into_worklist(WorkItem {
880-
id: owner_id.def_id,
881-
propagated: comes_from_allow,
882-
own: comes_from_allow,
883-
});
884-
}
885-
886-
unsolved_items.push(owner_id.def_id);
917+
DefKind::Impl { of_trait: false } if allow_dead_code.is_none() => {
918+
if let ty::Adt(adt, _) =
919+
tcx.type_of(owner_id.def_id).instantiate_identity().skip_norm_wip().kind()
920+
&& let Some(adt_def_id) = adt.did().as_local()
921+
&& let Some(comes_from_allow) = has_allow_dead_code_or_lang_attr(tcx, adt_def_id)
922+
{
923+
push_into_worklist(WorkItem {
924+
id: owner_id.def_id,
925+
propagated: comes_from_allow,
926+
own: ComesFromAllowExpect::No,
927+
});
887928
}
888929
}
930+
DefKind::Impl { of_trait: true } if allow_dead_code.is_none() => {
931+
unsolved_items.push(owner_id.def_id);
932+
}
889933
DefKind::GlobalAsm => {
890934
// global_asm! is always live.
891935
push_into_worklist(WorkItem {
@@ -972,8 +1016,7 @@ fn live_symbols_and_ignored_derived_traits(
9721016
tcx: TyCtxt<'_>,
9731017
(): (),
9741018
) -> Result<DeadCodeLivenessSummary, ErrorGuaranteed> {
975-
let SeedWorklists { worklist, deferred_seeds, mut unsolved_items } =
976-
create_and_seed_worklist(tcx);
1019+
let SeedWorklists { worklist, deferred_seeds, unsolved_items } = create_and_seed_worklist(tcx);
9771020
let mut symbol_visitor = MarkSymbolVisitor {
9781021
worklist,
9791022
tcx,
@@ -986,15 +1029,16 @@ fn live_symbols_and_ignored_derived_traits(
9861029
ignore_variant_stack: vec![],
9871030
ignored_derived_traits: Default::default(),
9881031
propagated_comes_from_allow_expect: ComesFromAllowExpect::No,
1032+
unsolved_items,
9891033
};
990-
mark_live_symbols_and_ignored_derived_traits(&mut symbol_visitor, &mut unsolved_items)?;
1034+
symbol_visitor.mark_live_symbols_and_ignored_derived_traits()?;
9911035
let pre_deferred_seeding = DeadCodeLivenessSnapshot {
9921036
live_symbols: symbol_visitor.live_symbols.clone(),
9931037
ignored_derived_traits: symbol_visitor.ignored_derived_traits.clone(),
9941038
};
9951039

9961040
symbol_visitor.worklist.extend(deferred_seeds);
997-
mark_live_symbols_and_ignored_derived_traits(&mut symbol_visitor, &mut unsolved_items)?;
1041+
symbol_visitor.mark_live_symbols_and_ignored_derived_traits()?;
9981042

9991043
Ok(DeadCodeLivenessSummary {
10001044
pre_deferred_seeding,
@@ -1005,40 +1049,6 @@ fn live_symbols_and_ignored_derived_traits(
10051049
})
10061050
}
10071051

1008-
fn mark_live_symbols_and_ignored_derived_traits(
1009-
symbol_visitor: &mut MarkSymbolVisitor<'_>,
1010-
unsolved_items: &mut Vec<LocalDefId>,
1011-
) -> Result<(), ErrorGuaranteed> {
1012-
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
1013-
return Err(guar);
1014-
}
1015-
1016-
// We have marked the primary seeds as live. We now need to process unsolved items from traits
1017-
// and trait impls: add them to the work list if the trait or the implemented type is live.
1018-
let mut items_to_check: Vec<_> = unsolved_items
1019-
.extract_if(.., |&mut local_def_id| {
1020-
symbol_visitor.check_impl_or_impl_item_live(local_def_id)
1021-
})
1022-
.collect();
1023-
1024-
while !items_to_check.is_empty() {
1025-
symbol_visitor.worklist.extend(items_to_check.drain(..).map(|id| WorkItem {
1026-
id,
1027-
propagated: ComesFromAllowExpect::No,
1028-
own: ComesFromAllowExpect::No,
1029-
}));
1030-
if let ControlFlow::Break(guar) = symbol_visitor.mark_live_symbols() {
1031-
return Err(guar);
1032-
}
1033-
1034-
items_to_check.extend(unsolved_items.extract_if(.., |&mut local_def_id| {
1035-
symbol_visitor.check_impl_or_impl_item_live(local_def_id)
1036-
}));
1037-
}
1038-
1039-
Ok(())
1040-
}
1041-
10421052
struct DeadItem {
10431053
def_id: LocalDefId,
10441054
name: Symbol,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//@ check-pass
2+
3+
#![deny(dead_code)]
4+
5+
#[allow(dead_code)]
6+
struct Foo;
7+
8+
impl Foo {
9+
fn foo(&self) {}
10+
}
11+
12+
pub trait Tr {
13+
fn foo(&self);
14+
}
15+
16+
impl Tr for Foo {
17+
fn foo(&self) {
18+
bar()
19+
}
20+
}
21+
22+
fn bar() {}
23+
24+
fn main() {}

0 commit comments

Comments
 (0)