diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 9798b2d587d..2c4710f1e45 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -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, } -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, }; diff --git a/src/test/run-pass/auxiliary/issue_38226_aux.rs b/src/test/run-pass/auxiliary/issue_38226_aux.rs new file mode 100644 index 00000000000..d48a9733685 --- /dev/null +++ b/src/test/run-pass/auxiliary/issue_38226_aux.rs @@ -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 or the MIT license +// , 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() { + let _: Box = 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 {} diff --git a/src/test/run-pass/issue-38226.rs b/src/test/run-pass/issue-38226.rs new file mode 100644 index 00000000000..33604212af9 --- /dev/null +++ b/src/test/run-pass/issue-38226.rs @@ -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 or the MIT license +// , 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::<()>(); +}