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! ...
This commit is contained in:
Alex Crichton 2013-09-17 11:24:05 -07:00
parent 72e7c62ec4
commit 9adcbac30d
4 changed files with 67 additions and 5 deletions

View File

@ -2559,10 +2559,7 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
// LLVM type is not fully determined by the Rust type.
let (v, inlineable) = consts::const_expr(ccx, expr);
ccx.const_values.insert(id, v);
if !inlineable {
debug!("%s not inlined", sym);
ccx.non_inlineable_statics.insert(id);
}
let mut inlineable = inlineable;
exprt = true;
unsafe {
@ -2578,8 +2575,30 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
lib::llvm::SetUnnamedAddr(g, true);
lib::llvm::SetLinkage(g,
lib::llvm::InternalLinkage);
// This is a curious case where we must make
// all of these statics inlineable. If a
// global is tagged as
// address_insignificant, then LLVM won't
// coalesce globals unless they have an
// internal linkage type. This means that
// external crates cannot use this global.
// This is a problem for things like inner
// statics in generic functions, because the
// function will be inlined into another
// crate and then attempt to link to the
// static in the original crate, only to
// find that it's not there. On the other
// side of inlininig, the crates knows to
// not declare this static as
// available_externally (because it isn't)
inlineable = true;
}
if !inlineable {
debug!("%s not inlined", sym);
ccx.non_inlineable_statics.insert(id);
}
ccx.item_symbols.insert(i.id, sym);
g
}

View File

@ -21,6 +21,7 @@ use std::vec;
use syntax::ast;
use syntax::ast_map::path_name;
use syntax::ast_util::local_def;
use syntax::attr;
pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
-> ast::DefId {
@ -68,7 +69,12 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
match item.node {
ast::item_static(*) => {
let g = get_item_val(ccx, item.id);
SetLinkage(g, AvailableExternallyLinkage);
// see the comment in get_item_val() as to why this check is
// performed here.
if !attr::contains_name(item.attrs,
"address_insignificant") {
SetLinkage(g, AvailableExternallyLinkage);
}
}
_ => {}
}

View File

@ -0,0 +1,19 @@
// 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.
pub fn foo<T>() -> int {
#[address_insignificant]
static a: int = 3;
a
}
pub fn bar() -> int {
foo::<int>()
}

View File

@ -0,0 +1,18 @@
// 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 windows doesn't like aux-build
// aux-build:xcrate_address_insignificant.rs
extern mod foo(name = "xcrate_address_insignificant");
fn main() {
assert_eq!(foo::foo::<float>(), foo::bar());
}