@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
1515use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
1616use rustc_middle:: middle:: privacy:: Level ;
1717use rustc_middle:: query:: Providers ;
18- use rustc_middle:: ty:: { self , TyCtxt , Visibility } ;
18+ use rustc_middle:: ty:: { self , TyCtxt } ;
1919use rustc_session:: lint;
2020use rustc_session:: lint:: builtin:: DEAD_CODE ;
2121use rustc_span:: symbol:: { sym, Symbol } ;
@@ -45,6 +45,18 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4545 )
4646}
4747
48+ fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
49+ if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
50+ && let Res :: Def ( def_kind, def_id) = path. res
51+ && def_id. is_local ( )
52+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
53+ {
54+ tcx. visibility ( def_id) . is_public ( )
55+ } else {
56+ true
57+ }
58+ }
59+
4860/// Determine if a work from the worklist is coming from the a `#[allow]`
4961/// or a `#[expect]` of `dead_code`
5062#[ derive( Debug , Copy , Clone , Eq , PartialEq , Hash ) ]
@@ -415,6 +427,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
415427 && let ItemKind :: Impl ( impl_ref) =
416428 self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
417429 {
430+ if self . tcx . visibility ( trait_id) . is_public ( )
431+ && matches ! ( trait_item. kind, hir:: TraitItemKind :: Fn ( ..) )
432+ && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
433+ {
434+ continue ;
435+ }
436+
418437 // mark self_ty live
419438 intravisit:: walk_ty ( self , impl_ref. self_ty ) ;
420439 if let Some ( & impl_item_id) =
@@ -465,6 +484,36 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
465484 }
466485 }
467486 }
487+
488+ fn solve_rest_impl_items ( & mut self , mut unsolved_impl_items : Vec < ( hir:: ItemId , LocalDefId ) > ) {
489+ let mut ready;
490+ ( ready, unsolved_impl_items) = unsolved_impl_items
491+ . into_iter ( )
492+ . partition ( |& ( impl_id, _) | self . impl_item_with_used_self ( impl_id) ) ;
493+
494+ while !ready. is_empty ( ) {
495+ self . worklist =
496+ ready. into_iter ( ) . map ( |( _, id) | ( id, ComesFromAllowExpect :: No ) ) . collect ( ) ;
497+ self . mark_live_symbols ( ) ;
498+
499+ ( ready, unsolved_impl_items) = unsolved_impl_items
500+ . into_iter ( )
501+ . partition ( |& ( impl_id, _) | self . impl_item_with_used_self ( impl_id) ) ;
502+ }
503+ }
504+
505+ fn impl_item_with_used_self ( & mut self , impl_id : hir:: ItemId ) -> bool {
506+ if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
507+ self . tcx . hir ( ) . item ( impl_id) . expect_impl ( ) . self_ty . kind
508+ && let Res :: Def ( def_kind, def_id) = path. res
509+ && let Some ( local_def_id) = def_id. as_local ( )
510+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
511+ {
512+ self . live_symbols . contains ( & local_def_id)
513+ } else {
514+ false
515+ }
516+ }
468517}
469518
470519impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -652,6 +701,7 @@ fn check_item<'tcx>(
652701 tcx : TyCtxt < ' tcx > ,
653702 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
654703 struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
704+ unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
655705 id : hir:: ItemId ,
656706) {
657707 let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
@@ -683,16 +733,33 @@ fn check_item<'tcx>(
683733 . iter ( )
684734 . filter_map ( |def_id| def_id. as_local ( ) ) ;
685735
736+ let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
737+
686738 // And we access the Map here to get HirId from LocalDefId
687- for id in local_def_ids {
739+ for local_def_id in local_def_ids {
740+ // check the function may construct Self
741+ let mut may_construct_self = true ;
742+ if let Some ( hir_id) = tcx. opt_local_def_id_to_hir_id ( local_def_id)
743+ && let Some ( fn_sig) = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id)
744+ {
745+ may_construct_self =
746+ matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
747+ }
748+
688749 // for impl trait blocks, mark associate functions live if the trait is public
689750 if of_trait
690- && ( !matches ! ( tcx. def_kind( id) , DefKind :: AssocFn )
691- || tcx. local_visibility ( id) == Visibility :: Public )
751+ && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
752+ || tcx. visibility ( local_def_id) . is_public ( )
753+ && ( ty_is_pub || may_construct_self) )
692754 {
693- worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
694- } else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
695- worklist. push ( ( id, comes_from_allow) ) ;
755+ worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
756+ } else if of_trait && tcx. visibility ( local_def_id) . is_public ( ) {
757+ // pub method && private ty & methods not construct self
758+ unsolved_impl_items. push ( ( id, local_def_id) ) ;
759+ } else if let Some ( comes_from_allow) =
760+ has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
761+ {
762+ worklist. push ( ( local_def_id, comes_from_allow) ) ;
696763 }
697764 }
698765 }
@@ -743,9 +810,14 @@ fn check_foreign_item(
743810
744811fn create_and_seed_worklist (
745812 tcx : TyCtxt < ' _ > ,
746- ) -> ( Vec < ( LocalDefId , ComesFromAllowExpect ) > , LocalDefIdMap < LocalDefId > ) {
813+ ) -> (
814+ Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
815+ LocalDefIdMap < LocalDefId > ,
816+ Vec < ( hir:: ItemId , LocalDefId ) > ,
817+ ) {
747818 let effective_visibilities = & tcx. effective_visibilities ( ( ) ) ;
748819 // see `MarkSymbolVisitor::struct_constructors`
820+ let mut unsolved_impl_item = Vec :: new ( ) ;
749821 let mut struct_constructors = Default :: default ( ) ;
750822 let mut worklist = effective_visibilities
751823 . iter ( )
@@ -764,7 +836,7 @@ fn create_and_seed_worklist(
764836
765837 let crate_items = tcx. hir_crate_items ( ( ) ) ;
766838 for id in crate_items. items ( ) {
767- check_item ( tcx, & mut worklist, & mut struct_constructors, id) ;
839+ check_item ( tcx, & mut worklist, & mut struct_constructors, & mut unsolved_impl_item , id) ;
768840 }
769841
770842 for id in crate_items. trait_items ( ) {
@@ -775,14 +847,14 @@ fn create_and_seed_worklist(
775847 check_foreign_item ( tcx, & mut worklist, id) ;
776848 }
777849
778- ( worklist, struct_constructors)
850+ ( worklist, struct_constructors, unsolved_impl_item )
779851}
780852
781853fn live_symbols_and_ignored_derived_traits (
782854 tcx : TyCtxt < ' _ > ,
783855 ( ) : ( ) ,
784856) -> ( LocalDefIdSet , LocalDefIdMap < Vec < ( DefId , DefId ) > > ) {
785- let ( worklist, struct_constructors) = create_and_seed_worklist ( tcx) ;
857+ let ( worklist, struct_constructors, unsolved_impl_items ) = create_and_seed_worklist ( tcx) ;
786858 let mut symbol_visitor = MarkSymbolVisitor {
787859 worklist,
788860 tcx,
@@ -796,6 +868,8 @@ fn live_symbols_and_ignored_derived_traits(
796868 ignored_derived_traits : Default :: default ( ) ,
797869 } ;
798870 symbol_visitor. mark_live_symbols ( ) ;
871+ symbol_visitor. solve_rest_impl_items ( unsolved_impl_items) ;
872+
799873 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
800874}
801875
0 commit comments