about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-09-16 23:45:49 -0700
committerbors <bors@rust-lang.org>2013-09-16 23:45:49 -0700
commitd1c05504ba0ec65aac73ebaac82cbac7602d0f87 (patch)
tree02abbe4f94a95845e154e73dade8ef92e3dda6be
parent66ecff2b136dccabae98d2413632ff5177313205 (diff)
parent010702899197b3305126746adb4278d9da370808 (diff)
downloadrust-d1c05504ba0ec65aac73ebaac82cbac7602d0f87.tar.gz
rust-d1c05504ba0ec65aac73ebaac82cbac7602d0f87.zip
auto merge of #9130 : alexcrichton/rust/inline-globals, r=thestinger
In #8185 cross-crate condition handlers were fixed by ensuring that globals
didn't start appearing in different crates with different addressed. An
unfortunate side effect of that pull request is that constants weren't inlined
across crates (uint::bits is unknown to everything but libstd).

This commit fixes this inlining by using the `available_eternally` linkage
provided by LLVM. It partially reverts #8185, and then adds support for this
linkage type. The main caveat is that not all statics could be inlined into
other crates. Before this patch, all statics were considered "inlineable items",
but an unfortunate side effect of how we deal with `&static` and `&[static]`
means that these two cases cannot be inlined across crates. The translation of
constants was modified to propogate this condition of whether a constant
should be considered inlineable into other crates.

Closes #9036
-rw-r--r--src/librustc/metadata/encoder.rs8
-rw-r--r--src/librustc/middle/trans/_match.rs7
-rw-r--r--src/librustc/middle/trans/base.rs24
-rw-r--r--src/librustc/middle/trans/consts.rs121
-rw-r--r--src/librustc/middle/trans/context.rs9
-rw-r--r--src/librustc/middle/trans/expr.rs14
-rw-r--r--src/librustc/middle/trans/inline.rs23
-rw-r--r--src/test/auxiliary/xcrate_static_addresses.rs9
-rw-r--r--src/test/run-pass/xcrate-static-addresses.rs1
9 files changed, 157 insertions, 59 deletions
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index 692e4e345df..9e65e4ec18a 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -60,6 +60,7 @@ pub struct EncodeParams<'self> {
     reexports2: middle::resolve::ExportMap2,
     item_symbols: &'self HashMap<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+    non_inlineable_statics: &'self HashSet<ast::NodeId>,
     link_meta: &'self LinkMeta,
     cstore: @mut cstore::CStore,
     encode_inlined_item: encode_inlined_item<'self>,
@@ -89,6 +90,7 @@ pub struct EncodeContext<'self> {
     reexports2: middle::resolve::ExportMap2,
     item_symbols: &'self HashMap<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
+    non_inlineable_statics: &'self HashSet<ast::NodeId>,
     link_meta: &'self LinkMeta,
     cstore: &'self cstore::CStore,
     encode_inlined_item: encode_inlined_item<'self>,
@@ -907,7 +909,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_name(ecx, ebml_w, item.ident);
         let elt = ast_map::path_pretty_name(item.ident, item.id as u64);
         encode_path(ecx, ebml_w, path, elt);
-        (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+        if !ecx.non_inlineable_statics.contains(&item.id) {
+            (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
+        }
         ebml_w.end_tag();
       }
       item_fn(_, purity, _, ref generics, _) => {
@@ -1728,6 +1732,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         encode_inlined_item,
         link_meta,
         reachable,
+        non_inlineable_statics,
         _
     } = parms;
     let type_abbrevs = @mut HashMap::new();
@@ -1739,6 +1744,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
         reexports2: reexports2,
         item_symbols: item_symbols,
         discrim_symbols: discrim_symbols,
+        non_inlineable_statics: non_inlineable_statics,
         link_meta: link_meta,
         cstore: cstore,
         encode_inlined_item: encode_inlined_item,
diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs
index 62fbdc41b0e..d27bcde2064 100644
--- a/src/librustc/middle/trans/_match.rs
+++ b/src/librustc/middle/trans/_match.rs
@@ -324,15 +324,16 @@ fn trans_opt(bcx: @mut Block, o: &Opt) -> opt_result {
             return single_result(datumblock.to_result(bcx));
         }
         lit(ConstLit(lit_id)) => {
-            let llval = consts::get_const_val(bcx.ccx(), lit_id);
+            let (llval, _) = consts::get_const_val(bcx.ccx(), lit_id);
             return single_result(rslt(bcx, llval));
         }
         var(disr_val, repr) => {
             return adt::trans_case(bcx, repr, disr_val);
         }
         range(l1, l2) => {
-            return range_result(rslt(bcx, consts::const_expr(ccx, l1)),
-                                rslt(bcx, consts::const_expr(ccx, l2)));
+            let (l1, _) = consts::const_expr(ccx, l1);
+            let (l2, _) = consts::const_expr(ccx, l2);
+            return range_result(rslt(bcx, l1), rslt(bcx, l2));
         }
         vec_len(n, vec_len_eq, _) => {
             return single_result(rslt(bcx, C_int(ccx, n as int)));
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index e8c2388a383..5b07e3210b0 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -2541,12 +2541,29 @@ pub fn get_item_val(ccx: @mut CrateContext, id: ast::NodeId) -> ValueRef {
                     let sym = exported_name(ccx, my_path, ty, i.attrs);
 
                     let v = match i.node {
-                        ast::item_static(_, m, expr) => {
+                        ast::item_static(_, _, expr) => {
+                            // If this static came from an external crate, then
+                            // we need to get the symbol from csearch instead of
+                            // using the current crate's name/version
+                            // information in the hash of the symbol
+                            debug!("making %s", sym);
+                            let sym = match ccx.external_srcs.find(&i.id) {
+                                Some(&did) => {
+                                    debug!("but found in other crate...");
+                                    csearch::get_symbol(ccx.sess.cstore, did)
+                                }
+                                None => sym
+                            };
+
                             // We need the translated value here, because for enums the
                             // LLVM type is not fully determined by the Rust type.
-                            let v = consts::const_expr(ccx, expr);
+                            let (v, inlineable) = consts::const_expr(ccx, expr);
                             ccx.const_values.insert(id, v);
-                            exprt = (m == ast::MutMutable || i.vis == ast::public);
+                            if !inlineable {
+                                debug!("%s not inlined", sym);
+                                ccx.non_inlineable_statics.insert(id);
+                            }
+                            exprt = true;
 
                             unsafe {
                                 let llty = llvm::LLVMTypeOf(v);
@@ -2997,6 +3014,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_
             reexports2: cx.exp_map2,
             item_symbols: item_symbols,
             discrim_symbols: discrim_symbols,
+            non_inlineable_statics: &cx.non_inlineable_statics,
             link_meta: link_meta,
             cstore: cx.sess.cstore,
             encode_inlined_item: ie,
diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs
index 78d2228ff04..a7a04627981 100644
--- a/src/librustc/middle/trans/consts.rs
+++ b/src/librustc/middle/trans/consts.rs
@@ -84,21 +84,21 @@ pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef {
 }
 
 pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr])
-    -> (ValueRef, ValueRef, Type) {
+    -> (ValueRef, ValueRef, Type, bool) {
     unsafe {
         let vec_ty = ty::expr_ty(cx.tcx, e);
         let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty);
         let llunitty = type_of::type_of(cx, unit_ty);
         let unit_sz = machine::llsize_of(cx, llunitty);
         let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz);
-        let vs = es.map(|e| const_expr(cx, *e));
+        let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e)));
         // If the vector contains enums, an LLVM array won't work.
         let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
             C_struct(vs)
         } else {
             C_array(llunitty, vs)
         };
-        return (v, sz, llunitty);
+        return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b));
     }
 }
 
@@ -157,7 +157,8 @@ fn const_deref(cx: &mut CrateContext, v: ValueRef, t: ty::t, explicit: bool)
     }
 }
 
-pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef {
+pub fn get_const_val(cx: @mut CrateContext,
+                     mut def_id: ast::DefId) -> (ValueRef, bool) {
     let contains_key = cx.const_values.contains_key(&def_id.node);
     if !ast_util::is_local(def_id) || !contains_key {
         if !ast_util::is_local(def_id) {
@@ -172,11 +173,14 @@ pub fn get_const_val(cx: @mut CrateContext, mut def_id: ast::DefId) -> ValueRef
             _ => cx.tcx.sess.bug("expected a const to be an item")
         }
     }
-    cx.const_values.get_copy(&def_id.node)
+    (cx.const_values.get_copy(&def_id.node),
+     !cx.non_inlineable_statics.contains(&def_id.node))
 }
 
-pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
-    let mut llconst = const_expr_unadjusted(cx, e);
+pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> (ValueRef, bool) {
+    let (llconst, inlineable) = const_expr_unadjusted(cx, e);
+    let mut llconst = llconst;
+    let mut inlineable = inlineable;
     let ety = ty::expr_ty(cx.tcx, e);
     let adjustment = cx.tcx.adjustments.find_copy(&e.id);
     match adjustment {
@@ -204,7 +208,10 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                     // Don't copy data to do a deref+ref.
                     let llptr = match maybe_ptr {
                         Some(ptr) => ptr,
-                        None => const_addr_of(cx, llconst)
+                        None => {
+                            inlineable = false;
+                            const_addr_of(cx, llconst)
+                        }
                     };
                     match *autoref {
                         ty::AutoUnsafe(m) |
@@ -250,17 +257,27 @@ pub fn const_expr(cx: @mut CrateContext, e: @ast::Expr) -> ValueRef {
                          e.repr(cx.tcx), ty_to_str(cx.tcx, ety),
                          csize, tsize));
     }
-    llconst
+    (llconst, inlineable)
 }
 
-fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
+// the bool returned is whether this expression can be inlined into other crates
+// if it's assigned to a static.
+fn const_expr_unadjusted(cx: @mut CrateContext,
+                         e: &ast::Expr) -> (ValueRef, bool) {
+    fn map_list(cx: @mut CrateContext,
+                exprs: &[@ast::Expr]) -> (~[ValueRef], bool) {
+        exprs.iter().map(|&e| const_expr(cx, e))
+             .fold((~[], true), |(L, all_inlineable), (val, inlineable)| {
+                    (vec::append_one(L, val), all_inlineable && inlineable)
+             })
+    }
     unsafe {
         let _icx = push_ctxt("const_expr");
         return match e.node {
-          ast::ExprLit(lit) => consts::const_lit(cx, e, *lit),
+          ast::ExprLit(lit) => (consts::const_lit(cx, e, *lit), true),
           ast::ExprBinary(_, b, e1, e2) => {
-            let te1 = const_expr(cx, e1);
-            let te2 = const_expr(cx, e2);
+            let (te1, _) = const_expr(cx, e1);
+            let (te2, _) = const_expr(cx, e2);
 
             let te2 = base::cast_shift_const_rhs(b, te1, te2);
 
@@ -269,7 +286,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
             let ty = ty::expr_ty(cx.tcx, e1);
             let is_float = ty::type_is_fp(ty);
             let signed = ty::type_is_signed(ty);
-            return match b {
+            return (match b {
               ast::BiAdd   => {
                 if is_float { llvm::LLVMConstFAdd(te1, te2) }
                 else        { llvm::LLVMConstAdd(te1, te2) }
@@ -338,13 +355,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       else      { ConstICmp(IntUGT, te1, te2) }
                   }
               },
-            };
+            }, true)
           },
           ast::ExprUnary(_, u, e) => {
-            let te = const_expr(cx, e);
+            let (te, _) = const_expr(cx, e);
             let ty = ty::expr_ty(cx.tcx, e);
             let is_float = ty::type_is_fp(ty);
-            return match u {
+            return (match u {
               ast::UnBox(_)  |
               ast::UnUniq |
               ast::UnDeref  => {
@@ -367,21 +384,21 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 if is_float { llvm::LLVMConstFNeg(te) }
                 else        { llvm::LLVMConstNeg(te) }
               }
-            }
+            }, true)
           }
           ast::ExprField(base, field, _) => {
               let bt = ty::expr_ty_adjusted(cx.tcx, base);
               let brepr = adt::represent_type(cx, bt);
-              let bv = const_expr(cx, base);
+              let (bv, inlineable) = const_expr(cx, base);
               do expr::with_field_tys(cx.tcx, bt, None) |discr, field_tys| {
                   let ix = ty::field_idx_strict(cx.tcx, field.name, field_tys);
-                  adt::const_get_field(cx, brepr, bv, discr, ix)
+                  (adt::const_get_field(cx, brepr, bv, discr, ix), inlineable)
               }
           }
 
           ast::ExprIndex(_, base, index) => {
               let bt = ty::expr_ty_adjusted(cx.tcx, base);
-              let bv = const_expr(cx, base);
+              let (bv, inlineable) = const_expr(cx, base);
               let iv = match const_eval::eval_const_expr(cx.tcx, index) {
                   const_eval::const_int(i) => i as u64,
                   const_eval::const_uint(u) => u,
@@ -422,15 +439,15 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   cx.sess.span_err(e.span,
                                    "const index-expr is out of bounds");
               }
-              const_get_elt(cx, arr, [iv as c_uint])
+              (const_get_elt(cx, arr, [iv as c_uint]), inlineable)
           }
           ast::ExprCast(base, _) => {
             let ety = ty::expr_ty(cx.tcx, e);
             let llty = type_of::type_of(cx, ety);
             let basety = ty::expr_ty(cx.tcx, base);
-            let v = const_expr(cx, base);
-            match (expr::cast_type_kind(basety),
-                   expr::cast_type_kind(ety)) {
+            let (v, inlineable) = const_expr(cx, base);
+            return (match (expr::cast_type_kind(basety),
+                           expr::cast_type_kind(ety)) {
 
               (expr::cast_integral, expr::cast_integral) => {
                 let s = ty::type_is_signed(basety) as Bool;
@@ -476,17 +493,17 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 cx.sess.impossible_case(e.span,
                                         "bad combination of types for cast")
               }
-            }
+            }, inlineable)
           }
           ast::ExprAddrOf(ast::MutImmutable, sub) => {
-              let e = const_expr(cx, sub);
-              const_addr_of(cx, e)
+              let (e, _) = const_expr(cx, sub);
+              (const_addr_of(cx, e), false)
           }
           ast::ExprTup(ref es) => {
               let ety = ty::expr_ty(cx.tcx, e);
               let repr = adt::represent_type(cx, ety);
-              let vals = es.map(|&e| const_expr(cx, e));
-              adt::trans_const(cx, repr, 0, vals)
+              let (vals, inlineable) = map_list(cx, *es);
+              (adt::trans_const(cx, repr, 0, vals), inlineable)
           }
           ast::ExprStruct(_, ref fs, ref base_opt) => {
               let ety = ty::expr_ty(cx.tcx, e);
@@ -500,24 +517,29 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
 
               do expr::with_field_tys(tcx, ety, Some(e.id))
                   |discr, field_tys| {
-                  let cs: ~[ValueRef] = field_tys.iter().enumerate()
+                  let cs = field_tys.iter().enumerate()
                       .map(|(ix, &field_ty)| {
                       match fs.iter().find(|f| field_ty.ident.name == f.ident.name) {
                           Some(f) => const_expr(cx, (*f).expr),
                           None => {
                               match base_val {
-                                Some(bv) => adt::const_get_field(cx, repr, bv, discr, ix),
+                                Some((bv, inlineable)) => {
+                                    (adt::const_get_field(cx, repr, bv, discr, ix),
+                                     inlineable)
+                                }
                                 None => cx.tcx.sess.span_bug(e.span, "missing struct field")
                               }
                           }
                       }
-                  }).collect();
-                  adt::trans_const(cx, repr, discr, cs)
+                  }).to_owned_vec();
+                  let (cs, inlineable) = vec::unzip(cs.move_iter());
+                  (adt::trans_const(cx, repr, discr, cs),
+                   inlineable.iter().fold(true, |a, &b| a && b))
               }
           }
           ast::ExprVec(ref es, ast::MutImmutable) => {
-            let (v, _, _) = const_vec(cx, e, *es);
-            v
+            let (v, _, _, inlineable) = const_vec(cx, e, *es);
+            (v, inlineable)
           }
           ast::ExprVstore(sub, ast::ExprVstoreSlice) => {
             match sub.node {
@@ -528,7 +550,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 }
               }
               ast::ExprVec(ref es, ast::MutImmutable) => {
-                let (cv, sz, llunitty) = const_vec(cx, e, *es);
+                let (cv, sz, llunitty, _) = const_vec(cx, e, *es);
                 let llty = val_ty(cv);
                 let gv = do "const".with_c_str |name| {
                     llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
@@ -537,7 +559,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 llvm::LLVMSetGlobalConstant(gv, True);
                 SetLinkage(gv, PrivateLinkage);
                 let p = const_ptrcast(cx, gv, llunitty);
-                C_struct([p, sz])
+                (C_struct([p, sz]), false)
               }
               _ => cx.sess.span_bug(e.span, "bad const-slice expr")
             }
@@ -551,13 +573,13 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 const_eval::const_uint(i) => i as uint,
                 _ => cx.sess.span_bug(count.span, "count must be integral const expression.")
             };
-            let vs = vec::from_elem(n, const_expr(cx, elem));
+            let vs = vec::from_elem(n, const_expr(cx, elem).first());
             let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
                 C_struct(vs)
             } else {
                 C_array(llunitty, vs)
             };
-            v
+            (v, true)
           }
           ast::ExprPath(ref pth) => {
             // Assert that there are no type parameters in this path.
@@ -568,10 +590,10 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                 Some(&ast::DefFn(def_id, _purity)) => {
                     if !ast_util::is_local(def_id) {
                         let ty = csearch::get_type(cx.tcx, def_id).ty;
-                        base::trans_external_path(cx, def_id, ty)
+                        (base::trans_external_path(cx, def_id, ty), true)
                     } else {
                         assert!(ast_util::is_local(def_id));
-                        base::get_item_val(cx, def_id.node)
+                        (base::get_item_val(cx, def_id.node), true)
                     }
                 }
                 Some(&ast::DefStatic(def_id, false)) => {
@@ -583,12 +605,12 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                     let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                          enum_did,
                                                          variant_did);
-                    adt::trans_const(cx, repr, vinfo.disr_val, [])
+                    (adt::trans_const(cx, repr, vinfo.disr_val, []), true)
                 }
                 Some(&ast::DefStruct(_)) => {
                     let ety = ty::expr_ty(cx.tcx, e);
                     let llty = type_of::type_of(cx, ety);
-                    C_null(llty)
+                    (C_null(llty), true)
                 }
                 _ => {
                     cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def")
@@ -601,8 +623,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                   Some(&ast::DefStruct(_)) => {
                       let ety = ty::expr_ty(cx.tcx, e);
                       let repr = adt::represent_type(cx, ety);
-                      let arg_vals = args.map(|a| const_expr(cx, *a));
-                      adt::trans_const(cx, repr, 0, arg_vals)
+                      let (arg_vals, inlineable) = map_list(cx, *args);
+                      (adt::trans_const(cx, repr, 0, arg_vals), inlineable)
                   }
                   Some(&ast::DefVariant(enum_did, variant_did, _)) => {
                       let ety = ty::expr_ty(cx.tcx, e);
@@ -610,13 +632,14 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::Expr) -> ValueRef {
                       let vinfo = ty::enum_variant_with_id(cx.tcx,
                                                            enum_did,
                                                            variant_did);
-                      let arg_vals = args.map(|a| const_expr(cx, *a));
-                      adt::trans_const(cx, repr, vinfo.disr_val, arg_vals)
+                      let (arg_vals, inlineable) = map_list(cx, *args);
+                      (adt::trans_const(cx, repr, vinfo.disr_val, arg_vals),
+                       inlineable)
                   }
                   _ => cx.sess.span_bug(e.span, "expected a struct or variant def")
               }
           }
-          ast::ExprParen(e) => { return const_expr(cx, e); }
+          ast::ExprParen(e) => { const_expr(cx, e) }
           _ => cx.sess.span_bug(e.span,
                   "bad constant expression type in consts::const_expr")
         };
diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs
index 6eb2fcf25fd..9ee7f09253b 100644
--- a/src/librustc/middle/trans/context.rs
+++ b/src/librustc/middle/trans/context.rs
@@ -61,6 +61,13 @@ pub struct CrateContext {
      finished_tydescs: bool,
      // Track mapping of external ids to local items imported for inlining
      external: HashMap<ast::DefId, Option<ast::NodeId>>,
+     // Backwards version of the `external` map (inlined items to where they
+     // came from)
+     external_srcs: HashMap<ast::NodeId, ast::DefId>,
+     // A set of static items which cannot be inlined into other crates. This
+     // will pevent in ii_item() structures from being encoded into the metadata
+     // that is generated
+     non_inlineable_statics: HashSet<ast::NodeId>,
      // Cache instances of monomorphized functions
      monomorphized: HashMap<mono_id, ValueRef>,
      monomorphizing: HashMap<ast::DefId, uint>,
@@ -189,6 +196,8 @@ impl CrateContext {
                   tydescs: HashMap::new(),
                   finished_tydescs: false,
                   external: HashMap::new(),
+                  external_srcs: HashMap::new(),
+                  non_inlineable_statics: HashSet::new(),
                   monomorphized: HashMap::new(),
                   monomorphizing: HashMap::new(),
                   type_use_cache: HashMap::new(),
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index b351fe91e6f..0a557869758 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -116,7 +116,7 @@ return type, such as `while` loops or assignments (`a = b`).
 
 use back::abi;
 use back::link;
-use lib::llvm::{ValueRef, llvm, SetLinkage, ExternalLinkage, False};
+use lib::llvm::{ValueRef, llvm, SetLinkage, False};
 use lib;
 use metadata::csearch;
 use middle::trans::_match;
@@ -135,6 +135,7 @@ use middle::trans::datum::*;
 use middle::trans::debuginfo;
 use middle::trans::machine;
 use middle::trans::meth;
+use middle::trans::inline;
 use middle::trans::tvec;
 use middle::trans::type_of;
 use middle::ty::struct_fields;
@@ -987,6 +988,15 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
             ast::DefStatic(did, _) => {
                 let const_ty = expr_ty(bcx, ref_expr);
 
+                fn get_did(ccx: @mut CrateContext, did: ast::DefId)
+                    -> ast::DefId {
+                    if did.crate != ast::LOCAL_CRATE {
+                        inline::maybe_instantiate_inline(ccx, did)
+                    } else {
+                        did
+                    }
+                }
+
                 fn get_val(bcx: @mut Block, did: ast::DefId, const_ty: ty::t)
                            -> ValueRef {
                     // For external constants, we don't inline.
@@ -1018,7 +1028,6 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
                                                     llty.to_ref(),
                                                     buf)
                             };
-                            SetLinkage(llval, ExternalLinkage);
                             let extern_const_values = &mut bcx.ccx().extern_const_values;
                             extern_const_values.insert(did, llval);
                             llval
@@ -1026,6 +1035,7 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: @ast::Expr) -> DatumBlock {
                     }
                 }
 
+                let did = get_did(bcx.ccx(), did);
                 let val = get_val(bcx, did, const_ty);
                 DatumBlock {
                     bcx: bcx,
diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs
index cfc9c8a2e17..a571e56a48e 100644
--- a/src/librustc/middle/trans/inline.rs
+++ b/src/librustc/middle/trans/inline.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
+use lib::llvm::{AvailableExternallyLinkage, SetLinkage};
 use metadata::csearch;
 use middle::astencode;
 use middle::trans::base::{push_ctxt, impl_self, no_self};
@@ -53,16 +53,36 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         }
         csearch::found(ast::ii_item(item)) => {
             ccx.external.insert(fn_id, Some(item.id));
+            ccx.external_srcs.insert(item.id, fn_id);
             ccx.stats.n_inlines += 1;
             trans_item(ccx, item);
+
+            // We're bringing an external global into this crate, but we don't
+            // want to create two copies of the global. If we do this, then if
+            // you take the address of the global in two separate crates you get
+            // two different addresses. This is bad for things like conditions,
+            // but it could possibly have other adverse side effects. We still
+            // want to achieve the optimizations related to this global,
+            // however, so we use the available_externally linkage which llvm
+            // provides
+            match item.node {
+                ast::item_static(*) => {
+                    let g = get_item_val(ccx, item.id);
+                    SetLinkage(g, AvailableExternallyLinkage);
+                }
+                _ => {}
+            }
+
             local_def(item.id)
         }
         csearch::found(ast::ii_foreign(item)) => {
           ccx.external.insert(fn_id, Some(item.id));
+          ccx.external_srcs.insert(item.id, fn_id);
           local_def(item.id)
         }
         csearch::found_parent(parent_id, ast::ii_item(item)) => {
           ccx.external.insert(parent_id, Some(item.id));
+          ccx.external_srcs.insert(item.id, parent_id);
           let mut my_id = 0;
           match item.node {
             ast::item_enum(_, _) => {
@@ -86,6 +106,7 @@ pub fn maybe_instantiate_inline(ccx: @mut CrateContext, fn_id: ast::DefId)
         csearch::found(ast::ii_method(impl_did, is_provided, mth)) => {
           ccx.stats.n_inlines += 1;
           ccx.external.insert(fn_id, Some(mth.id));
+          ccx.external_srcs.insert(mth.id, fn_id);
           // If this is a default method, we can't look up the
           // impl type. But we aren't going to translate anyways, so don't.
           if is_provided { return local_def(mth.id); }
diff --git a/src/test/auxiliary/xcrate_static_addresses.rs b/src/test/auxiliary/xcrate_static_addresses.rs
index 3a05462d856..f0df2b1e71e 100644
--- a/src/test/auxiliary/xcrate_static_addresses.rs
+++ b/src/test/auxiliary/xcrate_static_addresses.rs
@@ -10,12 +10,21 @@
 
 pub static global: int = 3;
 
+static global0: int = 4;
+pub static global2: &'static int = &global0;
+
 pub fn verify_same(a: &'static int) {
     let a = a as *int as uint;
     let b = &global as *int as uint;
     assert_eq!(a, b);
 }
 
+pub fn verify_same2(a: &'static int) {
+    let a = a as *int as uint;
+    let b = global2 as *int as uint;
+    assert_eq!(a, b);
+}
+
 condition!{ pub test: int -> (); }
 
 pub fn raise() {
diff --git a/src/test/run-pass/xcrate-static-addresses.rs b/src/test/run-pass/xcrate-static-addresses.rs
index 059a6f75ac8..7eb4adfd067 100644
--- a/src/test/run-pass/xcrate-static-addresses.rs
+++ b/src/test/run-pass/xcrate-static-addresses.rs
@@ -17,6 +17,7 @@ use other = xcrate_static_addresses;
 
 pub fn main() {
     other::verify_same(&other::global);
+    other::verify_same2(other::global2);
 
     // Previously this fail'd because there were two addresses that were being
     // used when declaring constants.