diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 92a6bb73c8e3a..b2375e640430a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1851,62 +1851,77 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. - let (v, inlineable) = consts::const_expr(ccx, expr, is_local); + let (v, inlineable) = if attr::contains_name(i.attrs.as_slice(), + "unsafe_override_address") { + let (addrconst, _) = consts::const_expr(ccx, expr, is_local); + let llptrty = type_of(ccx, ty).ptr_to().to_ref(); + let ptr = unsafe { llvm::LLVMConstIntToPtr(addrconst, llptrty) }; + + (ptr, true) + } else { + consts::const_expr(ccx, expr, is_local) + }; ccx.const_values.borrow_mut().insert(id, v); let mut inlineable = inlineable; - unsafe { - let llty = llvm::LLVMTypeOf(v); - let g = sym.with_c_str(|buf| { - llvm::LLVMAddGlobal(ccx.llmod, llty, buf) - }); + if attr::contains_name(i.attrs.as_slice(), "unsafe_override_address") { + ccx.item_symbols.borrow_mut().insert(i.id, sym); + foreign = true; + v + } else { + unsafe { + let llty = llvm::LLVMTypeOf(v); + let g = sym.with_c_str(|buf| { + llvm::LLVMAddGlobal(ccx.llmod, llty, buf) + }); + + if !ccx.reachable.contains(&id) { + lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage); + } - if !ccx.reachable.contains(&id) { - lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage); - } + // Apply the `unnamed_addr` attribute if + // requested + if attr::contains_name(i.attrs.as_slice(), + "address_insignificant") { + if ccx.reachable.contains(&id) { + ccx.sess().span_bug(i.span, + "insignificant static is reachable"); + } + lib::llvm::SetUnnamedAddr(g, true); + + // 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; + } - // Apply the `unnamed_addr` attribute if - // requested - if attr::contains_name(i.attrs.as_slice(), - "address_insignificant") { - if ccx.reachable.contains(&id) { - ccx.sess().span_bug(i.span, - "insignificant static is reachable"); + if attr::contains_name(i.attrs.as_slice(), + "thread_local") { + lib::llvm::set_thread_local(g, true); } - lib::llvm::SetUnnamedAddr(g, true); - - // 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 attr::contains_name(i.attrs.as_slice(), - "thread_local") { - lib::llvm::set_thread_local(g, true); - } + if !inlineable { + debug!("{} not inlined", sym); + ccx.non_inlineable_statics.borrow_mut() + .insert(id); + } - if !inlineable { - debug!("{} not inlined", sym); - ccx.non_inlineable_statics.borrow_mut() - .insert(id); + ccx.item_symbols.borrow_mut().insert(i.id, sym); + g } - - ccx.item_symbols.borrow_mut().insert(i.id, sym); - g } } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 8848feb888904..4c18e824f08c6 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -36,7 +36,8 @@ use std::c_str::ToCStr; use std::slice; use std::vec::Vec; use libc::c_uint; -use syntax::{ast, ast_util}; +use syntax::{ast, ast_util, ast_map, attr}; + pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: ast::Lit) -> ValueRef { @@ -683,13 +684,22 @@ pub fn trans_const(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { unsafe { let _icx = push_ctxt("trans_const"); let g = base::get_item_val(ccx, id); + let item = ccx.tcx.map.get(id); + let isglobal = match item { + ast_map::NodeItem(i) => + if attr::contains_name(i.attrs.as_slice(), + "unsafe_override_address") {false} else {true}, + _ => true, + }; // At this point, get_item_val has already translated the // constant's initializer to determine its LLVM type. - let v = ccx.const_values.borrow().get_copy(&id); - llvm::LLVMSetInitializer(g, v); - if m != ast::MutMutable { - llvm::LLVMSetGlobalConstant(g, True); + if isglobal { + let v = ccx.const_values.borrow().get_copy(&id); + llvm::LLVMSetInitializer(g, v); + if m != ast::MutMutable { + llvm::LLVMSetGlobalConstant(g, True); + } + debuginfo::create_global_var_metadata(ccx, id, g); } - debuginfo::create_global_var_metadata(ccx, id, g); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index fb470cbdfb1ab..ec37a6c432b6c 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -585,7 +585,15 @@ pub fn check_item(ccx: &CrateCtxt, it: &ast::Item) { let _indenter = indenter(); match it.node { - ast::ItemStatic(_, _, e) => check_const(ccx, it.span, e, it.id), + ast::ItemStatic(_, _, e) => { + // override type to uint if it's unsafe_override_address, to make things + // like static t: T = 123 work. + if attr::contains_name(it.attrs.as_slice(), "unsafe_override_address") { + check_const(ccx, it.span, e, it.id, Some(ty::mk_u32())); + } else { + check_const(ccx, it.span, e, it.id, None); + } + } ast::ItemEnum(ref enum_definition, _) => { check_enum_variants(ccx, it.span, @@ -3407,11 +3415,15 @@ pub fn check_block_with_expected(fcx: &FnCtxt, pub fn check_const(ccx: &CrateCtxt, sp: Span, e: &ast::Expr, - id: ast::NodeId) { + id: ast::NodeId, + override_ty: Option) { let inh = blank_inherited_fields(ccx); let rty = ty::node_id_to_type(ccx.tcx, id); let fcx = blank_fn_ctxt(ccx, &inh, rty, e.id); - let declty = fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty; + let declty = match override_ty { + Some(t) => t, + None => fcx.ccx.tcx.tcache.borrow().get(&local_def(id)).ty, + }; check_const_with_ty(&fcx, sp, e, declty); }