@@ -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) =
@@ -465,6 +484,36 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
465
484
}
466
485
}
467
486
}
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
+ }
468
517
}
469
518
470
519
impl < ' tcx > Visitor < ' tcx > for MarkSymbolVisitor < ' tcx > {
@@ -652,6 +701,7 @@ fn check_item<'tcx>(
652
701
tcx : TyCtxt < ' tcx > ,
653
702
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
654
703
struct_constructors : & mut LocalDefIdMap < LocalDefId > ,
704
+ unsolved_impl_items : & mut Vec < ( hir:: ItemId , LocalDefId ) > ,
655
705
id : hir:: ItemId ,
656
706
) {
657
707
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>(
683
733
. iter ( )
684
734
. filter_map ( |def_id| def_id. as_local ( ) ) ;
685
735
736
+ let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
737
+
686
738
// 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
+
688
749
// for impl trait blocks, mark associate functions live if the trait is public
689
750
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) )
692
754
{
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) ) ;
696
763
}
697
764
}
698
765
}
@@ -743,9 +810,14 @@ fn check_foreign_item(
743
810
744
811
fn create_and_seed_worklist (
745
812
tcx : TyCtxt < ' _ > ,
746
- ) -> ( Vec < ( LocalDefId , ComesFromAllowExpect ) > , LocalDefIdMap < LocalDefId > ) {
813
+ ) -> (
814
+ Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
815
+ LocalDefIdMap < LocalDefId > ,
816
+ Vec < ( hir:: ItemId , LocalDefId ) > ,
817
+ ) {
747
818
let effective_visibilities = & tcx. effective_visibilities ( ( ) ) ;
748
819
// see `MarkSymbolVisitor::struct_constructors`
820
+ let mut unsolved_impl_item = Vec :: new ( ) ;
749
821
let mut struct_constructors = Default :: default ( ) ;
750
822
let mut worklist = effective_visibilities
751
823
. iter ( )
@@ -764,7 +836,7 @@ fn create_and_seed_worklist(
764
836
765
837
let crate_items = tcx. hir_crate_items ( ( ) ) ;
766
838
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) ;
768
840
}
769
841
770
842
for id in crate_items. trait_items ( ) {
@@ -775,14 +847,14 @@ fn create_and_seed_worklist(
775
847
check_foreign_item ( tcx, & mut worklist, id) ;
776
848
}
777
849
778
- ( worklist, struct_constructors)
850
+ ( worklist, struct_constructors, unsolved_impl_item )
779
851
}
780
852
781
853
fn live_symbols_and_ignored_derived_traits (
782
854
tcx : TyCtxt < ' _ > ,
783
855
( ) : ( ) ,
784
856
) -> ( 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) ;
786
858
let mut symbol_visitor = MarkSymbolVisitor {
787
859
worklist,
788
860
tcx,
@@ -796,6 +868,8 @@ fn live_symbols_and_ignored_derived_traits(
796
868
ignored_derived_traits : Default :: default ( ) ,
797
869
} ;
798
870
symbol_visitor. mark_live_symbols ( ) ;
871
+ symbol_visitor. solve_rest_impl_items ( unsolved_impl_items) ;
872
+
799
873
( symbol_visitor. live_symbols , symbol_visitor. ignored_derived_traits )
800
874
}
801
875
0 commit comments