about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-08-24 23:27:16 +0800
committerkennytm <kennytm@gmail.com>2018-08-24 23:27:16 +0800
commita1ec2f76bb409a03a1993bf40fa092cc937b0f5f (patch)
tree0672767f14414707d887625ce6ef2f9f2883697d /src
parent62f29c4fb811da8ea2c2584d0d2c6bcf316b0a7a (diff)
parent85a05d1815217584c096ebc9d64b3a547b667f48 (diff)
downloadrust-a1ec2f76bb409a03a1993bf40fa092cc937b0f5f.tar.gz
rust-a1ec2f76bb409a03a1993bf40fa092cc937b0f5f.zip
Rollup merge of #53545 - FelixMcFelix:fix-50865-beta, r=petrochenkov
Fix #50865: ICE on impl-trait returning functions reaching private items

Adds a test case as suggested in #50865, and implements @petrochenkov's suggestion. Fixes #50865.

Impl-trait-returning functions are marked under a new (low) access level, which they propagate rather than `AccessLevels::Reachable`. `AccessLevels::is_reachable` returns false for such items (leaving stability analysis unaffected), these items may still be visible to the lints phase however.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs1
-rw-r--r--src/librustc/middle/privacy.rs4
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc_privacy/lib.rs23
-rw-r--r--src/test/run-pass/issue-50865-private-impl-trait/auxiliary/lib.rs24
-rw-r--r--src/test/run-pass/issue-50865-private-impl-trait/main.rs25
6 files changed, 72 insertions, 7 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 1c331d53a2a..f4c46b6ce09 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1091,6 +1091,7 @@ impl_stable_hash_for!(enum traits::Reveal {
 });
 
 impl_stable_hash_for!(enum ::middle::privacy::AccessLevel {
+    ReachableFromImplTrait,
     Reachable,
     Exported,
     Public
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index e2de0b6bd01..70fed9af921 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -21,6 +21,8 @@ use syntax::ast::NodeId;
 // Accessibility levels, sorted in ascending order
 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub enum AccessLevel {
+    // Superset of Reachable used to mark impl Trait items.
+    ReachableFromImplTrait,
     // Exported items + items participating in various kinds of public interfaces,
     // but not directly nameable. For example, if function `fn f() -> T {...}` is
     // public, then type `T` is reachable. Its values can be obtained by other crates
@@ -40,7 +42,7 @@ pub struct AccessLevels<Id = NodeId> {
 
 impl<Id: Hash + Eq> AccessLevels<Id> {
     pub fn is_reachable(&self, id: Id) -> bool {
-        self.map.contains_key(&id)
+        self.map.get(&id) >= Some(&AccessLevel::Reachable)
     }
     pub fn is_exported(&self, id: Id) -> bool {
         self.map.get(&id) >= Some(&AccessLevel::Exported)
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 3d8bb6b825b..0328b5f1fd5 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -434,6 +434,8 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) ->
     // Step 2: Mark all symbols that the symbols on the worklist touch.
     reachable_context.propagate();
 
+    debug!("Inline reachability shows: {:?}", reachable_context.reachable_symbols);
+
     // Return the set of reachable symbols.
     ReachableSet(Lrc::new(reachable_context.reachable_symbols))
 }
diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs
index dd536d673cf..f68f2d0da68 100644
--- a/src/librustc_privacy/lib.rs
+++ b/src/librustc_privacy/lib.rs
@@ -82,6 +82,7 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
 }
 
 struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
+    access_level: Option<AccessLevel>,
     item_def_id: DefId,
     ev: &'b mut EmbargoVisitor<'a, 'tcx>,
 }
@@ -132,6 +133,7 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
     fn reach<'b>(&'b mut self, item_id: ast::NodeId)
                  -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
         ReachEverythingInTheInterfaceVisitor {
+            access_level: self.prev_level.map(|l| l.min(AccessLevel::Reachable)),
             item_def_id: self.tcx.hir.local_def_id(item_id),
             ev: self,
         }
@@ -214,7 +216,15 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
                     }
                 }
             }
-            hir::ItemKind::Existential(..) |
+            // Impl trait return types mark their parent function.
+            // It (and its children) are revisited if the change applies.
+            hir::ItemKind::Existential(ref ty_data) => {
+                if let Some(impl_trait_fn) = ty_data.impl_trait_fn {
+                    if let Some(node_id) = self.tcx.hir.as_local_node_id(impl_trait_fn) {
+                        self.update(node_id, Some(AccessLevel::ReachableFromImplTrait));
+                    }
+                }
+            }
             hir::ItemKind::Use(..) |
             hir::ItemKind::Static(..) |
             hir::ItemKind::Const(..) |
@@ -226,6 +236,10 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
             hir::ItemKind::ExternCrate(..) => {}
         }
 
+        // Store this node's access level here to propagate the correct
+        // reachability level through interfaces and children.
+        let orig_level = replace(&mut self.prev_level, item_level);
+
         // Mark all items in interfaces of reachable items as reachable
         match item.node {
             // The interface is empty
@@ -324,9 +338,6 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
             }
         }
 
-        let orig_level = self.prev_level;
-        self.prev_level = item_level;
-
         intravisit::walk_item(self, item);
 
         self.prev_level = orig_level;
@@ -462,7 +473,7 @@ impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
     fn check_trait_ref(&mut self, trait_ref: ty::TraitRef<'tcx>) {
         if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(trait_ref.def_id) {
             let item = self.ev.tcx.hir.expect_item(node_id);
-            self.ev.update(item.id, Some(AccessLevel::Reachable));
+            self.ev.update(item.id, self.access_level);
         }
     }
 }
@@ -483,7 +494,7 @@ impl<'b, 'a, 'tcx> TypeVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'b
 
         if let Some(def_id) = ty_def_id {
             if let Some(node_id) = self.ev.tcx.hir.as_local_node_id(def_id) {
-                self.ev.update(node_id, Some(AccessLevel::Reachable));
+                self.ev.update(node_id, self.access_level);
             }
         }
 
diff --git a/src/test/run-pass/issue-50865-private-impl-trait/auxiliary/lib.rs b/src/test/run-pass/issue-50865-private-impl-trait/auxiliary/lib.rs
new file mode 100644
index 00000000000..306256d53d3
--- /dev/null
+++ b/src/test/run-pass/issue-50865-private-impl-trait/auxiliary/lib.rs
@@ -0,0 +1,24 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+
+pub fn bar<P>( // Error won't happen if "bar" is not generic
+    _baz: P,
+) {
+    hide_foo()();
+}
+
+fn hide_foo() -> impl Fn() { // Error won't happen if "iterate" hasn't impl Trait or has generics
+    foo
+}
+
+fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
+}
diff --git a/src/test/run-pass/issue-50865-private-impl-trait/main.rs b/src/test/run-pass/issue-50865-private-impl-trait/main.rs
new file mode 100644
index 00000000000..bc347edf8a7
--- /dev/null
+++ b/src/test/run-pass/issue-50865-private-impl-trait/main.rs
@@ -0,0 +1,25 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:lib.rs
+
+// Regression test for #50865.
+// When using generics or specifying the type directly, this example
+// codegens `foo` internally. However, when using a private `impl Trait`
+// function which references another private item, `foo` (in this case)
+// wouldn't be codegenned until main.rs used `bar`, as with impl Trait
+// it is not cast to `fn()` automatically to satisfy e.g.
+// `fn foo() -> fn() { ... }`.
+
+extern crate lib;
+
+fn main() {
+    lib::bar(()); // Error won't happen if bar is called from same crate
+}