@@ -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 } ;
18+ use rustc_middle:: ty:: { self , AssocItemContainer , TyCtxt } ;
1919use rustc_middle:: { bug, span_bug} ;
2020use rustc_session:: lint;
2121use rustc_session:: lint:: builtin:: DEAD_CODE ;
@@ -44,16 +44,55 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4444 )
4545}
4646
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+ /// pub struct whose fields are all public
69+ fn ty_ref_to_pure_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
70+ if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
71+ && let Res :: Def ( def_kind, def_id) = path. res
72+ && def_id. is_local ( )
73+ {
74+ return match def_kind {
75+ DefKind :: Enum | DefKind :: Union => tcx. visibility ( def_id) . is_public ( ) ,
76+ DefKind :: Struct => {
77+ tcx. visibility ( def_id) . is_public ( ) && struct_all_fields_are_public ( tcx, def_id)
78+ }
79+ _ => true ,
80+ } ;
81+ }
82+
83+ true
84+ }
85+
86+ /// pub struct but may have private fields
4787fn ty_ref_to_pub_struct ( tcx : TyCtxt < ' _ > , ty : & hir:: Ty < ' _ > ) -> bool {
4888 if let TyKind :: Path ( hir:: QPath :: Resolved ( _, path) ) = ty. kind
4989 && let Res :: Def ( def_kind, def_id) = path. res
5090 && def_id. is_local ( )
51- && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
91+ && matches ! ( def_kind, DefKind :: Enum | DefKind :: Union | DefKind :: Struct )
5292 {
53- tcx. visibility ( def_id) . is_public ( )
54- } else {
55- true
93+ return tcx. visibility ( def_id) . is_public ( ) ;
5694 }
95+ true
5796}
5897
5998/// Determine if a work from the worklist is coming from the a `#[allow]`
@@ -426,10 +465,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
426465 self . tcx . hir ( ) . expect_item ( local_impl_id) . kind
427466 {
428467 if matches ! ( trait_item. kind, hir:: TraitItemKind :: Fn ( ..) )
429- && !ty_ref_to_pub_struct ( self . tcx , impl_ref. self_ty )
468+ && !ty_ref_to_pure_pub_struct ( self . tcx , impl_ref. self_ty )
430469 {
431- // skip methods of private ty,
432- // they would be solved in `solve_rest_impl_items`
470+ // skip impl-items of non pure pub ty,
471+ // cause we don't know the ty is constructed or not,
472+ // check these later in `solve_rest_impl_items`
433473 continue ;
434474 }
435475
@@ -510,22 +550,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
510550 && let Some ( local_def_id) = def_id. as_local ( )
511551 && matches ! ( def_kind, DefKind :: Struct | DefKind :: Enum | DefKind :: Union )
512552 {
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-
519553 if let Some ( trait_item_id) = self . tcx . associated_item ( impl_item_id) . trait_item_def_id
520554 && let Some ( local_id) = trait_item_id. as_local ( )
521555 {
522- // for the private method , we can know the trait item is used or not,
556+ // for the local impl item , we can know the trait item is used or not,
523557 // 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) ;
558+ self . live_symbols . contains ( & local_id) && self . live_symbols . contains ( & local_def_id)
559+ } else {
560+ // for the foreign method and inherent pub method,
561+ // we don't know the trait item or the method is used or not,
562+ // so we mark the method live if the self is used
563+ self . live_symbols . contains ( & local_def_id)
526564 }
565+ } else {
566+ false
527567 }
528- false
529568 }
530569}
531570
@@ -747,7 +786,8 @@ fn check_item<'tcx>(
747786 . iter ( )
748787 . filter_map ( |def_id| def_id. as_local ( ) ) ;
749788
750- let ty_is_pub = ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ;
789+ let self_ty = tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ;
790+ let ty_is_pure_pub = ty_ref_to_pure_pub_struct ( tcx, self_ty) ;
751791
752792 // And we access the Map here to get HirId from LocalDefId
753793 for local_def_id in local_def_ids {
@@ -763,18 +803,23 @@ fn check_item<'tcx>(
763803 // for trait impl blocks,
764804 // mark the method live if the self_ty is public,
765805 // or the method is public and may construct self
766- if of_trait
767- && ( !matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocFn )
768- || tcx. visibility ( local_def_id) . is_public ( )
769- && ( ty_is_pub || may_construct_self) )
806+ if of_trait && matches ! ( tcx. def_kind( local_def_id) , DefKind :: AssocTy )
807+ || tcx. visibility ( local_def_id) . is_public ( )
808+ && ( ty_is_pure_pub || may_construct_self)
770809 {
810+ // if the impl item is public,
811+ // and the ty may be constructed or can be constructed in foreign crates,
812+ // mark the impl item live
771813 worklist. push ( ( local_def_id, ComesFromAllowExpect :: No ) ) ;
772814 } else if let Some ( comes_from_allow) =
773815 has_allow_dead_code_or_lang_attr ( tcx, local_def_id)
774816 {
775817 worklist. push ( ( local_def_id, comes_from_allow) ) ;
776- } else if of_trait {
777- // private method || public method not constructs self
818+ } else if of_trait
819+ || tcx. visibility ( local_def_id) . is_public ( )
820+ && ty_ref_to_pub_struct ( tcx, self_ty)
821+ {
822+ // private impl items of traits || public impl items not constructs self
778823 unsolved_impl_items. push ( ( id, local_def_id) ) ;
779824 }
780825 }
@@ -841,6 +886,14 @@ fn create_and_seed_worklist(
841886 effective_vis
842887 . is_public_at_level ( Level :: Reachable )
843888 . then_some ( id)
889+ . filter ( |& id|
890+ // checks impls, impl-items and pub structs with all public fields later
891+ match tcx. def_kind ( id) {
892+ DefKind :: Impl { .. } => false ,
893+ DefKind :: AssocConst | DefKind :: AssocFn => !matches ! ( tcx. associated_item( id) . container, AssocItemContainer :: ImplContainer ) ,
894+ DefKind :: Struct => struct_all_fields_are_public ( tcx, id. to_def_id ( ) ) ,
895+ _ => true
896+ } )
844897 . map ( |id| ( id, ComesFromAllowExpect :: No ) )
845898 } )
846899 // Seed entry point
@@ -1113,10 +1166,13 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
11131166 || ( def_kind == DefKind :: Trait && live_symbols. contains ( & item. owner_id . def_id ) )
11141167 {
11151168 for & def_id in tcx. associated_item_def_ids ( item. owner_id . def_id ) {
1116- // We have diagnosed unused methods in traits
1169+ // We have diagnosed unused assoc consts and fns in traits
11171170 if matches ! ( def_kind, DefKind :: Impl { of_trait: true } )
1118- && tcx. def_kind ( def_id) == DefKind :: AssocFn
1119- || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) != DefKind :: AssocFn
1171+ && matches ! ( tcx. def_kind( def_id) , DefKind :: AssocConst | DefKind :: AssocFn )
1172+ // skip unused public inherent methods,
1173+ // cause we have diagnosed unconstructed struct
1174+ || matches ! ( def_kind, DefKind :: Impl { of_trait: false } ) && tcx. visibility ( def_id) . is_public ( ) && ty_ref_to_pub_struct ( tcx, tcx. hir ( ) . item ( item) . expect_impl ( ) . self_ty )
1175+ || def_kind == DefKind :: Trait && tcx. def_kind ( def_id) == DefKind :: AssocTy
11201176 {
11211177 continue ;
11221178 }
0 commit comments