@@ -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,63 @@ fn should_explore(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
4444    ) 
4545} 
4646
47- fn  ty_ref_to_pub_struct ( tcx :  TyCtxt < ' _ > ,  ty :  & hir:: Ty < ' _ > )  -> bool  { 
47+ struct  Publicness  { 
48+     ty_is_public :  bool , 
49+     ty_and_all_fields_are_public :  bool , 
50+ } 
51+ 
52+ impl  Publicness  { 
53+     fn  new ( ty_is_public :  bool ,  ty_and_all_fields_are_public :  bool )  -> Self  { 
54+         Self  {  ty_is_public,  ty_and_all_fields_are_public } 
55+     } 
56+ } 
57+ 
58+ fn  struct_all_fields_are_public ( tcx :  TyCtxt < ' _ > ,  id :  DefId )  -> bool  { 
59+     // treat PhantomData and positional ZST as public, 
60+     // we don't want to lint types which only have them, 
61+     // cause it's a common way to use such types to check things like well-formedness 
62+     tcx. adt_def ( id) . all_fields ( ) . all ( |field| { 
63+         let  field_type = tcx. type_of ( field. did ) . instantiate_identity ( ) ; 
64+         if  field_type. is_phantom_data ( )  { 
65+             return  true ; 
66+         } 
67+         let  is_positional = field. name . as_str ( ) . starts_with ( |c :  char | c. is_ascii_digit ( ) ) ; 
68+         if  is_positional
69+             && tcx
70+                 . layout_of ( tcx. param_env ( field. did ) . and ( field_type) ) 
71+                 . map_or ( true ,  |layout| layout. is_zst ( ) ) 
72+         { 
73+             return  true ; 
74+         } 
75+         field. vis . is_public ( ) 
76+     } ) 
77+ } 
78+ 
79+ /// check struct and its fields are public or not, 
80+ /// for enum and union, just check they are public, 
81+ /// and doesn't solve types like &T for now, just skip them 
82+ fn  ty_ref_to_pub_struct ( tcx :  TyCtxt < ' _ > ,  ty :  & hir:: Ty < ' _ > )  -> Publicness  { 
4883    if  let  TyKind :: Path ( hir:: QPath :: Resolved ( _,  path) )  = ty. kind 
4984        && let  Res :: Def ( def_kind,  def_id)  = path. res 
5085        && def_id. is_local ( ) 
51-         && matches ! ( def_kind,  DefKind :: Struct  | DefKind :: Enum  | DefKind :: Union ) 
5286    { 
53-         tcx. visibility ( def_id) . is_public ( ) 
54-     }  else  { 
55-         true 
87+         return  match  def_kind { 
88+             DefKind :: Enum  | DefKind :: Union  => { 
89+                 let  ty_is_public = tcx. visibility ( def_id) . is_public ( ) ; 
90+                 Publicness :: new ( ty_is_public,  ty_is_public) 
91+             } 
92+             DefKind :: Struct  => { 
93+                 let  ty_is_public = tcx. visibility ( def_id) . is_public ( ) ; 
94+                 Publicness :: new ( 
95+                     ty_is_public, 
96+                     ty_is_public && struct_all_fields_are_public ( tcx,  def_id) , 
97+                 ) 
98+             } 
99+             _ => Publicness :: new ( true ,  true ) , 
100+         } ; 
56101    } 
102+ 
103+     Publicness :: new ( true ,  true ) 
57104} 
58105
59106/// Determine if a work from the worklist is coming from the a `#[allow]` 
@@ -427,9 +474,11 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
427474                        { 
428475                            if  matches ! ( trait_item. kind,  hir:: TraitItemKind :: Fn ( ..) ) 
429476                                && !ty_ref_to_pub_struct ( self . tcx ,  impl_ref. self_ty ) 
477+                                     . ty_and_all_fields_are_public 
430478                            { 
431-                                 // skip methods of private ty, 
432-                                 // they would be solved in `solve_rest_impl_items` 
479+                                 // skip impl-items of non pure pub ty, 
480+                                 // cause we don't know the ty is constructed or not, 
481+                                 // check these later in `solve_rest_impl_items` 
433482                                continue ; 
434483                            } 
435484
@@ -510,22 +559,21 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
510559            && let  Some ( local_def_id)  = def_id. as_local ( ) 
511560            && matches ! ( def_kind,  DefKind :: Struct  | DefKind :: Enum  | DefKind :: Union ) 
512561        { 
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- 
519562            if  let  Some ( trait_item_id)  = self . tcx . associated_item ( impl_item_id) . trait_item_def_id 
520563                && let  Some ( local_id)  = trait_item_id. as_local ( ) 
521564            { 
522-                 // for the private method , we can know the trait item is used or not, 
565+                 // for the local impl item , we can know the trait item is used or not, 
523566                // 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) ; 
567+                 self . live_symbols . contains ( & local_id)  && self . live_symbols . contains ( & local_def_id) 
568+             }  else  { 
569+                 // for the foreign method and inherent pub method, 
570+                 // we don't know the trait item or the method is used or not, 
571+                 // so we mark the method live if the self is used 
572+                 self . live_symbols . contains ( & local_def_id) 
526573            } 
574+         }  else  { 
575+             false 
527576        } 
528-         false 
529577    } 
530578} 
531579
@@ -746,7 +794,9 @@ fn check_item<'tcx>(
746794                . iter ( ) 
747795                . filter_map ( |def_id| def_id. as_local ( ) ) ; 
748796
749-             let  ty_is_pub = ty_ref_to_pub_struct ( tcx,  tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ) ; 
797+             let  self_ty = tcx. hir ( ) . item ( id) . expect_impl ( ) . self_ty ; 
798+             let  Publicness  {  ty_is_public,  ty_and_all_fields_are_public }  =
799+                 ty_ref_to_pub_struct ( tcx,  self_ty) ; 
750800
751801            // And we access the Map here to get HirId from LocalDefId 
752802            for  local_def_id in  local_def_ids { 
@@ -762,18 +812,20 @@ fn check_item<'tcx>(
762812                // for trait impl blocks, 
763813                // mark the method live if the self_ty is public, 
764814                // 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) ) 
815+                 if  of_trait && matches ! ( tcx. def_kind( local_def_id) ,  DefKind :: AssocTy ) 
816+                     || tcx. visibility ( local_def_id) . is_public ( ) 
817+                         && ( ty_and_all_fields_are_public || may_construct_self) 
769818                { 
819+                     // if the impl item is public, 
820+                     // and the ty may be constructed or can be constructed in foreign crates, 
821+                     // mark the impl item live 
770822                    worklist. push ( ( local_def_id,  ComesFromAllowExpect :: No ) ) ; 
771823                }  else  if  let  Some ( comes_from_allow)  =
772824                    has_allow_dead_code_or_lang_attr ( tcx,  local_def_id) 
773825                { 
774826                    worklist. push ( ( local_def_id,  comes_from_allow) ) ; 
775-                 }  else  if  of_trait { 
776-                     // private method  || public method  not constructs self 
827+                 }  else  if  of_trait || tcx . visibility ( local_def_id ) . is_public ( )  && ty_is_public  { 
828+                     // private impl items of traits  || public impl items  not constructs self 
777829                    unsolved_impl_items. push ( ( id,  local_def_id) ) ; 
778830                } 
779831            } 
@@ -840,6 +892,14 @@ fn create_and_seed_worklist(
840892            effective_vis
841893                . is_public_at_level ( Level :: Reachable ) 
842894                . then_some ( id) 
895+                 . filter ( |& id|
896+                     // checks impls, impl-items and pub structs with all public fields later 
897+                     match  tcx. def_kind ( id)  { 
898+                         DefKind :: Impl  {  .. }  => false , 
899+                         DefKind :: AssocConst  | DefKind :: AssocFn  => !matches ! ( tcx. associated_item( id) . container,  AssocItemContainer :: ImplContainer ) , 
900+                         DefKind :: Struct  => struct_all_fields_are_public ( tcx,  id. to_def_id ( ) ) , 
901+                         _ => true 
902+                     } ) 
843903                . map ( |id| ( id,  ComesFromAllowExpect :: No ) ) 
844904        } ) 
845905        // Seed entry point 
@@ -1112,10 +1172,15 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) {
11121172            || ( def_kind == DefKind :: Trait  && live_symbols. contains ( & item. owner_id . def_id ) ) 
11131173        { 
11141174            for  & def_id in  tcx. associated_item_def_ids ( item. owner_id . def_id )  { 
1115-                 // We have diagnosed unused methods  in traits 
1175+                 // We have diagnosed unused assoc consts and fns  in traits 
11161176                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 
1177+                     && matches ! ( tcx. def_kind( def_id) ,  DefKind :: AssocConst  | DefKind :: AssocFn ) 
1178+                     // skip unused public inherent methods, 
1179+                     // cause we have diagnosed unconstructed struct 
1180+                     || matches ! ( def_kind,  DefKind :: Impl  {  of_trait:  false  } ) 
1181+                         && tcx. visibility ( def_id) . is_public ( ) 
1182+                         && ty_ref_to_pub_struct ( tcx,  tcx. hir ( ) . item ( item) . expect_impl ( ) . self_ty ) . ty_is_public 
1183+                     || def_kind == DefKind :: Trait  && tcx. def_kind ( def_id)  == DefKind :: AssocTy 
11191184                { 
11201185                    continue ; 
11211186                } 
0 commit comments