@@ -9,7 +9,7 @@ use std::sync::atomic::Ordering;
99
1010use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
1111use rustc_abi:: FieldIdx ;
12- use rustc_data_structures:: fx:: { FxHashSet , FxIndexSet } ;
12+ use rustc_data_structures:: fx:: { FxHashMap , FxHashSet , FxIndexSet } ;
1313use rustc_errors:: { ErrorGuaranteed , MultiSpan } ;
1414use rustc_hir:: def:: { CtorOf , DefKind , Res } ;
1515use rustc_hir:: def_id:: { DefId , LocalDefId , LocalModId } ;
@@ -113,6 +113,11 @@ struct WorkItem {
113113 own : ComesFromAllowExpect ,
114114}
115115
116+ enum ImplItemCheckResult {
117+ Live ( ComesFromAllowExpect ) ,
118+ Dead { require : LocalDefId } ,
119+ }
120+
116121struct MarkSymbolVisitor < ' tcx > {
117122 worklist : Vec < WorkItem > ,
118123 tcx : TyCtxt < ' tcx > ,
@@ -554,7 +559,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
554559 & self ,
555560 local_def_id : LocalDefId ,
556561 defer_seeds_come_from_allow : bool ,
557- ) -> Option < ComesFromAllowExpect > {
562+ ) -> ImplItemCheckResult {
558563 let ( impl_block_id, trait_def_id) = match self . tcx . def_kind ( local_def_id) {
559564 // assoc impl items of traits are live if the corresponding trait items are live
560565 DefKind :: AssocConst { .. } | DefKind :: AssocTy | DefKind :: AssocFn => {
@@ -573,14 +578,17 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
573578 if let Some ( trait_def_id) = trait_def_id {
574579 if defer_seeds_come_from_allow {
575580 if !self . live_symbols . contains ( & trait_def_id) {
576- return None ;
581+ return ImplItemCheckResult :: Dead { require : trait_def_id } ;
577582 }
578583 } else {
584+ trait_comes_from_allow = has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
585+
579586 if !self . live_symbols . contains ( & trait_def_id) {
580- return has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
587+ return match trait_comes_from_allow {
588+ Some ( comes_from_allow) => ImplItemCheckResult :: Live ( comes_from_allow) ,
589+ None => ImplItemCheckResult :: Dead { require : trait_def_id } ,
590+ } ;
581591 }
582-
583- trait_comes_from_allow = has_allow_dead_code_or_lang_attr ( self . tcx , trait_def_id) ;
584592 }
585593 }
586594
@@ -591,36 +599,46 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
591599 && !self . live_symbols . contains ( & adt_def_id)
592600 {
593601 if defer_seeds_come_from_allow {
594- return None ;
602+ return ImplItemCheckResult :: Dead { require : adt_def_id } ;
595603 } else {
596- return trait_comes_from_allow
604+ let comes_from_allow = trait_comes_from_allow
597605 . or_else ( || has_allow_dead_code_or_lang_attr ( self . tcx , adt_def_id) ) ;
606+
607+ return match comes_from_allow {
608+ Some ( comes_from_allow) => ImplItemCheckResult :: Live ( comes_from_allow) ,
609+ None => ImplItemCheckResult :: Dead { require : adt_def_id } ,
610+ } ;
598611 }
599612 }
600613
601- Some ( ComesFromAllowExpect :: No )
614+ ImplItemCheckResult :: Live ( ComesFromAllowExpect :: No )
602615 }
603616
604617 fn collect_live_items_from_unsolved_items (
605618 & mut self ,
606619 defer_seeds_come_from_allow : bool ,
620+ unsolved_items : Vec < LocalDefId > ,
621+ unsolved_map : & mut FxHashMap < LocalDefId , Vec < LocalDefId > > ,
607622 ) -> Vec < ( LocalDefId , ComesFromAllowExpect ) > {
608- let mut unsolved_items = std:: mem:: take ( & mut self . unsolved_items ) ;
609623 let mut items_to_check = vec ! [ ] ;
610- unsolved_items. retain ( |& def_id| {
611- let Some ( comes_from_allow) =
612- self . check_impl_or_impl_item_live ( def_id, defer_seeds_come_from_allow)
613- else {
614- return true ;
615- } ;
616624
617- items_to_check. push ( ( def_id, comes_from_allow) ) ;
618- false
619- } ) ;
620- self . unsolved_items = unsolved_items;
625+ for def_id in unsolved_items {
626+ match self . check_impl_or_impl_item_live ( def_id, defer_seeds_come_from_allow) {
627+ ImplItemCheckResult :: Live ( comes_from_allow) => {
628+ items_to_check. push ( ( def_id, comes_from_allow) ) ;
629+ }
630+ ImplItemCheckResult :: Dead { require } => {
631+ unsolved_map. entry ( require) . or_default ( ) . push ( def_id) ;
632+ }
633+ }
634+ }
621635 items_to_check
622636 }
623637
638+ #[ expect(
639+ rustc:: potential_query_instability,
640+ reason = "The order of the unsolved items is not important, so we can just collect them into a vector."
641+ ) ]
624642 fn mark_live_symbols_and_ignored_derived_traits (
625643 & mut self ,
626644 defer_seeds_come_from_allow : bool ,
@@ -631,8 +649,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
631649
632650 // We have marked the primary seeds as live. We now need to process unsolved items from traits
633651 // and trait impls: add them to the work list if the trait or the implemented type is live.
634- let mut items_to_check =
635- self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
652+ let unsolved_items = std:: mem:: take ( & mut self . unsolved_items ) ;
653+ let mut unsolved_map = FxHashMap :: default ( ) ;
654+ let mut items_to_check = self . collect_live_items_from_unsolved_items (
655+ defer_seeds_come_from_allow,
656+ unsolved_items,
657+ & mut unsolved_map,
658+ ) ;
636659
637660 while !items_to_check. is_empty ( ) {
638661 self . worklist . extend ( items_to_check. into_iter ( ) . map ( |( id, comes_from_allow) | {
@@ -649,10 +672,20 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
649672 return Err ( guar) ;
650673 }
651674
652- items_to_check =
653- self . collect_live_items_from_unsolved_items ( defer_seeds_come_from_allow) ;
675+ let unsolved_items = unsolved_map
676+ . extract_if ( |require, _| self . live_symbols . contains ( require) )
677+ . flat_map ( |( _, items) | items)
678+ . collect ( ) ;
679+
680+ items_to_check = self . collect_live_items_from_unsolved_items (
681+ defer_seeds_come_from_allow,
682+ unsolved_items,
683+ & mut unsolved_map,
684+ ) ;
654685 }
655686
687+ self . unsolved_items = unsolved_map. into_values ( ) . flatten ( ) . collect ( ) ;
688+
656689 Ok ( ( ) )
657690 }
658691}
0 commit comments