@@ -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 } ;
18
+ use rustc_middle:: ty:: { self , AssocItemContainer , TyCtxt } ;
19
19
use rustc_middle:: { bug, span_bug} ;
20
20
use rustc_session:: lint;
21
21
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -44,16 +44,52 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
44
44
)
45
45
}
46
46
47
- fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
47
+ fn struct_all_fields_are_public ( tcx : TyCtxt < ' _ > , id : DefId ) -> bool {
48
+ // treat PhantomData and positional ZST as public,
49
+ // we don't want to lint types which only have them,
50
+ // cause it's a common way to use such types to check things like well-formedness
51
+ tcx. adt_def ( id) . all_fields ( ) . all ( |field| {
52
+ let field_type = tcx. type_of ( field. did ) . instantiate_identity ( ) ;
53
+ if field_type. is_phantom_data ( ) {
54
+ return true ;
55
+ }
56
+ let is_positional = field. name . as_str ( ) . starts_with ( |c : char | c. is_ascii_digit ( ) ) ;
57
+ if is_positional
58
+ && tcx
59
+ . layout_of ( tcx. param_env ( field. did ) . and ( field_type) )
60
+ . map_or ( true , |layout| layout. is_zst ( ) )
61
+ {
62
+ return true ;
63
+ }
64
+ field. vis . is_public ( )
65
+ } )
66
+ }
67
+
68
+ /// check struct and its fields are public or not,
69
+ /// for enum and union, just check they are public,
70
+ /// and doesn't solve types like &T for now, just skip them
71
+ fn ty_ref_to_pub_struct (
72
+ tcx : TyCtxt < ' _ > ,
73
+ ty : & hir:: Ty < ' _ > ,
74
+ ) -> ( bool , /* public and all fields are public */ bool ) {
48
75
if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
49
76
&& let Res :: Def ( def_kind, def_id) = path. res
50
77
&& def_id. is_local ( )
51
- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
52
78
{
53
- tcx. visibility ( def_id) . is_public ( )
54
- } else {
55
- true
79
+ return match def_kind {
80
+ DefKind :: Enum | DefKind :: Union => {
81
+ let ty_is_public = tcx. visibility ( def_id) . is_public ( ) ;
82
+ ( ty_is_public, ty_is_public)
83
+ }
84
+ DefKind :: Struct => {
85
+ let ty_is_public = tcx. visibility ( def_id) . is_public ( ) ;
86
+ ( ty_is_public, ty_is_public && struct_all_fields_are_public ( tcx, def_id) )
87
+ }
88
+ _ => ( true , true ) ,
89
+ } ;
56
90
}
91
+
92
+ ( true , true )
57
93
}
58
94
59
95
/// Determine if a work from the worklist is coming from the a `#[allow]`
@@ -426,10 +462,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
426
462
self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
427
463
{
428
464
if matches ! ( trait_item. kind, hir:: TraitItemKind :: Fn ( ..) )
429
- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
465
+ && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty ) . 1
430
466
{
431
- // skip methods of private ty,
432
- // they would be solved in `solve_rest_impl_items`
467
+ // skip impl-items of non pure pub ty,
468
+ // cause we don't know the ty is constructed or not,
469
+ // check these later in `solve_rest_impl_items`
433
470
continue ;
434
471
}
435
472
@@ -510,22 +547,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
510
547
&& let Some ( local_def_id) = def_id. as_local ( )
511
548
&& matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
512
549
{
513
- if self . tcx . visibility ( impl_item_id) . is_public ( ) {
514
- // for the public method, we don't know the trait item is used or not,
515
- // so we mark the method live if the self is used
516
- return self . live_symbols . contains ( & local_def_id) ;
517
- }
518
-
519
550
if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
520
551
&& let Some ( local_id) = trait_item_id. as_local ( )
521
552
{
522
- // for the private method , we can know the trait item is used or not,
553
+ // for the local impl item , we can know the trait item is used or not,
523
554
// so we mark the method live if the self is used and the trait item is used
524
- return self . live_symbols . contains ( & local_id)
525
- && self . live_symbols . contains ( & local_def_id) ;
555
+ self . live_symbols . contains ( & local_id) && self . live_symbols . contains ( & local_def_id)
556
+ } else {
557
+ // for the foreign method and inherent pub method,
558
+ // we don't know the trait item or the method is used or not,
559
+ // so we mark the method live if the self is used
560
+ self . live_symbols . contains ( & local_def_id)
526
561
}
562
+ } else {
563
+ false
527
564
}
528
- false
529
565
}
530
566
}
531
567
@@ -746,7 +782,8 @@ fn check_item<'tcx>(
746
782
. iter ( )
747
783
. filter_map ( |def_id| def_id. as_local ( ) ) ;
748
784
749
- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
785
+ let self_ty = tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ;
786
+ let ( pub_ty, pub_ty_with_all_fields_pub) = ty_ref_to_pub_struct ( tcx, self_ty) ;
750
787
751
788
// And we access the Map here to get HirId from LocalDefId
752
789
for local_def_id in local_def_ids {
@@ -762,18 +799,20 @@ fn check_item<'tcx>(
762
799
// for trait impl blocks,
763
800
// mark the method live if the self_ty is public,
764
801
// or the method is public and may construct self
765
- if of_trait
766
- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
767
- || tcx. visibility ( local_def_id) . is_public ( )
768
- && ( ty_is_pub || may_construct_self) )
802
+ if of_trait && matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocTy )
803
+ || tcx. visibility ( local_def_id) . is_public ( )
804
+ && ( pub_ty_with_all_fields_pub || may_construct_self)
769
805
{
806
+ // if the impl item is public,
807
+ // and the ty may be constructed or can be constructed in foreign crates,
808
+ // mark the impl item live
770
809
worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
771
810
} else if let Some ( comes_from_allow) =
772
811
has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
773
812
{
774
813
worklist. push ( ( local_def_id, comes_from_allow) ) ;
775
- } else if of_trait {
776
- // private method || public method not constructs self
814
+ } else if of_trait || tcx . visibility ( local_def_id ) . is_public ( ) && pub_ty {
815
+ // private impl items of traits || public impl items not constructs self
777
816
unsolved_impl_items. push ( ( id, local_def_id) ) ;
778
817
}
779
818
}
@@ -840,6 +879,14 @@ fn create_and_seed_worklist(
840
879
effective_vis
841
880
. is_public_at_level ( Level :: Reachable )
842
881
. then_some ( id)
882
+ . filter ( |& id|
883
+ // checks impls, impl-items and pub structs with all public fields later
884
+ match tcx. def_kind ( id) {
885
+ DefKind :: Impl { .. } => false ,
886
+ DefKind :: AssocConst | DefKind :: AssocFn => !matches ! ( tcx. associated_item( id) . container, AssocItemContainer :: ImplContainer ) ,
887
+ DefKind :: Struct => struct_all_fields_are_public ( tcx, id. to_def_id ( ) ) ,
888
+ _ => true
889
+ } )
843
890
. map ( |id| ( id, ComesFromAllowExpect :: No ) )
844
891
} )
845
892
// Seed entry point
@@ -1112,10 +1159,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1112
1159
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1113
1160
{
1114
1161
for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1115
- // We have diagnosed unused methods in traits
1162
+ // We have diagnosed unused assoc consts and fns in traits
1116
1163
if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1117
- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1118
- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1164
+ && matches ! ( tcx. def_kind( def_id) , DefKind :: AssocConst | DefKind :: AssocFn )
1165
+ // skip unused public inherent methods,
1166
+ // cause we have diagnosed unconstructed struct
1167
+ || matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
1168
+ && tcx. visibility ( def_id) . is_public ( )
1169
+ && ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( item) . expect_impl ( ) . self_ty ) . 0
1170
+ || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) == DefKind :: AssocTy
1119
1171
{
1120
1172
continue ;
1121
1173
}
0 commit comments