auto merge of #10539 : alexcrichton/rust/external-linkage, r=pcwalton

If a function is marked as external, then it's likely desired for use with some
native library, so we're not really accomplishing a whole lot by internalizing
all of these symbols.
This commit is contained in:
bors 2013-11-18 10:26:49 -08:00
commit 6c8b702cf7
3 changed files with 160 additions and 92 deletions

View file

@ -260,17 +260,53 @@ impl ReachableContext {
continue
}
scanned.insert(search_item);
self.reachable_symbols.insert(search_item);
// Find the AST block corresponding to the item and visit it,
// marking all path expressions that resolve to something
// interesting.
match self.tcx.items.find(&search_item) {
Some(&ast_map::node_item(item, _)) => {
Some(item) => self.propagate_node(item, search_item,
&mut visitor),
None if search_item == ast::CRATE_NODE_ID => {}
None => {
self.tcx.sess.bug(format!("found unmapped ID in worklist: \
{}",
search_item))
}
}
}
}
fn propagate_node(&self, node: &ast_map::ast_node,
search_item: ast::NodeId,
visitor: &mut MarkSymbolVisitor) {
if !*self.tcx.sess.building_library {
// If we are building an executable, then there's no need to flag
// anything as external except for `extern fn` types. These
// functions may still participate in some form of native interface,
// but all other rust-only interfaces can be private (they will not
// participate in linkage after this product is produced)
match *node {
ast_map::node_item(item, _) => {
match item.node {
ast::item_fn(_, ast::extern_fn, _, _, _) => {
self.reachable_symbols.insert(search_item);
}
_ => {}
}
}
_ => {}
}
} else {
// If we are building a library, then reachable symbols will
// continue to participate in linkage after this product is
// produced. In this case, we traverse the ast node, recursing on
// all reachable nodes from this one.
self.reachable_symbols.insert(search_item);
}
match *node {
ast_map::node_item(item, _) => {
match item.node {
ast::item_fn(_, _, _, _, ref search_block) => {
if item_might_be_inlined(item) {
visit::walk_block(&mut visitor, search_block, ())
visit::walk_block(visitor, search_block, ())
}
}
@ -281,7 +317,7 @@ impl ReachableContext {
let def = local_def(item.id);
let impls = match self.tcx.inherent_impls.find(&def) {
Some(&impls) => impls,
None => continue
None => return
};
for imp in impls.iter() {
if is_local(imp.did) {
@ -323,26 +359,26 @@ impl ReachableContext {
}
}
}
Some(&ast_map::node_trait_method(trait_method, _, _)) => {
ast_map::node_trait_method(trait_method, _, _) => {
match *trait_method {
ast::required(*) => {
// Keep going, nothing to get exported
}
ast::provided(ref method) => {
visit::walk_block(&mut visitor, &method.body, ())
visit::walk_block(visitor, &method.body, ())
}
}
}
Some(&ast_map::node_method(method, did, _)) => {
ast_map::node_method(method, did, _) => {
if method_might_be_inlined(self.tcx, method, did) {
visit::walk_block(&mut visitor, &method.body, ())
visit::walk_block(visitor, &method.body, ())
}
}
// Nothing to recurse on for these
Some(&ast_map::node_foreign_item(*)) |
Some(&ast_map::node_variant(*)) |
Some(&ast_map::node_struct_ctor(*)) => {}
Some(_) => {
ast_map::node_foreign_item(*) |
ast_map::node_variant(*) |
ast_map::node_struct_ctor(*) => {}
_ => {
let ident_interner = token::get_ident_interner();
let desc = ast_map::node_id_to_str(self.tcx.items,
search_item,
@ -351,13 +387,6 @@ impl ReachableContext {
worklist: {}",
desc))
}
None if search_item == ast::CRATE_NODE_ID => {}
None => {
self.tcx.sess.bug(format!("found unmapped ID in worklist: \
{}",
search_item))
}
}
}
}

View file

@ -2294,7 +2294,7 @@ fn finish_register_fn(ccx: @mut CrateContext, sp: Span, sym: ~str, node_id: ast:
llfn: ValueRef) {
ccx.item_symbols.insert(node_id, sym);
if !*ccx.sess.building_library {
if !ccx.reachable.contains(&node_id) {
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
}
@ -2504,7 +2504,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
};
if !*ccx.sess.building_library {
if !ccx.reachable.contains(&id) {
lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
}

View file

@ -0,0 +1,39 @@
// Copyright 2013 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.
// xfail-fast
// xfail-linux apparently dlsym doesn't work on program symbols?
// xfail-android apparently dlsym doesn't work on program symbols?
// xfail-freebsd apparently dlsym doesn't work on program symbols?
use std::unstable::dynamic_lib::DynamicLibrary;
#[no_mangle] pub extern "C" fn fun1() {}
#[no_mangle] extern "C" fn fun2() {}
mod foo {
#[no_mangle] pub extern "C" fn fun3() {}
}
pub mod bar {
#[no_mangle] pub extern "C" fn fun4() {}
}
#[no_mangle] pub fn fun5() {}
fn main() {
unsafe {
let a = DynamicLibrary::open(None).unwrap();
assert!(a.symbol::<int>("fun1").is_ok());
assert!(a.symbol::<int>("fun2").is_err());
assert!(a.symbol::<int>("fun3").is_err());
assert!(a.symbol::<int>("fun4").is_ok());
assert!(a.symbol::<int>("fun5").is_err());
}
}