@@ -15,7 +15,7 @@ use rustc_hir::{Node, PatKind, TyKind};
15
15
use rustc_middle:: middle:: codegen_fn_attrs:: CodegenFnAttrFlags ;
16
16
use rustc_middle:: middle:: privacy:: Level ;
17
17
use rustc_middle:: query:: Providers ;
18
- use rustc_middle:: ty:: { self , TyCtxt , Visibility } ;
18
+ use rustc_middle:: ty:: { self , TyCtxt } ;
19
19
use rustc_session:: lint;
20
20
use rustc_session:: lint:: builtin:: DEAD_CODE ;
21
21
use rustc_span:: symbol:: { sym, Symbol } ;
@@ -45,6 +45,18 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
45
45
)
46
46
}
47
47
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
+
48
60
/// Determine if a work from the worklist is coming from the a `#[allow]`
49
61
/// or a `#[expect]` of `dead_code`
50
62
#[ derive( Debug , Copy , Clone , Eq , PartialEq , Hash ) ]
@@ -415,6 +427,13 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
415
427
&& let ItemKind :: Impl ( impl_ref) =
416
428
self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
417
429
{
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
+
418
437
// mark self_ty live
419
438
intravisit:: walk_ty ( self , impl_ref. self_ty ) ;
420
439
if let Some ( & impl_item_id) =
@@ -683,12 +702,23 @@ fn check_item<'tcx>(
683
702
. iter ( )
684
703
. filter_map ( |def_id| def_id. as_local ( ) ) ;
685
704
705
+ let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
706
+
686
707
// And we access the Map here to get HirId from LocalDefId
687
708
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
+
688
718
// for impl trait blocks, mark associate functions live if the trait is public
689
719
if of_trait
690
720
&& ( !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 ) )
692
722
{
693
723
worklist. push ( ( id, ComesFromAllowExpect :: No ) ) ;
694
724
} else if let Some ( comes_from_allow) = has_allow_dead_code_or_lang_attr ( tcx, id) {
@@ -712,6 +742,49 @@ fn check_item<'tcx>(
712
742
}
713
743
}
714
744
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
+
715
788
fn check_trait_item (
716
789
tcx : TyCtxt < ' _ > ,
717
790
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
@@ -778,6 +851,20 @@ fn create_and_seed_worklist(
778
851
( worklist, struct_constructors)
779
852
}
780
853
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
+
781
868
fn live_symbols_and_ignored_derived_traits (
782
869
tcx : TyCtxt < ' _ > ,
783
870
( ) : ( ) ,
@@ -796,6 +883,11 @@ fn live_symbols_and_ignored_derived_traits(
796
883
ignored_derived_traits : Default :: default ( ) ,
797
884
} ;
798
885
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
+
799
891
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
800
892
}
801
893
0 commit comments