Auto merge of #38250 - michaelwoerister:trait-methods-in-reachable, r=alexcrichton

Consider provided trait methods in middle::reachable

Fixes https://github.com/rust-lang/rust/issues/38226 by also considering trait methods with default implementation instead of just methods provided in an impl.

r? @alexcrichton
cc @panicbit
This commit is contained in:
bors 2016-12-11 06:37:19 +00:00
commit 368e092c26
4 changed files with 86 additions and 7 deletions

View File

@ -323,19 +323,37 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
// items of non-exported traits (or maybe all local traits?) unless their respective
// trait items are used from inlinable code through method call syntax or UFCS, or their
// trait is a lang item.
struct CollectPrivateImplItemsVisitor<'a> {
struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
access_levels: &'a privacy::AccessLevels,
worklist: &'a mut Vec<ast::NodeId>,
}
impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> {
impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &hir::Item) {
// We need only trait impls here, not inherent impls, and only non-exported ones
if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node {
if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node {
if !self.access_levels.is_reachable(item.id) {
for impl_item_ref in impl_item_refs {
self.worklist.push(impl_item_ref.id.node_id);
}
let trait_def_id = match trait_ref.path.def {
Def::Trait(def_id) => def_id,
_ => unreachable!()
};
if !trait_def_id.is_local() {
return
}
for default_method in self.tcx.provided_trait_methods(trait_def_id) {
let node_id = self.tcx
.map
.as_local_node_id(default_method.def_id)
.unwrap();
self.worklist.push(node_id);
}
}
}
}
@ -369,6 +387,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
{
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
tcx: tcx,
access_levels: access_levels,
worklist: &mut reachable_context.worklist,
};

View File

@ -51,8 +51,10 @@ impl ExportedSymbols {
scx.tcx().map.local_def_id(node_id)
})
.map(|def_id| {
(symbol_for_def_id(scx, def_id, symbol_map),
export_level(scx, def_id))
let name = symbol_for_def_id(scx, def_id, symbol_map);
let export_level = export_level(scx, def_id);
debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
(name, export_level)
})
.collect();
@ -90,9 +92,10 @@ impl ExportedSymbols {
.exported_symbols(cnum)
.iter()
.map(|&def_id| {
debug!("EXTERN-SYMBOL: {:?}", def_id);
let name = Instance::mono(scx, def_id).symbol_name(scx);
(name, export_level(scx, def_id))
let export_level = export_level(scx, def_id);
debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
(name, export_level)
})
.collect();

View File

@ -0,0 +1,33 @@
// Copyright 2016 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="rlib"]
#[inline(never)]
pub fn foo<T>() {
let _: Box<SomeTrait> = Box::new(SomeTraitImpl);
}
pub fn bar() {
SomeTraitImpl.bar();
}
mod submod {
pub trait SomeTrait {
fn bar(&self) {
panic!("NO")
}
}
}
use self::submod::SomeTrait;
pub struct SomeTraitImpl;
impl SomeTrait for SomeTraitImpl {}

View File

@ -0,0 +1,24 @@
// Copyright 2016 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.
// This test makes sure that we don't run into a linker error because of the
// middle::reachable pass missing trait methods with default impls.
// aux-build:issue_38226_aux.rs
// Need -Cno-prepopulate-passes to really disable inlining, otherwise the faulty
// code gets optimized out:
// compile-flags: -Cno-prepopulate-passes
extern crate issue_38226_aux;
fn main() {
issue_38226_aux::foo::<()>();
}