diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 1c331d53a2a3c..f4c46b6ce09e1 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 e2de0b6bd013d..70fed9af92128 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 { impl AccessLevels { 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 3d8bb6b825b38..0328b5f1fd5e5 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 dd536d673cf4d..f68f2d0da6850 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, 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 0000000000000..306256d53d38c --- /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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "lib"] + +pub fn bar

( // 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 0000000000000..bc347edf8a765 --- /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 or the MIT license +// , 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 +}