未验证 提交 a1ec2f76 编写于 作者: K kennytm

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.
......@@ -1091,6 +1091,7 @@ fn hash_stable<W: StableHasherResult>(&self,
});
impl_stable_hash_for!(enum ::middle::privacy::AccessLevel {
ReachableFromImplTrait,
Reachable,
Exported,
Public
......
......@@ -21,6 +21,8 @@
// 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)
......
......@@ -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))
}
......
......@@ -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 @@ fn update(&mut self, id: ast::NodeId, level: Option<AccessLevel>) -> Option<Acce
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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
}
}
}
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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
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 @@ fn visit_item(&mut self, item: &'tcx hir::Item) {
}
}
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 @@ fn impl_trait_ref(&mut self) -> &mut Self {
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 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool {
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);
}
}
......
// 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
}
// 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
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册