@@ -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,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-
10421052struct DeadItem {
10431053 def_id : LocalDefId ,
10441054 name : Symbol ,
0 commit comments