@@ -1458,6 +1458,7 @@ struct SearchInterfaceForPrivateItemsVisitor<'a, 'tcx: 'a> {
1458
1458
has_pub_restricted : bool ,
1459
1459
has_old_errors : bool ,
1460
1460
in_assoc_ty : bool ,
1461
+ public_crates : FxHashSet < CrateNum >
1461
1462
}
1462
1463
1463
1464
impl < ' a , ' tcx : ' a > SearchInterfaceForPrivateItemsVisitor < ' a , ' tcx > {
@@ -1514,22 +1515,134 @@ impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
1514
1515
self . tcx . lint_node ( lint:: builtin:: PRIVATE_IN_PUBLIC , node_id, self . span ,
1515
1516
& format ! ( "{} (error {})" , msg, err_code) ) ;
1516
1517
}
1518
+
1519
+ if self . leaks_private_dep ( trait_ref. def_id ) {
1520
+ self . tcx . lint_node ( lint:: builtin:: LEAKED_PRIVATE_DEPENDENCY ,
1521
+ node_id,
1522
+ self . span ,
1523
+ & format ! ( "trait `{}` from private dependency '{}' in public \
1524
+ interface", trait_ref,
1525
+ trait_ref. def_id. krate) ) ;
1526
+
1527
+ }
1517
1528
}
1518
- false
1529
+ }
1530
+
1531
+ /// An item is 'leaked' from a private dependency if all
1532
+ /// of the following are true:
1533
+ /// 1. It's contained within a public type
1534
+ /// 2. It does not come from a crate marked as public
1535
+ fn leaks_private_dep ( & self , item_id : DefId ) -> bool {
1536
+ // Never do any leak checking if the feature is not enabled
1537
+ if !self . tcx . features ( ) . public_private_dependencies {
1538
+ return false
1539
+ }
1540
+ self . required_visibility == ty:: Visibility :: Public &&
1541
+ !item_id. is_local ( ) &&
1542
+ !self . public_crates . contains ( & item_id. krate )
1519
1543
}
1520
1544
}
1521
1545
1522
- impl < ' a , ' tcx > DefIdVisitor < ' a , ' tcx > for SearchInterfaceForPrivateItemsVisitor < ' a , ' tcx > {
1523
- fn tcx ( & self ) -> TyCtxt < ' a , ' tcx , ' tcx > { self . tcx }
1524
- fn visit_def_id ( & mut self , def_id : DefId , kind : & str , descr : & dyn fmt:: Display ) -> bool {
1525
- self . check_def_id ( def_id, kind, descr)
1546
+ impl < ' a , ' tcx : ' a > TypeVisitor < ' tcx > for SearchInterfaceForPrivateItemsVisitor < ' a , ' tcx > {
1547
+ fn visit_ty ( & mut self , ty : Ty < ' tcx > ) -> bool {
1548
+ let ty_def_id = match ty. sty {
1549
+ ty:: Adt ( adt, _) => Some ( adt. did ) ,
1550
+ ty:: Foreign ( did) => Some ( did) ,
1551
+ ty:: Dynamic ( ref obj, ..) => Some ( obj. principal ( ) . def_id ( ) ) ,
1552
+ ty:: Projection ( ref proj) => {
1553
+ if self . required_visibility == ty:: Visibility :: Invisible {
1554
+ // Conservatively approximate the whole type alias as public without
1555
+ // recursing into its components when determining impl publicity.
1556
+ // For example, `impl <Type as Trait>::Alias {...}` may be a public impl
1557
+ // even if both `Type` and `Trait` are private.
1558
+ // Ideally, associated types should be substituted in the same way as
1559
+ // free type aliases, but this isn't done yet.
1560
+ return false ;
1561
+ }
1562
+ let trait_ref = proj. trait_ref ( self . tcx ) ;
1563
+ Some ( trait_ref. def_id )
1564
+ }
1565
+ _ => None
1566
+ } ;
1567
+
1568
+ if let Some ( def_id) = ty_def_id {
1569
+ // Non-local means public (private items can't leave their crate, modulo bugs).
1570
+ if let Some ( node_id) = self . tcx . hir ( ) . as_local_node_id ( def_id) {
1571
+ let hir_vis = match self . tcx . hir ( ) . find ( node_id) {
1572
+ Some ( Node :: Item ( item) ) => & item. vis ,
1573
+ Some ( Node :: ForeignItem ( item) ) => & item. vis ,
1574
+ _ => bug ! ( "expected item of foreign item" ) ,
1575
+ } ;
1576
+
1577
+ let vis = ty:: Visibility :: from_hir ( hir_vis, node_id, self . tcx ) ;
1578
+
1579
+ if !vis. is_at_least ( self . min_visibility , self . tcx ) {
1580
+ self . min_visibility = vis;
1581
+ }
1582
+ if !vis. is_at_least ( self . required_visibility , self . tcx ) {
1583
+ let vis_adj = match hir_vis. node {
1584
+ hir:: VisibilityKind :: Crate ( _) => "crate-visible" ,
1585
+ hir:: VisibilityKind :: Restricted { .. } => "restricted" ,
1586
+ _ => "private"
1587
+ } ;
1588
+
1589
+ if self . has_pub_restricted || self . has_old_errors || self . in_assoc_ty {
1590
+ let mut err = struct_span_err ! ( self . tcx. sess, self . span, E0446 ,
1591
+ "{} type `{}` in public interface" , vis_adj, ty) ;
1592
+ err. span_label ( self . span , format ! ( "can't leak {} type" , vis_adj) ) ;
1593
+ err. span_label ( hir_vis. span , format ! ( "`{}` declared as {}" , ty, vis_adj) ) ;
1594
+ err. emit ( ) ;
1595
+ } else {
1596
+ self . tcx . lint_node ( lint:: builtin:: PRIVATE_IN_PUBLIC ,
1597
+ node_id,
1598
+ self . span ,
1599
+ & format ! ( "{} type `{}` in public \
1600
+ interface (error E0446)", vis_adj, ty) ) ;
1601
+ }
1602
+ }
1603
+
1604
+ if self . leaks_private_dep ( def_id) {
1605
+ self . tcx . lint_node ( lint:: builtin:: LEAKED_PRIVATE_DEPENDENCY ,
1606
+ node_id,
1607
+ self . span ,
1608
+ & format ! ( "type '{}' from private dependency '{}' in \
1609
+ public interface", ty, def_id. krate) ) ;
1610
+ }
1611
+ }
1612
+ }
1613
+
1614
+ ty. super_visit_with ( self )
1615
+ }
1616
+ }
1617
+
1618
+ /*struct LeakedPrivateDependenciesVisitor<'a, 'tcx: 'a> {
1619
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
1620
+ public_crates: FxHashSet<CrateNum>
1621
+ }
1622
+
1623
+ impl<'a, 'tcx> LeakedPrivateDependenciesVisitor<'a, 'tcx> {
1624
+ fn is_private_dep(&self, item_id: DefId) {
1625
+ !item_id.is_local() && !self.public_crates.contains(item_id.krate)
1526
1626
}
1627
+
1527
1628
}
1528
1629
1630
+ impl<'a, 'tcx> Visitor<'tcx> for LeakedPrivateDependenciesVisitor<'a, 'tcx> {
1631
+ fn nested_visit_map<'this>(&'this mut self) -> nestedvisitormap<'this, 'tcx> {
1632
+ nestedvisitormap::onlybodies(&self.tcx.hir())
1633
+ }
1634
+
1635
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
1636
+
1637
+ }
1638
+
1639
+ }*/
1640
+
1529
1641
struct PrivateItemsInPublicInterfacesVisitor < ' a , ' tcx : ' a > {
1530
1642
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
1531
1643
has_pub_restricted : bool ,
1532
1644
old_error_set : & ' a NodeSet ,
1645
+ public_crates : FxHashSet < CrateNum >
1533
1646
}
1534
1647
1535
1648
impl < ' a , ' tcx > PrivateItemsInPublicInterfacesVisitor < ' a , ' tcx > {
@@ -1566,6 +1679,7 @@ impl<'a, 'tcx> PrivateItemsInPublicInterfacesVisitor<'a, 'tcx> {
1566
1679
has_pub_restricted : self . has_pub_restricted ,
1567
1680
has_old_errors,
1568
1681
in_assoc_ty : false ,
1682
+ public_crates : self . public_crates . clone ( )
1569
1683
}
1570
1684
}
1571
1685
@@ -1690,6 +1804,10 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Lrc<AccessLevels> {
1690
1804
fn check_mod_privacy < ' tcx > ( tcx : TyCtxt < ' _ , ' tcx , ' tcx > , module_def_id : DefId ) {
1691
1805
let empty_tables = ty:: TypeckTables :: empty ( None ) ;
1692
1806
1807
+ let public_crates: FxHashSet < CrateNum > = tcx. sess . opts . extern_public . iter ( ) . flat_map ( |c| {
1808
+ tcx. crates ( ) . iter ( ) . find ( |& & krate| & tcx. crate_name ( krate) == c) . cloned ( )
1809
+ } ) . collect ( ) ;
1810
+
1693
1811
// Check privacy of names not checked in previous compilation stages.
1694
1812
let mut visitor = NamePrivacyVisitor {
1695
1813
tcx,
@@ -1767,6 +1885,7 @@ fn privacy_access_levels<'tcx>(
1767
1885
tcx,
1768
1886
has_pub_restricted,
1769
1887
old_error_set : & visitor. old_error_set ,
1888
+ public_crates
1770
1889
} ;
1771
1890
krate. visit_all_item_likes ( & mut DeepVisitor :: new ( & mut visitor) ) ;
1772
1891
}
0 commit comments