From ef4ec38f455481c27d2f81f389ad3f31e9c390f0 Mon Sep 17 00:00:00 2001 From: Vladimir Pouzanov Date: Mon, 21 Apr 2014 17:49:42 +0100 Subject: [PATCH 1/2] Added support for #[unsafe_override_address] #[unsafe_override_address] static t: T = 123 would be pointing to ((*T)123). The global is not registered in this case. --- src/librustc/middle/trans/base.rs | 111 ++++++++++++++---------- src/librustc/middle/trans/consts.rs | 22 +++-- src/librustc/middle/typeck/check/mod.rs | 18 +++- 3 files changed, 95 insertions(+), 56 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 92a6bb73c8e3a..12e707c29847b 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1851,62 +1851,79 @@ 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, override_reach) = 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, true) + } else { + let (v, i) = consts::const_expr(ccx, expr, is_local); + + (v, i, false) + }; 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 override_reach || !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 override_reach || attr::contains_name(i.attrs.as_slice(), + "address_insignificant") { + if !override_reach && 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); } From 54ed4b38fb818f218d1bc3a207daa914486707a4 Mon Sep 17 00:00:00 2001 From: Vladimir Pouzanov Date: Mon, 21 Apr 2014 18:00:13 +0100 Subject: [PATCH 2/2] Removed unused override_reach --- src/librustc/middle/trans/base.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 12e707c29847b..b2375e640430a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1851,17 +1851,15 @@ 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, override_reach) = if attr::contains_name(i.attrs.as_slice(), + 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, true) + (ptr, true) } else { - let (v, i) = consts::const_expr(ccx, expr, is_local); - - (v, i, false) + consts::const_expr(ccx, expr, is_local) }; ccx.const_values.borrow_mut().insert(id, v); let mut inlineable = inlineable; @@ -1877,15 +1875,15 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { llvm::LLVMAddGlobal(ccx.llmod, llty, buf) }); - if override_reach || !ccx.reachable.contains(&id) { + if !ccx.reachable.contains(&id) { lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage); } // Apply the `unnamed_addr` attribute if // requested - if override_reach || attr::contains_name(i.attrs.as_slice(), + if attr::contains_name(i.attrs.as_slice(), "address_insignificant") { - if !override_reach && ccx.reachable.contains(&id) { + if ccx.reachable.contains(&id) { ccx.sess().span_bug(i.span, "insignificant static is reachable"); }