@@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
614614 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
615615 tables : & ' a ty:: TypeckTables < ' tcx > ,
616616 current_item : DefId ,
617+ in_body : bool ,
617618 span : Span ,
618619 empty_tables : & ' a ty:: TypeckTables < ' tcx > ,
619620}
@@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
671672 // Take node ID of an expression or pattern and check its type for privacy.
672673 fn check_expr_pat_type ( & mut self , id : hir:: HirId , span : Span ) -> bool {
673674 self . span = span;
674- if let Some ( ty) = self . tables . node_id_to_type_opt ( id) {
675- if ty. visit_with ( self ) {
676- return true ;
677- }
675+ if self . tables . node_id_to_type ( id) . visit_with ( self ) {
676+ return true ;
678677 }
679678 if self . tables . node_substs ( id) . visit_with ( self ) {
680679 return true ;
@@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
688687 }
689688 false
690689 }
690+
691+ fn check_trait_ref ( & mut self , trait_ref : ty:: TraitRef < ' tcx > ) -> bool {
692+ if !self . item_is_accessible ( trait_ref. def_id ) {
693+ let msg = format ! ( "trait `{}` is private" , trait_ref) ;
694+ self . tcx . sess . span_err ( self . span , & msg) ;
695+ return true ;
696+ }
697+
698+ trait_ref. super_visit_with ( self )
699+ }
691700}
692701
693702impl < ' a , ' tcx > Visitor < ' tcx > for TypePrivacyVisitor < ' a , ' tcx > {
@@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
699708
700709 fn visit_nested_body ( & mut self , body : hir:: BodyId ) {
701710 let orig_tables = replace ( & mut self . tables , self . tcx . body_tables ( body) ) ;
711+ let orig_in_body = replace ( & mut self . in_body , true ) ;
702712 let body = self . tcx . hir . body ( body) ;
703713 self . visit_body ( body) ;
704714 self . tables = orig_tables;
715+ self . in_body = orig_in_body;
705716 }
706717
707718 fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty ) {
708719 self . span = hir_ty. span ;
709- if let Some ( ty ) = self . tables . node_id_to_type_opt ( hir_ty . hir_id ) {
720+ if self . in_body {
710721 // Types in bodies.
711- if ty . visit_with ( self ) {
722+ if self . tables . node_id_to_type ( hir_ty . hir_id ) . visit_with ( self ) {
712723 return ;
713724 }
714725 } else {
@@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
724735 }
725736
726737 fn visit_trait_ref ( & mut self , trait_ref : & ' tcx hir:: TraitRef ) {
727- if !self . item_is_accessible ( trait_ref. path . def . def_id ( ) ) {
728- let msg = format ! ( "trait `{:?}` is private" , trait_ref. path) ;
729- self . tcx . sess . span_err ( self . span , & msg) ;
730- return ;
738+ self . span = trait_ref. path . span ;
739+ if !self . in_body {
740+ // Avoid calling `hir_trait_to_predicates` in bodies, it will ICE.
741+ // The traits' privacy in bodies is already checked as a part of trait object types.
742+ let ( principal, projections) =
743+ rustc_typeck:: hir_trait_to_predicates ( self . tcx , trait_ref) ;
744+ if self . check_trait_ref ( * principal. skip_binder ( ) ) {
745+ return ;
746+ }
747+ for poly_predicate in projections {
748+ let tcx = self . tcx ;
749+ if self . check_trait_ref ( poly_predicate. skip_binder ( ) . projection_ty . trait_ref ( tcx) ) {
750+ return ;
751+ }
752+ }
731753 }
732754
733755 intravisit:: walk_trait_ref ( self , trait_ref) ;
@@ -760,19 +782,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
760782 intravisit:: walk_expr ( self , expr) ;
761783 }
762784
785+ // Prohibit access to associated items with insufficient nominal visibility.
786+ //
787+ // Additionally, until better reachability analysis for macros 2.0 is available,
788+ // we prohibit access to private statics from other crates, this allows to give
789+ // more code internal visibility at link time. (Access to private functions
790+ // is already prohibited by type privacy for funciton types.)
763791 fn visit_qpath ( & mut self , qpath : & ' tcx hir:: QPath , id : ast:: NodeId , span : Span ) {
764- // Inherent associated constants don't have self type in substs,
765- // we have to check it additionally.
766- if let hir:: QPath :: TypeRelative ( ..) = * qpath {
767- let hir_id = self . tcx . hir . node_to_hir_id ( id) ;
768- if let Some ( def) = self . tables . type_dependent_defs ( ) . get ( hir_id) . cloned ( ) {
769- if let Some ( assoc_item) = self . tcx . opt_associated_item ( def. def_id ( ) ) {
770- if let ty:: ImplContainer ( impl_def_id) = assoc_item. container {
771- if self . tcx . type_of ( impl_def_id) . visit_with ( self ) {
772- return ;
773- }
774- }
775- }
792+ let def = match * qpath {
793+ hir:: QPath :: Resolved ( _, ref path) => match path. def {
794+ Def :: Method ( ..) | Def :: AssociatedConst ( ..) |
795+ Def :: AssociatedTy ( ..) | Def :: Static ( ..) => Some ( path. def ) ,
796+ _ => None ,
797+ }
798+ hir:: QPath :: TypeRelative ( ..) => {
799+ let hir_id = self . tcx . hir . node_to_hir_id ( id) ;
800+ self . tables . type_dependent_defs ( ) . get ( hir_id) . cloned ( )
801+ }
802+ } ;
803+ if let Some ( def) = def {
804+ let def_id = def. def_id ( ) ;
805+ let is_local_static = if let Def :: Static ( ..) = def { def_id. is_local ( ) } else { false } ;
806+ if !self . item_is_accessible ( def_id) && !is_local_static {
807+ let name = match * qpath {
808+ hir:: QPath :: Resolved ( _, ref path) => format ! ( "{}" , path) ,
809+ hir:: QPath :: TypeRelative ( _, ref segment) => segment. name . to_string ( ) ,
810+ } ;
811+ let msg = format ! ( "{} `{}` is private" , def. kind_name( ) , name) ;
812+ self . tcx . sess . span_err ( span, & msg) ;
813+ return ;
776814 }
777815 }
778816
@@ -807,9 +845,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
807845 item. id ,
808846 & mut self . tables ,
809847 self . empty_tables ) ;
848+ let orig_in_body = replace ( & mut self . in_body , false ) ;
810849 self . current_item = self . tcx . hir . local_def_id ( item. id ) ;
811850 intravisit:: walk_item ( self , item) ;
812851 self . tables = orig_tables;
852+ self . in_body = orig_in_body;
813853 self . current_item = orig_current_item;
814854 }
815855
@@ -869,13 +909,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
869909 }
870910 }
871911 ty:: TyProjection ( ref proj) => {
872- let trait_ref = proj. trait_ref ( self . tcx ) ;
873- if !self . item_is_accessible ( trait_ref. def_id ) {
874- let msg = format ! ( "trait `{}` is private" , trait_ref) ;
875- self . tcx . sess . span_err ( self . span , & msg) ;
876- return true ;
877- }
878- if trait_ref. super_visit_with ( self ) {
912+ let tcx = self . tcx ;
913+ if self . check_trait_ref ( proj. trait_ref ( tcx) ) {
879914 return true ;
880915 }
881916 }
@@ -1278,6 +1313,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
12781313 min_visibility : ty:: Visibility ,
12791314 has_pub_restricted : bool ,
12801315 has_old_errors : bool ,
1316+ in_assoc_ty : bool ,
12811317}
12821318
12831319impl < ' a , ' tcx : ' a > SearchInterfaceForPrivateItemsVisitor < ' a , ' tcx > {
@@ -1338,11 +1374,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
13381374 self . min_visibility = vis;
13391375 }
13401376 if !vis. is_at_least ( self . required_visibility , self . tcx ) {
1341- if self . has_pub_restricted || self . has_old_errors {
1377+ if self . has_pub_restricted || self . has_old_errors || self . in_assoc_ty {
13421378 struct_span_err ! ( self . tcx. sess, self . span, E0445 ,
13431379 "private trait `{}` in public interface" , trait_ref)
13441380 . span_label ( self . span , format ! (
1345- "private trait can't be public " ) )
1381+ "can't leak private trait " ) )
13461382 . emit ( ) ;
13471383 } else {
13481384 self . tcx . lint_node ( lint:: builtin:: PRIVATE_IN_PUBLIC ,
@@ -1393,7 +1429,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
13931429 self . min_visibility = vis;
13941430 }
13951431 if !vis. is_at_least ( self . required_visibility , self . tcx ) {
1396- if self . has_pub_restricted || self . has_old_errors {
1432+ if self . has_pub_restricted || self . has_old_errors || self . in_assoc_ty {
13971433 let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0446 ,
13981434 "private type `{}` in public interface" , ty) ;
13991435 err. span_label ( self . span , "can't leak private type" ) ;
@@ -1454,6 +1490,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
14541490 required_visibility,
14551491 has_pub_restricted : self . has_pub_restricted ,
14561492 has_old_errors,
1493+ in_assoc_ty : false ,
14571494 }
14581495 }
14591496}
@@ -1494,6 +1531,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
14941531
14951532 for trait_item_ref in trait_item_refs {
14961533 let mut check = self . check ( trait_item_ref. id . node_id , item_visibility) ;
1534+ check. in_assoc_ty = trait_item_ref. kind == hir:: AssociatedItemKind :: Type ;
14971535 check. generics ( ) . predicates ( ) ;
14981536
14991537 if trait_item_ref. kind == hir:: AssociatedItemKind :: Type &&
@@ -1544,10 +1582,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
15441582
15451583 for impl_item_ref in impl_item_refs {
15461584 let impl_item = self . tcx . hir . impl_item ( impl_item_ref. id ) ;
1547- let impl_item_vis =
1548- ty :: Visibility :: from_hir ( & impl_item. vis , item . id , tcx ) ;
1549- self . check ( impl_item . id , min ( impl_item_vis , ty_vis ) )
1550- . generics ( ) . predicates ( ) . ty ( ) ;
1585+ let impl_item_vis = ty :: Visibility :: from_hir ( & impl_item . vis , item . id , tcx ) ;
1586+ let mut check = self . check ( impl_item. id , min ( impl_item_vis , ty_vis ) ) ;
1587+ check. in_assoc_ty = impl_item_ref . kind == hir :: AssociatedItemKind :: Type ;
1588+ check . generics ( ) . predicates ( ) . ty ( ) ;
15511589
15521590 // Recurse for e.g. `impl Trait` (see `visit_ty`).
15531591 self . inner_visibility = impl_item_vis;
@@ -1562,7 +1600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
15621600 self . check ( item. id , vis) . generics ( ) . predicates ( ) ;
15631601 for impl_item_ref in impl_item_refs {
15641602 let impl_item = self . tcx . hir . impl_item ( impl_item_ref. id ) ;
1565- self . check ( impl_item. id , vis) . generics ( ) . predicates ( ) . ty ( ) ;
1603+ let mut check = self . check ( impl_item. id , vis) ;
1604+ check. in_assoc_ty = impl_item_ref. kind == hir:: AssociatedItemKind :: Type ;
1605+ check. generics ( ) . predicates ( ) . ty ( ) ;
15661606
15671607 // Recurse for e.g. `impl Trait` (see `visit_ty`).
15681608 self . inner_visibility = vis;
@@ -1629,6 +1669,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
16291669 tcx,
16301670 tables : & empty_tables,
16311671 current_item : DefId :: local ( CRATE_DEF_INDEX ) ,
1672+ in_body : false ,
16321673 span : krate. span ,
16331674 empty_tables : & empty_tables,
16341675 } ;
0 commit comments