@@ -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 > {
@@ -419,6 +420,8 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
419420
420421 if !self . scanned . insert ( ( id, propagated) ) {
421422 continue ;
423+ } else if propagated == ComesFromAllowExpect :: No {
424+ self . scanned . insert ( ( id, ComesFromAllowExpect :: Yes ) ) ;
422425 }
423426
424427 // Avoid accessing the HIR for the synthesized associated type generated for RPITITs.
@@ -544,13 +547,17 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
544547 /// `local_def_id` points to an impl or an impl item,
545548 /// both impl and impl item that may be passed to this function are of a trait,
546549 /// 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 {
550+ fn check_impl_or_impl_item_live (
551+ & self ,
552+ local_def_id : LocalDefId ,
553+ defer_seeds_come_from_allow : bool ,
554+ ) -> Option < ComesFromAllowExpect > {
548555 let ( impl_block_id, trait_def_id) = match self . tcx . def_kind ( local_def_id) {
549556 // assoc impl items of traits are live if the corresponding trait items are live
550557 DefKind :: AssocConst { .. } | DefKind :: AssocTy | DefKind :: AssocFn => {
551- let trait_item_id =
558+ let trait_def_id =
552559 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 )
560+ ( self . tcx . local_parent ( local_def_id) , trait_def_id )
554561 }
555562 // impl items are live if the corresponding traits are live
556563 DefKind :: Impl { of_trait : true } => {
@@ -559,10 +566,19 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
559566 _ => bug ! ( ) ,
560567 } ;
561568
562- if let Some ( trait_def_id) = trait_def_id
563- && !self . live_symbols . contains ( & trait_def_id)
564- {
565- return false ;
569+ let mut trait_comes_from_allow = None ;
570+ if let Some ( trait_def_id) = trait_def_id {
571+ if defer_seeds_come_from_allow {
572+ if !self . live_symbols . contains ( & trait_def_id) {
573+ return None ;
574+ }
575+ } else {
576+ if !self . live_symbols . contains ( & trait_def_id) {
577+ return has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
578+ }
579+
580+ trait_comes_from_allow = has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
581+ }
566582 }
567583
568584 // The impl or impl item is used if the corresponding trait or trait item is used and the ty is used.
@@ -571,10 +587,70 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
571587 && let Some ( adt_def_id) = adt. did ( ) . as_local ( )
572588 && !self . live_symbols . contains ( & adt_def_id)
573589 {
574- return false ;
590+ if defer_seeds_come_from_allow {
591+ return None ;
592+ } else {
593+ return trait_comes_from_allow
594+ . or_else ( || has_allow_dead_code_or_lang_attr ( self . tcx , adt_def_id) ) ;
595+ }
575596 }
576597
577- true
598+ Some ( ComesFromAllowExpect :: No )
599+ }
600+
601+ fn collect_live_items_from_unsolved_items (
602+ & mut self ,
603+ defer_seeds_come_from_allow : bool ,
604+ ) -> Vec < ( LocalDefId , ComesFromAllowExpect ) > {
605+ let mut unsolved_items = std:: mem:: take ( & mut self . unsolved_items ) ;
606+ let mut items_to_check = vec ! [ ] ;
607+ unsolved_items. retain ( |& def_id| {
608+ let Some ( comes_from_allow) =
609+ self . check_impl_or_impl_item_live ( def_id, defer_seeds_come_from_allow)
610+ else {
611+ return true ;
612+ } ;
613+
614+ items_to_check. push ( ( def_id, comes_from_allow) ) ;
615+ false
616+ } ) ;
617+ self . unsolved_items = unsolved_items;
618+ items_to_check
619+ }
620+
621+ fn mark_live_symbols_and_ignored_derived_traits (
622+ & mut self ,
623+ defer_seeds_come_from_allow : bool ,
624+ ) -> Result < ( ) , ErrorGuaranteed > {
625+ if let ControlFlow :: Break ( guar) = self . mark_live_symbols ( ) {
626+ return Err ( guar) ;
627+ }
628+
629+ // We have marked the primary seeds as live. We now need to process unsolved items from traits
630+ // and trait impls: add them to the work list if the trait or the implemented type is live.
631+ let mut items_to_check =
632+ self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
633+
634+ while !items_to_check. is_empty ( ) {
635+ self . worklist . extend ( items_to_check. into_iter ( ) . map ( |( id, comes_from_allow) | {
636+ let own = if defer_seeds_come_from_allow {
637+ ComesFromAllowExpect :: No
638+ } else {
639+ has_allow_dead_code_or_lang_attr ( self . tcx , id)
640+ . unwrap_or ( ComesFromAllowExpect :: No )
641+ } ;
642+
643+ WorkItem { id, propagated : comes_from_allow, own }
644+ } ) ) ;
645+ if let ControlFlow :: Break ( guar) = self . mark_live_symbols ( ) {
646+ return Err ( guar) ;
647+ }
648+
649+ items_to_check =
650+ self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
651+ }
652+
653+ Ok ( ( ) )
578654 }
579655}
580656
@@ -843,21 +919,22 @@ fn maybe_record_as_seed<'tcx>(
843919 if allow_dead_code. is_none ( ) {
844920 let parent = tcx. local_parent ( owner_id. def_id ) ;
845921 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 ( )
922+ DefKind :: Trait => { }
923+ DefKind :: Impl { of_trait : false } => {
924+ if let ty :: Adt ( adt , _ ) =
925+ tcx. type_of ( parent ) . instantiate_identity ( ) . skip_normalization ( ) . kind ( )
926+ && let Some ( adt_def_id ) = adt . did ( ) . as_local ( )
851927 && let Some ( comes_from_allow) =
852- has_allow_dead_code_or_lang_attr ( tcx, trait_item_local_def_id )
928+ has_allow_dead_code_or_lang_attr ( tcx, adt_def_id )
853929 {
854930 push_into_worklist ( WorkItem {
855931 id : owner_id. def_id ,
856932 propagated : comes_from_allow,
857- own : comes_from_allow ,
933+ own : ComesFromAllowExpect :: No ,
858934 } ) ;
859935 }
860-
936+ }
937+ DefKind :: Impl { of_trait : true } => {
861938 // We only care about associated items of traits,
862939 // because they cannot be visited directly,
863940 // so we later mark them as live if their corresponding traits
@@ -869,23 +946,22 @@ fn maybe_record_as_seed<'tcx>(
869946 }
870947 }
871948 }
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 ) ;
949+ DefKind :: Impl { of_trait : false } if allow_dead_code. is_none ( ) => {
950+ if let ty:: Adt ( adt, _) =
951+ tcx. type_of ( owner_id. def_id ) . instantiate_identity ( ) . skip_normalization ( ) . kind ( )
952+ && let Some ( adt_def_id) = adt. did ( ) . as_local ( )
953+ && let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, adt_def_id)
954+ {
955+ push_into_worklist ( WorkItem {
956+ id : owner_id. def_id ,
957+ propagated : comes_from_allow,
958+ own : ComesFromAllowExpect :: No ,
959+ } ) ;
887960 }
888961 }
962+ DefKind :: Impl { of_trait : true } if allow_dead_code. is_none ( ) => {
963+ unsolved_items. push ( owner_id. def_id ) ;
964+ }
889965 DefKind :: GlobalAsm => {
890966 // global_asm! is always live.
891967 push_into_worklist ( WorkItem {
@@ -910,15 +986,21 @@ fn maybe_record_as_seed<'tcx>(
910986 }
911987}
912988
989+ #[ derive( Default ) ]
990+ struct DeferredSeeds {
991+ pub_reachables : Vec < WorkItem > ,
992+ come_from_allow : Vec < WorkItem > ,
993+ }
994+
913995struct SeedWorklists {
914996 worklist : Vec < WorkItem > ,
915- deferred_seeds : Vec < WorkItem > ,
997+ deferred_seeds : DeferredSeeds ,
916998 unsolved_items : Vec < LocalDefId > ,
917999}
9181000
9191001fn create_and_seed_worklist ( tcx : TyCtxt < ' _ > ) -> SeedWorklists {
9201002 let mut unsolved_items = Vec :: new ( ) ;
921- let mut deferred_seeds = Vec :: new ( ) ;
1003+ let mut deferred_seeds = DeferredSeeds :: default ( ) ;
9221004 let mut worklist = Vec :: new ( ) ;
9231005
9241006 if let Some ( ( def_id, _) ) = tcx. entry_fn ( ( ) )
@@ -948,7 +1030,7 @@ fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> SeedWorklists {
9481030
9491031 for ( id, effective_vis) in tcx. effective_visibilities ( ( ) ) . iter ( ) {
9501032 if effective_vis. is_public_at_level ( Level :: Reachable ) {
951- deferred_seeds. push ( WorkItem {
1033+ deferred_seeds. pub_reachables . push ( WorkItem {
9521034 id : * id,
9531035 propagated : ComesFromAllowExpect :: No ,
9541036 own : ComesFromAllowExpect :: No ,
@@ -957,7 +1039,7 @@ fn create_and_seed_worklist(tcx: TyCtxt<'_>) -> SeedWorklists {
9571039 }
9581040
9591041 let mut push_into_worklist = |work_item : WorkItem | match work_item. own {
960- ComesFromAllowExpect :: Yes => deferred_seeds. push ( work_item) ,
1042+ ComesFromAllowExpect :: Yes => deferred_seeds. come_from_allow . push ( work_item) ,
9611043 ComesFromAllowExpect :: No => worklist. push ( work_item) ,
9621044 } ;
9631045 let crate_items = tcx. hir_crate_items ( ( ) ) ;
@@ -972,8 +1054,7 @@ fn live_symbols_and_ignored_derived_traits(
9721054 tcx : TyCtxt < ' _ > ,
9731055 ( ) : ( ) ,
9741056) -> Result < DeadCodeLivenessSummary , ErrorGuaranteed > {
975- let SeedWorklists { worklist, deferred_seeds, mut unsolved_items } =
976- create_and_seed_worklist ( tcx) ;
1057+ let SeedWorklists { worklist, deferred_seeds, unsolved_items } = create_and_seed_worklist ( tcx) ;
9771058 let mut symbol_visitor = MarkSymbolVisitor {
9781059 worklist,
9791060 tcx,
@@ -986,15 +1067,19 @@ fn live_symbols_and_ignored_derived_traits(
9861067 ignore_variant_stack : vec ! [ ] ,
9871068 ignored_derived_traits : Default :: default ( ) ,
9881069 propagated_comes_from_allow_expect : ComesFromAllowExpect :: No ,
1070+ unsolved_items,
9891071 } ;
990- mark_live_symbols_and_ignored_derived_traits ( & mut symbol_visitor , & mut unsolved_items ) ?;
1072+ symbol_visitor . mark_live_symbols_and_ignored_derived_traits ( true ) ?;
9911073 let pre_deferred_seeding = DeadCodeLivenessSnapshot {
9921074 live_symbols : symbol_visitor. live_symbols . clone ( ) ,
9931075 ignored_derived_traits : symbol_visitor. ignored_derived_traits . clone ( ) ,
9941076 } ;
9951077
996- symbol_visitor. worklist . extend ( deferred_seeds) ;
997- mark_live_symbols_and_ignored_derived_traits ( & mut symbol_visitor, & mut unsolved_items) ?;
1078+ symbol_visitor. worklist . extend ( deferred_seeds. pub_reachables ) ;
1079+ symbol_visitor. mark_live_symbols_and_ignored_derived_traits ( true ) ?;
1080+
1081+ symbol_visitor. worklist . extend ( deferred_seeds. come_from_allow ) ;
1082+ symbol_visitor. mark_live_symbols_and_ignored_derived_traits ( false ) ?;
9981083
9991084 Ok ( DeadCodeLivenessSummary {
10001085 pre_deferred_seeding,
@@ -1005,40 +1090,6 @@ fn live_symbols_and_ignored_derived_traits(
10051090 } )
10061091}
10071092
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-
10421093struct DeadItem {
10431094 def_id : LocalDefId ,
10441095 name : Symbol ,
0 commit comments