Skip to content

Commit 368e092

Browse files
committed
Auto merge of rust-lang#38250 - michaelwoerister:trait-methods-in-reachable, r=alexcrichton
Consider provided trait methods in middle::reachable Fixes rust-lang#38226 by also considering trait methods with default implementation instead of just methods provided in an impl. r? @alexcrichton cc @panicbit
2 parents ea79852 + 5d35dfb commit 368e092

File tree

4 files changed

+86
-7
lines changed

4 files changed

+86
-7
lines changed

Diff for: src/librustc/middle/reachable.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -323,19 +323,37 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
323323
// items of non-exported traits (or maybe all local traits?) unless their respective
324324
// trait items are used from inlinable code through method call syntax or UFCS, or their
325325
// trait is a lang item.
326-
struct CollectPrivateImplItemsVisitor<'a> {
326+
struct CollectPrivateImplItemsVisitor<'a, 'tcx: 'a> {
327+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
327328
access_levels: &'a privacy::AccessLevels,
328329
worklist: &'a mut Vec<ast::NodeId>,
329330
}
330331

331-
impl<'a, 'v> ItemLikeVisitor<'v> for CollectPrivateImplItemsVisitor<'a> {
332+
impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, 'tcx> {
332333
fn visit_item(&mut self, item: &hir::Item) {
333334
// We need only trait impls here, not inherent impls, and only non-exported ones
334-
if let hir::ItemImpl(.., Some(_), _, ref impl_item_refs) = item.node {
335+
if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node {
335336
if !self.access_levels.is_reachable(item.id) {
336337
for impl_item_ref in impl_item_refs {
337338
self.worklist.push(impl_item_ref.id.node_id);
338339
}
340+
341+
let trait_def_id = match trait_ref.path.def {
342+
Def::Trait(def_id) => def_id,
343+
_ => unreachable!()
344+
};
345+
346+
if !trait_def_id.is_local() {
347+
return
348+
}
349+
350+
for default_method in self.tcx.provided_trait_methods(trait_def_id) {
351+
let node_id = self.tcx
352+
.map
353+
.as_local_node_id(default_method.def_id)
354+
.unwrap();
355+
self.worklist.push(node_id);
356+
}
339357
}
340358
}
341359
}
@@ -369,6 +387,7 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
369387
}
370388
{
371389
let mut collect_private_impl_items = CollectPrivateImplItemsVisitor {
390+
tcx: tcx,
372391
access_levels: access_levels,
373392
worklist: &mut reachable_context.worklist,
374393
};

Diff for: src/librustc_trans/back/symbol_export.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ impl ExportedSymbols {
5151
scx.tcx().map.local_def_id(node_id)
5252
})
5353
.map(|def_id| {
54-
(symbol_for_def_id(scx, def_id, symbol_map),
55-
export_level(scx, def_id))
54+
let name = symbol_for_def_id(scx, def_id, symbol_map);
55+
let export_level = export_level(scx, def_id);
56+
debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
57+
(name, export_level)
5658
})
5759
.collect();
5860

@@ -90,9 +92,10 @@ impl ExportedSymbols {
9092
.exported_symbols(cnum)
9193
.iter()
9294
.map(|&def_id| {
93-
debug!("EXTERN-SYMBOL: {:?}", def_id);
9495
let name = Instance::mono(scx, def_id).symbol_name(scx);
95-
(name, export_level(scx, def_id))
96+
let export_level = export_level(scx, def_id);
97+
debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
98+
(name, export_level)
9699
})
97100
.collect();
98101

Diff for: src/test/run-pass/auxiliary/issue_38226_aux.rs

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![crate_type="rlib"]
12+
13+
#[inline(never)]
14+
pub fn foo<T>() {
15+
let _: Box<SomeTrait> = Box::new(SomeTraitImpl);
16+
}
17+
18+
pub fn bar() {
19+
SomeTraitImpl.bar();
20+
}
21+
22+
mod submod {
23+
pub trait SomeTrait {
24+
fn bar(&self) {
25+
panic!("NO")
26+
}
27+
}
28+
}
29+
30+
use self::submod::SomeTrait;
31+
32+
pub struct SomeTraitImpl;
33+
impl SomeTrait for SomeTraitImpl {}

Diff for: src/test/run-pass/issue-38226.rs

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// This test makes sure that we don't run into a linker error because of the
12+
// middle::reachable pass missing trait methods with default impls.
13+
14+
// aux-build:issue_38226_aux.rs
15+
16+
// Need -Cno-prepopulate-passes to really disable inlining, otherwise the faulty
17+
// code gets optimized out:
18+
// compile-flags: -Cno-prepopulate-passes
19+
20+
extern crate issue_38226_aux;
21+
22+
fn main() {
23+
issue_38226_aux::foo::<()>();
24+
}

0 commit comments

Comments
 (0)