Skip to content

Commit 9adcbac

Browse files
committed
Prevent a rare linkage issue with an xcrate static
If a static is flagged as address_insignificant, then for LLVM to actually perform the relevant optimization it must have an internal linkage type. What this means, though, is that the static will not be available to other crates. Hence, if you have a generic function with an inner static, it will fail to link when built as a library because other crates will attempt to use the inner static externally. This gets around the issue by inlining the static into the metadata. The same relevant optimization is then applied separately in the external crate. What this ends up meaning is that all statics tagged with #[address_insignificant] will appear at most once per crate (by value), but they could appear in multiple crates. This should be the last blocker for using format! ...
1 parent 72e7c62 commit 9adcbac

File tree

4 files changed

+67
-5
lines changed

4 files changed

+67
-5
lines changed

src/librustc/middle/trans/base.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -2559,10 +2559,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
25592559
// LLVM type is not fully determined by the Rust type.
25602560
let (v, inlineable) = consts::const_expr(ccx, expr);
25612561
ccx.const_values.insert(id, v);
2562-
if !inlineable {
2563-
debug!("%s not inlined", sym);
2564-
ccx.non_inlineable_statics.insert(id);
2565-
}
2562+
let mut inlineable = inlineable;
25662563
exprt = true;
25672564

25682565
unsafe {
@@ -2578,8 +2575,30 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
25782575
lib::llvm::SetUnnamedAddr(g, true);
25792576
lib::llvm::SetLinkage(g,
25802577
lib::llvm::InternalLinkage);
2578+
2579+
// This is a curious case where we must make
2580+
// all of these statics inlineable. If a
2581+
// global is tagged as
2582+
// address_insignificant, then LLVM won't
2583+
// coalesce globals unless they have an
2584+
// internal linkage type. This means that
2585+
// external crates cannot use this global.
2586+
// This is a problem for things like inner
2587+
// statics in generic functions, because the
2588+
// function will be inlined into another
2589+
// crate and then attempt to link to the
2590+
// static in the original crate, only to
2591+
// find that it's not there. On the other
2592+
// side of inlininig, the crates knows to
2593+
// not declare this static as
2594+
// available_externally (because it isn't)
2595+
inlineable = true;
25812596
}
25822597

2598+
if !inlineable {
2599+
debug!("%s not inlined", sym);
2600+
ccx.non_inlineable_statics.insert(id);
2601+
}
25832602
ccx.item_symbols.insert(i.id, sym);
25842603
g
25852604
}

src/librustc/middle/trans/inline.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::vec;
2121
use syntax::ast;
2222
use syntax::ast_map::path_name;
2323
use syntax::ast_util::local_def;
24+
use syntax::attr;
2425

2526
pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
2627
-> ast::DefId {
@@ -68,7 +69,12 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
6869
match item.node {
6970
ast::item_static(*) => {
7071
let g = get_item_val(ccx, item.id);
71-
SetLinkage(g, AvailableExternallyLinkage);
72+
// see the comment in get_item_val() as to why this check is
73+
// performed here.
74+
if !attr::contains_name(item.attrs,
75+
"address_insignificant") {
76+
SetLinkage(g, AvailableExternallyLinkage);
77+
}
7278
}
7379
_ => {}
7480
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
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+
pub fn foo<T>() -> int {
12+
#[address_insignificant]
13+
static a: int = 3;
14+
a
15+
}
16+
17+
pub fn bar() -> int {
18+
foo::<int>()
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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 windows doesn't like aux-build
12+
// aux-build:xcrate_address_insignificant.rs
13+
14+
extern mod foo(name = "xcrate_address_insignificant");
15+
16+
fn main() {
17+
assert_eq!(foo::foo::<float>(), foo::bar());
18+
}

0 commit comments

Comments
 (0)