@@ -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) =
@@ -683,12 +702,23 @@ fn check_item<'tcx>(
683702 . iter ( )
684703 . filter_map ( |def_id| def_id. as_local ( ) ) ;
685704
705+ let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
706+
686707 // And we access the Map here to get HirId from LocalDefId
687708 for id in local_def_ids {
709+ // check the function may construct Self
710+ let mut may_construct_self = true ;
711+ if let Some ( hir_id) = tcx. opt_local_def_id_to_hir_id ( id)
712+ && let Some ( fn_sig) = tcx. hir ( ) . fn_sig_by_hir_id ( hir_id)
713+ {
714+ may_construct_self =
715+ matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None ) ;
716+ }
717+
688718 // for impl trait blocks, mark associate functions live if the trait is public
689719 if of_trait
690720 && ( !matches ! ( tcx. def_kind( id) , DefKind :: AssocFn )
691- || tcx. local_visibility ( id) == Visibility :: Public )
721+ || tcx. visibility ( id) . is_public ( ) && ( ty_is_pub || may_construct_self ) )
692722 {
693723 worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
694724 } else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
@@ -712,6 +742,49 @@ fn check_item<'tcx>(
712742 }
713743}
714744
745+ fn check_pub_impl_fns_of_constructed_self < ' tcx > (
746+ tcx : TyCtxt < ' tcx > ,
747+ worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
748+ id : hir:: ItemId ,
749+ live_symbols : & UnordSet < LocalDefId > ,
750+ ) {
751+ let allow_dead_code = has_allow_dead_code_or_lang_attr ( tcx, id. owner_id . def_id ) ;
752+ if let Some ( comes_from_allow) = allow_dead_code {
753+ worklist. push ( ( id. owner_id . def_id , comes_from_allow) ) ;
754+ }
755+
756+ match tcx. def_kind ( id. owner_id ) {
757+ DefKind :: Impl { of_trait : true } => {
758+ let mut self_is_constructed = false ;
759+ if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
760+ tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty . kind
761+ && let Res :: Def ( def_kind, def_id) = path. res
762+ && let Some ( local_def_id) = def_id. as_local ( )
763+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
764+ {
765+ self_is_constructed = live_symbols. contains ( & local_def_id) ;
766+ }
767+
768+ // get DefIds from another query
769+ let local_def_ids = tcx
770+ . associated_item_def_ids ( id. owner_id )
771+ . iter ( )
772+ . filter_map ( |def_id| def_id. as_local ( ) ) ;
773+
774+ // And we access the Map here to get HirId from LocalDefId
775+ for id in local_def_ids {
776+ // for impl trait blocks, mark associate functions live if the trait is public
777+ if !matches ! ( tcx. def_kind( id) , DefKind :: AssocFn )
778+ || ( tcx. visibility ( id) . is_public ( ) && self_is_constructed)
779+ {
780+ worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
781+ }
782+ }
783+ }
784+ _ => { }
785+ }
786+ }
787+
715788fn check_trait_item (
716789 tcx : TyCtxt < ' _ > ,
717790 worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
@@ -778,6 +851,20 @@ fn create_and_seed_worklist(
778851 ( worklist, struct_constructors)
779852}
780853
854+ fn create_worklist_for_pub_impl_fns_of_constructed_self (
855+ tcx : TyCtxt < ' _ > ,
856+ live_symbols : & UnordSet < LocalDefId > ,
857+ ) -> Vec < ( LocalDefId , ComesFromAllowExpect ) > {
858+ let mut worklist = Vec :: new ( ) ;
859+
860+ let crate_items = tcx. hir_crate_items ( ( ) ) ;
861+ for id in crate_items. items ( ) {
862+ check_pub_impl_fns_of_constructed_self ( tcx, & mut worklist, id, live_symbols) ;
863+ }
864+
865+ worklist
866+ }
867+
781868fn live_symbols_and_ignored_derived_traits (
782869 tcx : TyCtxt < ' _ > ,
783870 ( ) : ( ) ,
@@ -796,6 +883,11 @@ fn live_symbols_and_ignored_derived_traits(
796883 ignored_derived_traits : Default :: default ( ) ,
797884 } ;
798885 symbol_visitor. mark_live_symbols ( ) ;
886+
887+ symbol_visitor. worklist =
888+ create_worklist_for_pub_impl_fns_of_constructed_self ( tcx, & symbol_visitor. live_symbols ) ;
889+ symbol_visitor. mark_live_symbols ( ) ;
890+
799891 ( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
800892}
801893
0 commit comments