33// expectations such as `#[expect(unused)]` and `#[expect(dead_code)]` is live, and everything else
44// is dead.
55
6- use hir:: def_id:: { LocalDefIdMap , LocalDefIdSet } ;
6+ use hir:: def_id:: { DefIdMap , LocalDefIdMap , LocalDefIdSet } ;
77use hir:: ItemKind ;
88use rustc_data_structures:: unord:: UnordSet ;
99use rustc_errors:: MultiSpan ;
@@ -80,6 +80,7 @@ struct MarkSymbolVisitor<'tcx> {
8080 // and the span of their respective impl (i.e., part of the derive
8181 // macro)
8282 ignored_derived_traits : LocalDefIdMap < Vec < ( DefId , DefId ) > > ,
83+ impl_item_trait_item_ids_cache : DefIdMap < DefIdMap < DefId > > ,
8384}
8485
8586impl < ' tcx > MarkSymbolVisitor < ' tcx > {
@@ -490,7 +491,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
490491 let mut ready;
491492 ( ready, unsolved_impl_items) =
492493 unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
493- self . impl_item_with_used_self_and_trait_term ( impl_id, impl_item_id)
494+ self . impl_item_with_used_self_and_trait_item ( impl_id, impl_item_id)
494495 } ) ;
495496
496497 while !ready. is_empty ( ) {
@@ -500,12 +501,12 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
500501
501502 ( ready, unsolved_impl_items) =
502503 unsolved_impl_items. into_iter ( ) . partition ( |& ( impl_id, impl_item_id) | {
503- self . impl_item_with_used_self_and_trait_term ( impl_id, impl_item_id)
504+ self . impl_item_with_used_self_and_trait_item ( impl_id, impl_item_id)
504505 } ) ;
505506 }
506507 }
507508
508- fn impl_item_with_used_self_and_trait_term (
509+ fn impl_item_with_used_self_and_trait_item (
509510 & mut self ,
510511 impl_id : hir:: ItemId ,
511512 impl_item_id : LocalDefId ,
@@ -520,20 +521,32 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
520521 // for the public method, we don't know the trait item is used or not,
521522 // so we mark the method live if the self is used
522523 return self . live_symbols . contains ( & local_def_id) ;
523- } else if let Some ( trait_item_id) = self
524- . tcx
525- . impl_item_trait_item_ids ( impl_id. owner_id . to_def_id ( ) )
526- . get ( & impl_item_id. to_def_id ( ) )
524+ }
525+
526+ let impl_id = impl_id. owner_id . to_def_id ( ) ;
527+ let impl_item_trait_item_ids = self
528+ . impl_item_trait_item_ids_cache
529+ . entry ( impl_id)
530+ . or_insert_with ( || Self :: impl_item_trait_item_ids ( self . tcx , impl_id) ) ;
531+
532+ if let Some ( trait_item_id) = impl_item_trait_item_ids. get ( & impl_item_id. to_def_id ( ) )
527533 && let Some ( local_id) = trait_item_id. as_local ( )
528534 {
529- // for the private method, we can know the trait item is ued or not,
535+ // for the private method, we can know the trait item is used or not,
530536 // so we mark the method live if the self is used and the trait item is used
531537 return self . live_symbols . contains ( & local_id)
532538 && self . live_symbols . contains ( & local_def_id) ;
533539 }
534540 }
535541 false
536542 }
543+
544+ fn impl_item_trait_item_ids ( tcx : TyCtxt < ' tcx > , impl_id : DefId ) -> DefIdMap < DefId > {
545+ tcx. associated_items ( impl_id)
546+ . in_definition_order ( )
547+ . filter_map ( |item| item. trait_item_def_id . map ( |trait_item| ( item. def_id , trait_item) ) )
548+ . collect ( )
549+ }
537550}
538551
539552impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -888,6 +901,7 @@ fn live_symbols_and_ignored_derived_traits(
888901 ignore_variant_stack : vec ! [ ] ,
889902 struct_constructors,
890903 ignored_derived_traits : Default :: default ( ) ,
904+ impl_item_trait_item_ids_cache : Default :: default ( ) ,
891905 } ;
892906 symbol_visitor. mark_live_symbols ( ) ;
893907 symbol_visitor. solve_rest_impl_items ( unsolved_impl_items) ;
0 commit comments