@@ -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
134135impl < ' tcx > MarkSymbolVisitor < ' tcx > {
@@ -544,13 +545,17 @@ 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+ defer_seeds_come_from_allow : bool ,
552+ ) -> Option < ComesFromAllowExpect > {
548553 let ( impl_block_id, trait_def_id) = match self . tcx . def_kind ( local_def_id) {
549554 // assoc impl items of traits are live if the corresponding trait items are live
550555 DefKind :: AssocConst { .. } | DefKind :: AssocTy | DefKind :: AssocFn => {
551- let trait_item_id =
556+ let trait_def_id =
552557 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 )
558+ ( self . tcx . local_parent ( local_def_id) , trait_def_id )
554559 }
555560 // impl items are live if the corresponding traits are live
556561 DefKind :: Impl { of_trait : true } => {
@@ -559,10 +564,19 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
559564 _ => bug ! ( ) ,
560565 } ;
561566
562- if let Some ( trait_def_id) = trait_def_id
563- && !self . live_symbols . contains ( & trait_def_id)
564- {
565- return false ;
567+ let mut trait_comes_from_allow = None ;
568+ if let Some ( trait_def_id) = trait_def_id {
569+ if defer_seeds_come_from_allow {
570+ if !self . live_symbols . contains ( & trait_def_id) {
571+ return None ;
572+ }
573+ } else {
574+ if !self . live_symbols . contains ( & trait_def_id) {
575+ return has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
576+ }
577+
578+ trait_comes_from_allow = has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
579+ }
566580 }
567581
568582 // The impl or impl item is used if the corresponding trait or trait item is used and the ty is used.
@@ -571,10 +585,70 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
571585 && let Some ( adt_def_id) = adt. did ( ) . as_local ( )
572586 && !self . live_symbols . contains ( & adt_def_id)
573587 {
574- return false ;
588+ if defer_seeds_come_from_allow {
589+ return None ;
590+ } else {
591+ return trait_comes_from_allow
592+ . or_else ( || has_allow_dead_code_or_lang_attr ( self . tcx , adt_def_id) ) ;
593+ }
575594 }
576595
577- true
596+ Some ( ComesFromAllowExpect :: No )
597+ }
598+
599+ fn collect_live_items_from_unsolved_items (
600+ & mut self ,
601+ defer_seeds_come_from_allow : bool ,
602+ ) -> Vec < ( LocalDefId , ComesFromAllowExpect ) > {
603+ let mut unsolved_items = std:: mem:: take ( & mut self . unsolved_items ) ;
604+ let mut items_to_check = vec ! [ ] ;
605+ unsolved_items. retain ( |& def_id| {
606+ let Some ( comes_from_allow) =
607+ self . check_impl_or_impl_item_live ( def_id, defer_seeds_come_from_allow)
608+ else {
609+ return true ;
610+ } ;
611+
612+ items_to_check. push ( ( def_id, comes_from_allow) ) ;
613+ false
614+ } ) ;
615+ self . unsolved_items = unsolved_items;
616+ items_to_check
617+ }
618+
619+ fn mark_live_symbols_and_ignored_derived_traits (
620+ & mut self ,
621+ defer_seeds_come_from_allow : bool ,
622+ ) -> Result < ( ) , ErrorGuaranteed > {
623+ if let ControlFlow :: Break ( guar) = self . mark_live_symbols ( ) {
624+ return Err ( guar) ;
625+ }
626+
627+ // We have marked the primary seeds as live. We now need to process unsolved items from traits
628+ // and trait impls: add them to the work list if the trait or the implemented type is live.
629+ let mut items_to_check =
630+ self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
631+
632+ while !items_to_check. is_empty ( ) {
633+ self . worklist . extend ( items_to_check. into_iter ( ) . map ( |( id, comes_from_allow) | {
634+ let own = if defer_seeds_come_from_allow {
635+ ComesFromAllowExpect :: No
636+ } else {
637+ has_allow_dead_code_or_lang_attr ( self . tcx , id)
638+ . unwrap_or ( ComesFromAllowExpect :: No )
639+ } ;
640+
641+ WorkItem { id, propagated : comes_from_allow, own }
642+ } ) ) ;
643+ if let ControlFlow :: Break ( guar) = self . mark_live_symbols ( ) {
644+ return Err ( guar) ;
645+ }
646+
647+ items_to_check =
648+ self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
649+ }
650+
651+ Ok ( ( ) )
578652 }
579653}
580654
@@ -843,21 +917,22 @@ fn maybe_record_as_seed<'tcx>(
843917 if allow_dead_code. is_none ( ) {
844918 let parent = tcx. local_parent ( owner_id. def_id ) ;
845919 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 ( )
920+ DefKind :: Trait => { }
921+ DefKind :: Impl { of_trait : false } => {
922+ if let ty :: Adt ( adt , _ ) =
923+ tcx. type_of ( parent ) . instantiate_identity ( ) . skip_normalization ( ) . kind ( )
924+ && let Some ( adt_def_id ) = adt . did ( ) . as_local ( )
851925 && let Some ( comes_from_allow) =
852- has_allow_dead_code_or_lang_attr ( tcx, trait_item_local_def_id )
926+ has_allow_dead_code_or_lang_attr ( tcx, adt_def_id )
853927 {
854928 push_into_worklist ( WorkItem {
855929 id : owner_id. def_id ,
856930 propagated : comes_from_allow,
857- own : comes_from_allow ,
931+ own : ComesFromAllowExpect :: No ,
858932 } ) ;
859933 }
860-
934+ }
935+ DefKind :: Impl { of_trait : true } => {
861936 // We only care about associated items of traits,
862937 // because they cannot be visited directly,
863938 // so we later mark them as live if their corresponding traits
@@ -869,23 +944,22 @@ fn maybe_record_as_seed<'tcx>(
869944 }
870945 }
871946 }
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 ) ;
947+ DefKind :: Impl { of_trait : false } if allow_dead_code. is_none ( ) => {
948+ if let ty:: Adt ( adt, _) =
949+ tcx. type_of ( owner_id. def_id ) . instantiate_identity ( ) . skip_normalization ( ) . kind ( )
950+ && let Some ( adt_def_id) = adt. did ( ) . as_local ( )
951+ && let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, adt_def_id)
952+ {
953+ push_into_worklist ( WorkItem {
954+ id : owner_id. def_id ,
955+ propagated : comes_from_allow,
956+ own : ComesFromAllowExpect :: No ,
957+ } ) ;
887958 }
888959 }
960+ DefKind :: Impl { of_trait : true } if allow_dead_code. is_none ( ) => {
961+ unsolved_items. push ( owner_id. def_id ) ;
962+ }
889963 DefKind :: GlobalAsm => {
890964 // global_asm! is always live.
891965 push_into_worklist ( WorkItem {
@@ -910,15 +984,21 @@ fn maybe_record_as_seed<'tcx>(
910984 }
911985}
912986
987+ #[ derive( Default ) ]
988+ struct DeferredSeeds {
989+ pub_reachables : Vec < WorkItem > ,
990+ come_from_allow : Vec < WorkItem > ,
991+ }
992+
913993struct SeedWorklists {
914994 worklist : Vec < WorkItem > ,
915- deferred_seeds : Vec < WorkItem > ,
995+ deferred_seeds : DeferredSeeds ,
916996 unsolved_items : Vec < LocalDefId > ,
917997}
918998
919999fn create_and_seed_worklist ( tcx : TyCtxt < ' _ > ) -> SeedWorklists {
9201000 let mut unsolved_items = Vec :: new ( ) ;
921- let mut deferred_seeds = Vec :: new ( ) ;
1001+ let mut deferred_seeds = DeferredSeeds :: default ( ) ;
9221002 let mut worklist = Vec :: new ( ) ;
9231003
9241004 if let Some ( ( def_id, _) ) = tcx. entry_fn ( ( ) )
@@ -948,7 +1028,7 @@ fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> SeedWorklists {
9481028
9491029 for ( id, effective_vis) in tcx. effective_visibilities ( ( ) ) . iter ( ) {
9501030 if effective_vis. is_public_at_level ( Level :: Reachable ) {
951- deferred_seeds. push ( WorkItem {
1031+ deferred_seeds. pub_reachables . push ( WorkItem {
9521032 id : * id,
9531033 propagated : ComesFromAllowExpect :: No ,
9541034 own : ComesFromAllowExpect :: No ,
@@ -957,7 +1037,7 @@ fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> SeedWorklists {
9571037 }
9581038
9591039 let mut push_into_worklist = |work_item : WorkItem | match work_item. own {
960- ComesFromAllowExpect :: Yes => deferred_seeds. push ( work_item) ,
1040+ ComesFromAllowExpect :: Yes => deferred_seeds. come_from_allow . push ( work_item) ,
9611041 ComesFromAllowExpect :: No => worklist. push ( work_item) ,
9621042 } ;
9631043 let crate_items = tcx. hir_crate_items ( ( ) ) ;
@@ -972,8 +1052,7 @@ fn live_symbols_and_ignored_derived_traits(
9721052 tcx : TyCtxt < ' _ > ,
9731053 ( ) : ( ) ,
9741054) -> Result < DeadCodeLivenessSummary , ErrorGuaranteed > {
975- let SeedWorklists { worklist, deferred_seeds, mut unsolved_items } =
976- create_and_seed_worklist ( tcx) ;
1055+ let SeedWorklists { worklist, deferred_seeds, unsolved_items } = create_and_seed_worklist ( tcx) ;
9771056 let mut symbol_visitor = MarkSymbolVisitor {
9781057 worklist,
9791058 tcx,
@@ -986,15 +1065,19 @@ fn live_symbols_and_ignored_derived_traits(
9861065 ignore_variant_stack : vec ! [ ] ,
9871066 ignored_derived_traits : Default :: default ( ) ,
9881067 propagated_comes_from_allow_expect : ComesFromAllowExpect :: No ,
1068+ unsolved_items,
9891069 } ;
990- mark_live_symbols_and_ignored_derived_traits ( & mut symbol_visitor , & mut unsolved_items ) ?;
1070+ symbol_visitor . mark_live_symbols_and_ignored_derived_traits ( true ) ?;
9911071 let pre_deferred_seeding = DeadCodeLivenessSnapshot {
9921072 live_symbols : symbol_visitor. live_symbols . clone ( ) ,
9931073 ignored_derived_traits : symbol_visitor. ignored_derived_traits . clone ( ) ,
9941074 } ;
9951075
996- symbol_visitor. worklist . extend ( deferred_seeds) ;
997- mark_live_symbols_and_ignored_derived_traits ( & mut symbol_visitor, & mut unsolved_items) ?;
1076+ symbol_visitor. worklist . extend ( deferred_seeds. pub_reachables ) ;
1077+ symbol_visitor. mark_live_symbols_and_ignored_derived_traits ( true ) ?;
1078+
1079+ symbol_visitor. worklist . extend ( deferred_seeds. come_from_allow ) ;
1080+ symbol_visitor. mark_live_symbols_and_ignored_derived_traits ( false ) ?;
9981081
9991082 Ok ( DeadCodeLivenessSummary {
10001083 pre_deferred_seeding,
@@ -1005,40 +1088,6 @@ fn live_symbols_and_ignored_derived_traits(
10051088 } )
10061089}
10071090
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-
10421091struct DeadItem {
10431092 def_id : LocalDefId ,
10441093 name : Symbol ,
0 commit comments