@@ -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 , AssocItemContainer , TyCtxt } ;
18
+ use rustc_middle:: ty:: { self , TyCtxt } ;
19
19
use rustc_middle:: { bug, span_bug} ;
20
20
use rustc_session:: lint;
21
21
use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -43,63 +43,16 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
43
43
)
44
44
}
45
45
46
- struct Publicness {
47
- ty_is_public : bool ,
48
- ty_and_all_fields_are_public : bool ,
49
- }
50
-
51
- impl Publicness {
52
- fn new ( ty_is_public : bool , ty_and_all_fields_are_public : bool ) -> Self {
53
- Self { ty_is_public, ty_and_all_fields_are_public }
54
- }
55
- }
56
-
57
- fn struct_all_fields_are_public ( tcx : TyCtxt < ' _ > , id : DefId ) -> bool {
58
- // treat PhantomData and positional ZST as public,
59
- // we don't want to lint types which only have them,
60
- // cause it's a common way to use such types to check things like well-formedness
61
- tcx. adt_def ( id) . all_fields ( ) . all ( |field| {
62
- let field_type = tcx. type_of ( field. did ) . instantiate_identity ( ) ;
63
- if field_type. is_phantom_data ( ) {
64
- return true ;
65
- }
66
- let is_positional = field. name . as_str ( ) . starts_with ( |c : char | c. is_ascii_digit ( ) ) ;
67
- if is_positional
68
- && tcx
69
- . layout_of ( tcx. param_env ( field. did ) . and ( field_type) )
70
- . map_or ( true , |layout| layout. is_zst ( ) )
71
- {
72
- return true ;
73
- }
74
- field. vis . is_public ( )
75
- } )
76
- }
77
-
78
- /// check struct and its fields are public or not,
79
- /// for enum and union, just check they are public,
80
- /// and doesn't solve types like &T for now, just skip them
81
- fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> Publicness {
46
+ fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
82
47
if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
83
48
&& let Res :: Def ( def_kind, def_id) = path. res
84
49
&& def_id. is_local ( )
50
+ && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
85
51
{
86
- return match def_kind {
87
- DefKind :: Enum | DefKind :: Union => {
88
- let ty_is_public = tcx. visibility ( def_id) . is_public ( ) ;
89
- Publicness :: new ( ty_is_public, ty_is_public)
90
- }
91
- DefKind :: Struct => {
92
- let ty_is_public = tcx. visibility ( def_id) . is_public ( ) ;
93
- Publicness :: new (
94
- ty_is_public,
95
- ty_is_public && struct_all_fields_are_public ( tcx, def_id) ,
96
- )
97
- }
98
- _ => Publicness :: new ( true , true ) ,
99
- } ;
52
+ tcx. visibility ( def_id) . is_public ( )
53
+ } else {
54
+ true
100
55
}
101
-
102
- Publicness :: new ( true , true )
103
56
}
104
57
105
58
/// Determine if a work from the worklist is coming from a `#[allow]`
@@ -155,10 +108,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
155
108
156
109
fn handle_res ( & mut self , res : Res ) {
157
110
match res {
158
- Res :: Def (
159
- DefKind :: Const | DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: TyAlias ,
160
- def_id,
161
- ) => {
111
+ Res :: Def ( DefKind :: Const | DefKind :: AssocConst | DefKind :: TyAlias , def_id) => {
162
112
self . check_def_id ( def_id) ;
163
113
}
164
114
_ if self . in_pat => { }
@@ -277,10 +227,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
277
227
pats : & [ hir:: PatField < ' _ > ] ,
278
228
) {
279
229
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
280
- ty:: Adt ( adt, _) => {
281
- self . check_def_id ( adt. did ( ) ) ;
282
- adt. variant_of_res ( res)
283
- }
230
+ ty:: Adt ( adt, _) => adt. variant_of_res ( res) ,
284
231
_ => span_bug ! ( lhs. span, "non-ADT in struct pattern" ) ,
285
232
} ;
286
233
for pat in pats {
@@ -300,10 +247,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
300
247
dotdot : hir:: DotDotPos ,
301
248
) {
302
249
let variant = match self . typeck_results ( ) . node_type ( lhs. hir_id ) . kind ( ) {
303
- ty:: Adt ( adt, _) => {
304
- self . check_def_id ( adt. did ( ) ) ;
305
- adt. variant_of_res ( res)
306
- }
250
+ ty:: Adt ( adt, _) => adt. variant_of_res ( res) ,
307
251
_ => {
308
252
self . tcx . dcx ( ) . span_delayed_bug ( lhs. span , "non-ADT in tuple struct pattern" ) ;
309
253
return ;
@@ -408,6 +352,31 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
408
352
return false ;
409
353
}
410
354
355
+ // don't ignore impls for Enums and pub Structs whose methods don't have self receiver,
356
+ // cause external crate may call such methods to construct values of these types
357
+ if let Some ( local_impl_of) = impl_of. as_local ( )
358
+ && let Some ( local_def_id) = def_id. as_local ( )
359
+ && let Some ( fn_sig) =
360
+ self . tcx . hir ( ) . fn_sig_by_hir_id ( self . tcx . local_def_id_to_hir_id ( local_def_id) )
361
+ && matches ! ( fn_sig. decl. implicit_self, hir:: ImplicitSelfKind :: None )
362
+ && let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) =
363
+ self . tcx . hir ( ) . expect_item ( local_impl_of) . expect_impl ( ) . self_ty . kind
364
+ && let Res :: Def ( def_kind, did) = path. res
365
+ {
366
+ match def_kind {
367
+ // for example, #[derive(Default)] pub struct T(i32);
368
+ // external crate can call T::default() to construct T,
369
+ // so that don't ignore impl Default for pub Enum and Structs
370
+ DefKind :: Struct | DefKind :: Union if self . tcx . visibility ( did) . is_public ( ) => {
371
+ return false ;
372
+ }
373
+ // don't ignore impl Default for Enums,
374
+ // cause we don't know which variant is constructed
375
+ DefKind :: Enum => return false ,
376
+ _ => ( ) ,
377
+ } ;
378
+ }
379
+
411
380
if let Some ( trait_of) = self . tcx . trait_id_of_impl ( impl_of)
412
381
&& self . tcx . has_attr ( trait_of, sym:: rustc_trivial_field_reads)
413
382
{
@@ -450,7 +419,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
450
419
intravisit:: walk_item ( self , item)
451
420
}
452
421
hir:: ItemKind :: ForeignMod { .. } => { }
453
- hir:: ItemKind :: Trait ( _ , _ , _ , _ , trait_item_refs ) => {
422
+ hir:: ItemKind :: Trait ( .. ) => {
454
423
for impl_def_id in self . tcx . all_impls ( item. owner_id . to_def_id ( ) ) {
455
424
if let Some ( local_def_id) = impl_def_id. as_local ( )
456
425
&& let ItemKind :: Impl ( impl_ref) =
@@ -463,12 +432,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
463
432
intravisit:: walk_path ( self , impl_ref. of_trait . unwrap ( ) . path ) ;
464
433
}
465
434
}
466
- // mark assoc ty live if the trait is live
467
- for trait_item in trait_item_refs {
468
- if let hir:: AssocItemKind :: Type = trait_item. kind {
469
- self . check_def_id ( trait_item. id . owner_id . to_def_id ( ) ) ;
470
- }
471
- }
435
+
472
436
intravisit:: walk_item ( self , item)
473
437
}
474
438
_ => intravisit:: walk_item ( self , item) ,
@@ -485,12 +449,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
485
449
&& let ItemKind :: Impl ( impl_ref) =
486
450
self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
487
451
{
488
- if !ty_ref_to_pub_struct ( self . tcx , impl_ref . self_ty )
489
- . ty_and_all_fields_are_public
452
+ if !matches ! ( trait_item . kind , hir :: TraitItemKind :: Type ( .. ) )
453
+ && ! ty_ref_to_pub_struct ( self . tcx , impl_ref . self_ty )
490
454
{
491
- // skip impl-items of non pure pub ty,
492
- // cause we don't know the ty is constructed or not,
493
- // check these later in `solve_rest_impl_items`
455
+ // skip methods of private ty,
456
+ // they would be solved in `solve_rest_impl_items`
494
457
continue ;
495
458
}
496
459
@@ -571,21 +534,22 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
571
534
&& let Some ( local_def_id) = def_id. as_local ( )
572
535
&& matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
573
536
{
537
+ if self . tcx . visibility ( impl_item_id) . is_public ( ) {
538
+ // for the public method, we don't know the trait item is used or not,
539
+ // so we mark the method live if the self is used
540
+ return self . live_symbols . contains ( & local_def_id) ;
541
+ }
542
+
574
543
if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
575
544
&& let Some ( local_id) = trait_item_id. as_local ( )
576
545
{
577
- // for the local impl item , we can know the trait item is used or not,
546
+ // for the private method , we can know the trait item is used or not,
578
547
// so we mark the method live if the self is used and the trait item is used
579
- self . live_symbols . contains ( & local_id) && self . live_symbols . contains ( & local_def_id)
580
- } else {
581
- // for the foreign method and inherent pub method,
582
- // we don't know the trait item or the method is used or not,
583
- // so we mark the method live if the self is used
584
- self . live_symbols . contains ( & local_def_id)
548
+ return self . live_symbols . contains ( & local_id)
549
+ && self . live_symbols . contains ( & local_def_id) ;
585
550
}
586
- } else {
587
- false
588
551
}
552
+ false
589
553
}
590
554
}
591
555
@@ -671,9 +635,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
671
635
self . handle_field_pattern_match ( pat, res, fields) ;
672
636
}
673
637
PatKind :: Path ( ref qpath) => {
674
- if let ty:: Adt ( adt, _) = self . typeck_results ( ) . node_type ( pat. hir_id ) . kind ( ) {
675
- self . check_def_id ( adt. did ( ) ) ;
676
- }
677
638
let res = self . typeck_results ( ) . qpath_res ( qpath, pat. hir_id ) ;
678
639
self . handle_res ( res) ;
679
640
}
@@ -810,9 +771,7 @@ fn check_item<'tcx>(
810
771
. iter ( )
811
772
. filter_map ( |def_id| def_id. as_local ( ) ) ;
812
773
813
- let self_ty = tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ;
814
- let Publicness { ty_is_public, ty_and_all_fields_are_public } =
815
- ty_ref_to_pub_struct ( tcx, self_ty) ;
774
+ let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
816
775
817
776
// And we access the Map here to get HirId from LocalDefId
818
777
for local_def_id in local_def_ids {
@@ -828,19 +787,18 @@ fn check_item<'tcx>(
828
787
// for trait impl blocks,
829
788
// mark the method live if the self_ty is public,
830
789
// or the method is public and may construct self
831
- if tcx. visibility ( local_def_id) . is_public ( )
832
- && ( ty_and_all_fields_are_public || ( ty_is_public && may_construct_self) )
790
+ if of_trait
791
+ && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
792
+ || tcx. visibility ( local_def_id) . is_public ( )
793
+ && ( ty_is_pub || may_construct_self) )
833
794
{
834
- // if the impl item is public,
835
- // and the ty may be constructed or can be constructed in foreign crates,
836
- // mark the impl item live
837
795
worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
838
796
} else if let Some ( comes_from_allow) =
839
797
has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
840
798
{
841
799
worklist. push ( ( local_def_id, comes_from_allow) ) ;
842
- } else if of_trait || tcx . visibility ( local_def_id ) . is_public ( ) && ty_is_public {
843
- // private impl items of traits || public impl items not constructs self
800
+ } else if of_trait {
801
+ // private method || public method not constructs self
844
802
unsolved_impl_items. push ( ( id, local_def_id) ) ;
845
803
}
846
804
}
@@ -866,13 +824,10 @@ fn check_trait_item(
866
824
worklist : & mut Vec < ( LocalDefId , ComesFromAllowExpect ) > ,
867
825
id : hir:: TraitItemId ,
868
826
) {
869
- use hir:: TraitItemKind :: { Const , Fn , Type } ;
870
- if matches ! (
871
- tcx. def_kind( id. owner_id) ,
872
- DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn
873
- ) {
827
+ use hir:: TraitItemKind :: { Const , Fn } ;
828
+ if matches ! ( tcx. def_kind( id. owner_id) , DefKind :: AssocConst | DefKind :: AssocFn ) {
874
829
let trait_item = tcx. hir ( ) . trait_item ( id) ;
875
- if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Type ( _ , Some ( _ ) ) | Fn ( ..) )
830
+ if matches ! ( trait_item. kind, Const ( _, Some ( _) ) | Fn ( ..) )
876
831
&& let Some ( comes_from_allow) =
877
832
has_allow_dead_code_or_lang_attr ( tcx, trait_item. owner_id . def_id )
878
833
{
@@ -910,14 +865,6 @@ fn create_and_seed_worklist(
910
865
effective_vis
911
866
. is_public_at_level ( Level :: Reachable )
912
867
. then_some ( id)
913
- . filter ( |& id|
914
- // checks impls, impl-items and pub structs with all public fields later
915
- match tcx. def_kind ( id) {
916
- DefKind :: Impl { .. } => false ,
917
- DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn => !matches ! ( tcx. associated_item( id) . container, AssocItemContainer :: ImplContainer ) ,
918
- DefKind :: Struct => struct_all_fields_are_public ( tcx, id. to_def_id ( ) ) || has_allow_dead_code_or_lang_attr ( tcx, id) . is_some ( ) ,
919
- _ => true
920
- } )
921
868
. map ( |id| ( id, ComesFromAllowExpect :: No ) )
922
869
} )
923
870
// Seed entry point
@@ -1201,7 +1148,6 @@ impl<'tcx> DeadVisitor<'tcx> {
1201
1148
}
1202
1149
match self . tcx . def_kind ( def_id) {
1203
1150
DefKind :: AssocConst
1204
- | DefKind :: AssocTy
1205
1151
| DefKind :: AssocFn
1206
1152
| DefKind :: Fn
1207
1153
| DefKind :: Static { .. }
@@ -1243,14 +1189,10 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
1243
1189
|| ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
1244
1190
{
1245
1191
for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1246
- // We have diagnosed unused assocs in traits
1192
+ // We have diagnosed unused methods in traits
1247
1193
if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1248
- && matches ! ( tcx. def_kind( def_id) , DefKind :: AssocConst | DefKind :: AssocTy | DefKind :: AssocFn )
1249
- // skip unused public inherent methods,
1250
- // cause we have diagnosed unconstructed struct
1251
- || matches ! ( def_kind, DefKind :: Impl { of_trait: false } )
1252
- && tcx. visibility ( def_id) . is_public ( )
1253
- && ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( item) . expect_impl ( ) . self_ty ) . ty_is_public
1194
+ && tcx. def_kind ( def_id) == DefKind :: AssocFn
1195
+ || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1254
1196
{
1255
1197
continue ;
1256
1198
}
0 commit comments