Skip to content

Commit 6c8b702

Browse files
committed
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.
2 parents 4dded43 + 4ddeef3 commit 6c8b702

File tree

3 files changed

+147
-79
lines changed

3 files changed

+147
-79
lines changed

src/librustc/middle/reachable.rs

+106-77
Original file line numberDiff line numberDiff line change
@@ -260,104 +260,133 @@ impl ReachableContext {
260260
continue
261261
}
262262
scanned.insert(search_item);
263-
self.reachable_symbols.insert(search_item);
264-
265-
// Find the AST block corresponding to the item and visit it,
266-
// marking all path expressions that resolve to something
267-
// interesting.
268263
match self.tcx.items.find(&search_item) {
269-
Some(&ast_map::node_item(item, _)) => {
264+
Some(item) => self.propagate_node(item, search_item,
265+
&mut visitor),
266+
None if search_item == ast::CRATE_NODE_ID => {}
267+
None => {
268+
self.tcx.sess.bug(format!("found unmapped ID in worklist: \
269+
{}",
270+
search_item))
271+
}
272+
}
273+
}
274+
}
275+
276+
fn propagate_node(&self, node: &ast_map::ast_node,
277+
search_item: ast::NodeId,
278+
visitor: &mut MarkSymbolVisitor) {
279+
if !*self.tcx.sess.building_library {
280+
// If we are building an executable, then there's no need to flag
281+
// anything as external except for `extern fn` types. These
282+
// functions may still participate in some form of native interface,
283+
// but all other rust-only interfaces can be private (they will not
284+
// participate in linkage after this product is produced)
285+
match *node {
286+
ast_map::node_item(item, _) => {
270287
match item.node {
271-
ast::item_fn(_, _, _, _, ref search_block) => {
272-
if item_might_be_inlined(item) {
273-
visit::walk_block(&mut visitor, search_block, ())
274-
}
288+
ast::item_fn(_, ast::extern_fn, _, _, _) => {
289+
self.reachable_symbols.insert(search_item);
275290
}
291+
_ => {}
292+
}
293+
}
294+
_ => {}
295+
}
296+
} else {
297+
// If we are building a library, then reachable symbols will
298+
// continue to participate in linkage after this product is
299+
// produced. In this case, we traverse the ast node, recursing on
300+
// all reachable nodes from this one.
301+
self.reachable_symbols.insert(search_item);
302+
}
276303

277-
// Implementations of exported structs/enums need to get
278-
// added to the worklist (as all their methods should be
279-
// accessible)
280-
ast::item_struct(*) | ast::item_enum(*) => {
281-
let def = local_def(item.id);
282-
let impls = match self.tcx.inherent_impls.find(&def) {
283-
Some(&impls) => impls,
284-
None => continue
285-
};
286-
for imp in impls.iter() {
287-
if is_local(imp.did) {
288-
self.worklist.push(imp.did.node);
289-
}
290-
}
304+
match *node {
305+
ast_map::node_item(item, _) => {
306+
match item.node {
307+
ast::item_fn(_, _, _, _, ref search_block) => {
308+
if item_might_be_inlined(item) {
309+
visit::walk_block(visitor, search_block, ())
291310
}
311+
}
292312

293-
// Propagate through this impl
294-
ast::item_impl(_, _, _, ref methods) => {
295-
for method in methods.iter() {
296-
self.worklist.push(method.id);
313+
// Implementations of exported structs/enums need to get
314+
// added to the worklist (as all their methods should be
315+
// accessible)
316+
ast::item_struct(*) | ast::item_enum(*) => {
317+
let def = local_def(item.id);
318+
let impls = match self.tcx.inherent_impls.find(&def) {
319+
Some(&impls) => impls,
320+
None => return
321+
};
322+
for imp in impls.iter() {
323+
if is_local(imp.did) {
324+
self.worklist.push(imp.did.node);
297325
}
298326
}
327+
}
328+
329+
// Propagate through this impl
330+
ast::item_impl(_, _, _, ref methods) => {
331+
for method in methods.iter() {
332+
self.worklist.push(method.id);
333+
}
334+
}
299335

300-
// Default methods of exported traits need to all be
301-
// accessible.
302-
ast::item_trait(_, _, ref methods) => {
303-
for method in methods.iter() {
304-
match *method {
305-
ast::required(*) => {}
306-
ast::provided(ref method) => {
307-
self.worklist.push(method.id);
308-
}
336+
// Default methods of exported traits need to all be
337+
// accessible.
338+
ast::item_trait(_, _, ref methods) => {
339+
for method in methods.iter() {
340+
match *method {
341+
ast::required(*) => {}
342+
ast::provided(ref method) => {
343+
self.worklist.push(method.id);
309344
}
310345
}
311346
}
347+
}
312348

313-
// These are normal, nothing reachable about these
314-
// inherently and their children are already in the
315-
// worklist
316-
ast::item_static(*) | ast::item_ty(*) |
317-
ast::item_mod(*) | ast::item_foreign_mod(*) => {}
349+
// These are normal, nothing reachable about these
350+
// inherently and their children are already in the
351+
// worklist
352+
ast::item_static(*) | ast::item_ty(*) |
353+
ast::item_mod(*) | ast::item_foreign_mod(*) => {}
318354

319-
_ => {
320-
self.tcx.sess.span_bug(item.span,
321-
"found non-function item \
322-
in worklist?!")
323-
}
355+
_ => {
356+
self.tcx.sess.span_bug(item.span,
357+
"found non-function item \
358+
in worklist?!")
324359
}
325360
}
326-
Some(&ast_map::node_trait_method(trait_method, _, _)) => {
327-
match *trait_method {
328-
ast::required(*) => {
329-
// Keep going, nothing to get exported
330-
}
331-
ast::provided(ref method) => {
332-
visit::walk_block(&mut visitor, &method.body, ())
333-
}
361+
}
362+
ast_map::node_trait_method(trait_method, _, _) => {
363+
match *trait_method {
364+
ast::required(*) => {
365+
// Keep going, nothing to get exported
334366
}
335-
}
336-
Some(&ast_map::node_method(method, did, _)) => {
337-
if method_might_be_inlined(self.tcx, method, did) {
338-
visit::walk_block(&mut visitor, &method.body, ())
367+
ast::provided(ref method) => {
368+
visit::walk_block(visitor, &method.body, ())
339369
}
340370
}
341-
// Nothing to recurse on for these
342-
Some(&ast_map::node_foreign_item(*)) |
343-
Some(&ast_map::node_variant(*)) |
344-
Some(&ast_map::node_struct_ctor(*)) => {}
345-
Some(_) => {
346-
let ident_interner = token::get_ident_interner();
347-
let desc = ast_map::node_id_to_str(self.tcx.items,
348-
search_item,
349-
ident_interner);
350-
self.tcx.sess.bug(format!("found unexpected thingy in \
351-
worklist: {}",
352-
desc))
353-
}
354-
None if search_item == ast::CRATE_NODE_ID => {}
355-
None => {
356-
self.tcx.sess.bug(format!("found unmapped ID in worklist: \
357-
{}",
358-
search_item))
371+
}
372+
ast_map::node_method(method, did, _) => {
373+
if method_might_be_inlined(self.tcx, method, did) {
374+
visit::walk_block(visitor, &method.body, ())
359375
}
360376
}
377+
// Nothing to recurse on for these
378+
ast_map::node_foreign_item(*) |
379+
ast_map::node_variant(*) |
380+
ast_map::node_struct_ctor(*) => {}
381+
_ => {
382+
let ident_interner = token::get_ident_interner();
383+
let desc = ast_map::node_id_to_str(self.tcx.items,
384+
search_item,
385+
ident_interner);
386+
self.tcx.sess.bug(format!("found unexpected thingy in \
387+
worklist: {}",
388+
desc))
389+
}
361390
}
362391
}
363392

src/librustc/middle/trans/base.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,7 @@ fn finish_register_fn(ccx: @mut CrateContext, sp: Span, sym: ~str, node_id: ast:
22942294
llfn: ValueRef) {
22952295
ccx.item_symbols.insert(node_id, sym);
22962296

2297-
if !*ccx.sess.building_library {
2297+
if !ccx.reachable.contains(&node_id) {
22982298
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
22992299
}
23002300

@@ -2504,7 +2504,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
25042504
llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
25052505
};
25062506

2507-
if !*ccx.sess.building_library {
2507+
if !ccx.reachable.contains(&id) {
25082508
lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
25092509
}
25102510

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2013 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+
// xfail-fast
12+
// xfail-linux apparently dlsym doesn't work on program symbols?
13+
// xfail-android apparently dlsym doesn't work on program symbols?
14+
// xfail-freebsd apparently dlsym doesn't work on program symbols?
15+
16+
use std::unstable::dynamic_lib::DynamicLibrary;
17+
18+
#[no_mangle] pub extern "C" fn fun1() {}
19+
#[no_mangle] extern "C" fn fun2() {}
20+
21+
mod foo {
22+
#[no_mangle] pub extern "C" fn fun3() {}
23+
}
24+
pub mod bar {
25+
#[no_mangle] pub extern "C" fn fun4() {}
26+
}
27+
28+
#[no_mangle] pub fn fun5() {}
29+
30+
fn main() {
31+
unsafe {
32+
let a = DynamicLibrary::open(None).unwrap();
33+
assert!(a.symbol::<int>("fun1").is_ok());
34+
assert!(a.symbol::<int>("fun2").is_err());
35+
assert!(a.symbol::<int>("fun3").is_err());
36+
assert!(a.symbol::<int>("fun4").is_ok());
37+
assert!(a.symbol::<int>("fun5").is_err());
38+
}
39+
}

0 commit comments

Comments
 (0)