about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-01-04 21:30:54 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-01-05 23:46:19 +0300
commit67713f5b7f502ddeec4b41eef36bd281fea83091 (patch)
tree3ff5bf99f32a5a05dcf3816a0b3704e92404b017
parent68fe5182c967259ef89dbe313e4bf80f45a53e7e (diff)
downloadrust-67713f5b7f502ddeec4b41eef36bd281fea83091.tar.gz
rust-67713f5b7f502ddeec4b41eef36bd281fea83091.zip
privacy: Fix regression in impl reachability
-rw-r--r--src/librustc_privacy/lib.rs16
-rw-r--r--src/test/ui/privacy/auxiliary/issue-57264.rs9
-rw-r--r--src/test/ui/privacy/issue-57264.rs8
3 files changed, 30 insertions, 3 deletions
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index c6626c1551f..2f0d53f1d81 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -51,6 +51,7 @@ mod diagnostics;
 /// in `impl Trait`, see individual commits in `DefIdVisitorSkeleton::visit_ty`.
 trait DefIdVisitor<'a, 'tcx: 'a> {
     fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
+    fn recurse(&self) -> bool { true }
     fn recurse_into_assoc_tys(&self) -> bool { true }
     fn visit_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool;
 
@@ -86,7 +87,8 @@ impl<'a, 'tcx, V> DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
 {
     fn visit_trait(&mut self, trait_ref: TraitRef<'tcx>) -> bool {
         let TraitRef { def_id, substs } = trait_ref;
-        self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) || substs.visit_with(self)
+        self.def_id_visitor.visit_def_id(def_id, "trait", &trait_ref) ||
+        self.def_id_visitor.recurse() && substs.visit_with(self)
     }
 
     fn visit_predicates(&mut self, predicates: Lrc<ty::GenericPredicates<'tcx>>) -> bool {
@@ -167,7 +169,7 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
                     // free type aliases, but this isn't done yet.
                     return false;
                 }
-                // This will also visit substs, so we don't need to recurse.
+                // This will also visit substs if necessary, so we don't need to recurse.
                 return self.visit_trait(proj.trait_ref(tcx));
             }
             ty::Dynamic(predicates, ..) => {
@@ -206,7 +208,7 @@ impl<'a, 'tcx, V> TypeVisitor<'tcx> for DefIdVisitorSkeleton<'_, 'a, 'tcx, V>
                 bug!("unexpected type: {:?}", ty),
         }
 
-        ty.super_visit_with(self)
+        self.def_id_visitor.recurse() && ty.super_visit_with(self)
     }
 }
 
@@ -325,6 +327,7 @@ struct FindMin<'a, 'tcx, VL: VisibilityLike> {
 
 impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx, VL> {
     fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> { self.tcx }
+    fn recurse(&self) -> bool { VL::RECURSE }
     fn recurse_into_assoc_tys(&self) -> bool { false }
     fn visit_def_id(&mut self, def_id: DefId, _kind: &str, _descr: &dyn fmt::Display) -> bool {
         self.min = VL::new_min(self, def_id);
@@ -334,6 +337,7 @@ impl<'a, 'tcx, VL: VisibilityLike> DefIdVisitor<'a, 'tcx> for FindMin<'a, 'tcx,
 
 trait VisibilityLike: Sized {
     const MAX: Self;
+    const RECURSE: bool = true;
     fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self;
 
     // Returns an over-approximation (`recurse_into_assoc_tys` = false) of visibility due to
@@ -357,6 +361,12 @@ impl VisibilityLike for ty::Visibility {
 }
 impl VisibilityLike for Option<AccessLevel> {
     const MAX: Self = Some(AccessLevel::Public);
+    // Type inference is very smart sometimes.
+    // It can make an impl reachable even some components of its type or trait are unreachable.
+    // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
+    // can be usable from other crates (#57264). So we skip substs when calculating reachability
+    // and consider an impl reachable if its "primary" type and trait are reachable.
+    const RECURSE: bool = false;
     fn new_min<'a, 'tcx>(find: &FindMin<'a, 'tcx, Self>, def_id: DefId) -> Self {
         cmp::min(if let Some(node_id) = find.tcx.hir().as_local_node_id(def_id) {
             find.access_levels.map.get(&node_id).cloned()
diff --git a/src/test/ui/privacy/auxiliary/issue-57264.rs b/src/test/ui/privacy/auxiliary/issue-57264.rs
new file mode 100644
index 00000000000..9302fa0d9e8
--- /dev/null
+++ b/src/test/ui/privacy/auxiliary/issue-57264.rs
@@ -0,0 +1,9 @@
+mod inner {
+    pub struct PubUnnameable;
+}
+
+pub struct Pub<T>(T);
+
+impl Pub<inner::PubUnnameable> {
+    pub fn pub_method() {}
+}
diff --git a/src/test/ui/privacy/issue-57264.rs b/src/test/ui/privacy/issue-57264.rs
new file mode 100644
index 00000000000..57e9960a058
--- /dev/null
+++ b/src/test/ui/privacy/issue-57264.rs
@@ -0,0 +1,8 @@
+// compile-pass
+// aux-build:issue-57264.rs
+
+extern crate issue_57264;
+
+fn main() {
+    issue_57264::Pub::pub_method();
+}