@@ -614,6 +614,7 @@ struct TypePrivacyVisitor<'a, 'tcx: 'a> {
614
614
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
615
615
tables : & ' a ty:: TypeckTables < ' tcx > ,
616
616
current_item : DefId ,
617
+ in_body : bool ,
617
618
span : Span ,
618
619
empty_tables : & ' a ty:: TypeckTables < ' tcx > ,
619
620
}
@@ -671,10 +672,8 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
671
672
// Take node ID of an expression or pattern and check its type for privacy.
672
673
fn check_expr_pat_type ( & mut self , id : hir:: HirId , span : Span ) -> bool {
673
674
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 ;
678
677
}
679
678
if self . tables . node_substs ( id) . visit_with ( self ) {
680
679
return true ;
@@ -688,6 +687,16 @@ impl<'a, 'tcx> TypePrivacyVisitor<'a, 'tcx> {
688
687
}
689
688
false
690
689
}
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
+ }
691
700
}
692
701
693
702
impl < ' a , ' tcx > Visitor < ' tcx > for TypePrivacyVisitor < ' a , ' tcx > {
@@ -699,16 +708,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
699
708
700
709
fn visit_nested_body ( & mut self , body : hir:: BodyId ) {
701
710
let orig_tables = replace ( & mut self . tables , self . tcx . body_tables ( body) ) ;
711
+ let orig_in_body = replace ( & mut self . in_body , true ) ;
702
712
let body = self . tcx . hir . body ( body) ;
703
713
self . visit_body ( body) ;
704
714
self . tables = orig_tables;
715
+ self . in_body = orig_in_body;
705
716
}
706
717
707
718
fn visit_ty ( & mut self , hir_ty : & ' tcx hir:: Ty ) {
708
719
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 {
710
721
// Types in bodies.
711
- if ty . visit_with ( self ) {
722
+ if self . tables . node_id_to_type ( hir_ty . hir_id ) . visit_with ( self ) {
712
723
return ;
713
724
}
714
725
} else {
@@ -724,10 +735,21 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
724
735
}
725
736
726
737
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
+ }
731
753
}
732
754
733
755
intravisit:: walk_trait_ref ( self , trait_ref) ;
@@ -760,19 +782,35 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
760
782
intravisit:: walk_expr ( self , expr) ;
761
783
}
762
784
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.)
763
791
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 ;
776
814
}
777
815
}
778
816
@@ -807,9 +845,11 @@ impl<'a, 'tcx> Visitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
807
845
item. id ,
808
846
& mut self . tables ,
809
847
self . empty_tables ) ;
848
+ let orig_in_body = replace ( & mut self . in_body , false ) ;
810
849
self . current_item = self . tcx . hir . local_def_id ( item. id ) ;
811
850
intravisit:: walk_item ( self , item) ;
812
851
self . tables = orig_tables;
852
+ self . in_body = orig_in_body;
813
853
self . current_item = orig_current_item;
814
854
}
815
855
@@ -869,13 +909,8 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for TypePrivacyVisitor<'a, 'tcx> {
869
909
}
870
910
}
871
911
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) ) {
879
914
return true ;
880
915
}
881
916
}
@@ -1278,6 +1313,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
1278
1313
min_visibility : ty:: Visibility ,
1279
1314
has_pub_restricted : bool ,
1280
1315
has_old_errors : bool ,
1316
+ in_assoc_ty : bool ,
1281
1317
}
1282
1318
1283
1319
impl < ' a , ' tcx : ' a > SearchInterfaceForPrivateItemsVisitor < ' a , ' tcx > {
@@ -1338,11 +1374,11 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1338
1374
self . min_visibility = vis;
1339
1375
}
1340
1376
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 {
1342
1378
struct_span_err ! ( self . tcx. sess, self . span, E0445 ,
1343
1379
"private trait `{}` in public interface" , trait_ref)
1344
1380
. span_label ( self . span , format ! (
1345
- "private trait can't be public " ) )
1381
+ "can't leak private trait " ) )
1346
1382
. emit ( ) ;
1347
1383
} else {
1348
1384
self . tcx . lint_node ( lint:: builtin:: PRIVATE_IN_PUBLIC ,
@@ -1393,7 +1429,7 @@ impl<'a, 'tcx: 'a> TypeVisitor<'tcx> for SearchInterfaceForPrivateItemsVisitor<'
1393
1429
self . min_visibility = vis;
1394
1430
}
1395
1431
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 {
1397
1433
let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0446 ,
1398
1434
"private type `{}` in public interface" , ty) ;
1399
1435
err. span_label ( self . span , "can't leak private type" ) ;
@@ -1454,6 +1490,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1454
1490
required_visibility,
1455
1491
has_pub_restricted : self . has_pub_restricted ,
1456
1492
has_old_errors,
1493
+ in_assoc_ty : false ,
1457
1494
}
1458
1495
}
1459
1496
}
@@ -1494,6 +1531,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
1494
1531
1495
1532
for trait_item_ref in trait_item_refs {
1496
1533
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 ;
1497
1535
check. generics ( ) . predicates ( ) ;
1498
1536
1499
1537
if trait_item_ref. kind == hir:: AssociatedItemKind :: Type &&
@@ -1544,10 +1582,10 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
1544
1582
1545
1583
for impl_item_ref in impl_item_refs {
1546
1584
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 ( ) ;
1551
1589
1552
1590
// Recurse for e.g. `impl Trait` (see `visit_ty`).
1553
1591
self . inner_visibility = impl_item_vis;
@@ -1562,7 +1600,9 @@ impl<'a, 'tcx> Visitor<'tcx> for PrivateItemsInPublicInterfacesVisitor<'a, 'tcx>
1562
1600
self . check ( item. id , vis) . generics ( ) . predicates ( ) ;
1563
1601
for impl_item_ref in impl_item_refs {
1564
1602
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 ( ) ;
1566
1606
1567
1607
// Recurse for e.g. `impl Trait` (see `visit_ty`).
1568
1608
self . inner_visibility = vis;
@@ -1629,6 +1669,7 @@ fn privacy_access_levels<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1629
1669
tcx,
1630
1670
tables : & empty_tables,
1631
1671
current_item : DefId :: local ( CRATE_DEF_INDEX ) ,
1672
+ in_body : false ,
1632
1673
span : krate. span ,
1633
1674
empty_tables : & empty_tables,
1634
1675
} ;
0 commit comments