about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/trans/base.rs27
-rw-r--r--src/librustc/middle/trans/inline.rs8
-rw-r--r--src/test/auxiliary/xcrate_address_insignificant.rs19
-rw-r--r--src/test/run-pass/xcrate-address-insignificant.rs18
4 files changed, 67 insertions, 5 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index b4979c335b5..6f70d2e601d 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -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
                             }
diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs
index a571e56a48e..8900b50b49d 100644
--- a/src/librustc/middle/trans/inline.rs
+++ b/src/librustc/middle/trans/inline.rs
@@ -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);
+                    }
                 }
                 _ => {}
             }
diff --git a/src/test/auxiliary/xcrate_address_insignificant.rs b/src/test/auxiliary/xcrate_address_insignificant.rs
new file mode 100644
index 00000000000..08e3eff0c8c
--- /dev/null
+++ b/src/test/auxiliary/xcrate_address_insignificant.rs
@@ -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>()
+}
diff --git a/src/test/run-pass/xcrate-address-insignificant.rs b/src/test/run-pass/xcrate-address-insignificant.rs
new file mode 100644
index 00000000000..1bf3763834a
--- /dev/null
+++ b/src/test/run-pass/xcrate-address-insignificant.rs
@@ -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());
+}