Introduce trans::declare

We provide tools to tell what exact symbols to emit for any fn or static, but
don’t quite check if that won’t cause any issues later on. Some of the issues
include LLVM mangling our names again and our names pointing to wrong locations,
us generating dumb foreign call wrappers, linker errors, extern functions
resolving to different symbols altogether (extern {fn fail();} fail(); in some
cases calling fail1()), etc.

Before the commit we had a function called note_unique_llvm_symbol, so it is
clear somebody was aware of the issue at some point, but the function was barely
used, mostly in irrelevant locations.

Along with working on it I took liberty to start refactoring trans/base into
a few smaller modules. The refactoring is incomplete and I hope I will find some
motivation to carry on with it.

This is possibly a [breaking-change] because it makes dumbly written code
properly invalid.
This commit is contained in:
Simonas Kazlauskas 2015-03-04 01:08:06 +02:00
parent caea044929
commit f1dabed82b
15 changed files with 430 additions and 284 deletions

View File

@ -64,6 +64,7 @@ use trans::context::SharedCrateContext;
use trans::controlflow; use trans::controlflow;
use trans::datum; use trans::datum;
use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
use trans::declare;
use trans::expr; use trans::expr;
use trans::foreign; use trans::foreign;
use trans::glue; use trans::glue;
@ -179,44 +180,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
} }
} }
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
ty: Type, output: ty::FnOutput) -> ValueRef {
let buf = CString::new(name).unwrap();
let llfn: ValueRef = unsafe {
llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
};
// diverging functions may unwind, but can never return normally
if output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
}
if ccx.tcx().sess.opts.cg.no_redzone
.unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute)
}
llvm::SetFunctionCallConv(llfn, cc);
// Function addresses in Rust are never significant, allowing functions to be merged.
llvm::SetUnnamedAddr(llfn, true);
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
attributes::split_stack(llfn, true);
}
llfn
}
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_cdecl_fn(ccx: &CrateContext,
name: &str,
ty: Type,
output: Ty) -> ValueRef {
decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output))
}
fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>, fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
name: &str, did: ast::DefId) -> ValueRef { name: &str, did: ast::DefId) -> ValueRef {
match ccx.externs().borrow().get(name) { match ccx.externs().borrow().get(name) {
@ -224,7 +187,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
None => () None => ()
} }
let f = decl_rust_fn(ccx, fn_ty, name); let f = declare::declare_rust_fn(ccx, name, fn_ty);
let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
attributes::from_fn_attrs(ccx, &attrs[..], f); attributes::from_fn_attrs(ccx, &attrs[..], f);
@ -254,63 +217,6 @@ pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::Closu
*ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap() *ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap()
} }
pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
debug!("decl_rust_fn(fn_ty={}, name={:?})",
fn_ty.repr(ccx.tcx()),
name);
let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);
debug!("decl_rust_fn: fn_ty={} (after normalized associated types)",
fn_ty.repr(ccx.tcx()));
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => {
(&f.sig, f.abi, None)
}
ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = self_type_for_closure(ccx, closure_did, fn_ty);
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
debug!("decl_rust_fn: function_type={} self_type={}",
function_type.repr(ccx.tcx()),
self_type.repr(ccx.tcx()));
(&function_type.sig, RustCall, Some(llenvironment_type))
}
_ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
let sig = ty::Binder(sig);
debug!("decl_rust_fn: sig={} (after erasing regions)",
sig.repr(ccx.tcx()));
let llfty = type_of_rust_fn(ccx, env, &sig, abi);
debug!("decl_rust_fn: llfty={}",
ccx.tn().type_to_string(llfty));
let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */);
let attrs = get_fn_llvm_attributes(ccx, fn_ty);
attrs.apply_llfn(llfn);
// (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above
llfn
}
pub fn decl_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
let llfn = decl_rust_fn(ccx, fn_ty, name);
llvm::SetLinkage(llfn, llvm::InternalLinkage);
llfn
}
pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId, pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
t: Ty<'tcx>) -> ValueRef { t: Ty<'tcx>) -> ValueRef {
let name = csearch::get_symbol(&ccx.sess().cstore, did); let name = csearch::get_symbol(&ccx.sess().cstore, did);
@ -319,23 +225,22 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
Some(n) => return *n, Some(n) => return *n,
None => () None => ()
} }
unsafe { // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
let buf = CString::new(name.clone()).unwrap(); // FIXME(nagisa): investigate whether it can be changed into define_global
let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); let c = declare::declare_global(ccx, &name[..], ty);
// Thread-local statics in some other crate need to *always* be linked // Thread-local statics in some other crate need to *always* be linked
// against in a thread-local fashion, so we need to be sure to apply the // against in a thread-local fashion, so we need to be sure to apply the
// thread-local attribute locally if it was present remotely. If we // thread-local attribute locally if it was present remotely. If we
// don't do this then linker errors can be generated where the linker // don't do this then linker errors can be generated where the linker
// complains that one object files has a thread local version of the // complains that one object files has a thread local version of the
// symbol and another one doesn't. // symbol and another one doesn't.
for attr in &*ty::get_attrs(ccx.tcx(), did) { for attr in &*ty::get_attrs(ccx.tcx(), did) {
if attr.check_name("thread_local") { if attr.check_name("thread_local") {
llvm::set_thread_local(c, true); llvm::set_thread_local(c, true);
}
} }
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
} }
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
} }
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
@ -373,15 +278,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
} }
// Double-check that we never ask LLVM to declare the same symbol twice. It
// silently mangles such symbols, breaking our linkage model.
pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: String) {
if ccx.all_llvm_symbols().borrow().contains(&sym) {
ccx.sess().bug(&format!("duplicate LLVM symbol: {}", sym));
}
ccx.all_llvm_symbols().borrow_mut().insert(sym);
}
pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool) pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool)
-> llvm::IntPredicate { -> llvm::IntPredicate {
match op { match op {
@ -1713,15 +1609,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let fn_ty = ty::node_id_to_type(ccx.tcx(), id); let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty)); let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty));
let abi = ty::ty_fn_abi(fn_ty); let abi = ty::ty_fn_abi(fn_ty);
trans_closure(ccx, trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi,
decl,
body,
llfndecl,
param_substs,
id,
attrs,
output_type,
abi,
closure::ClosureEnv::NotClosure); closure::ClosureEnv::NotClosure);
} }
@ -2066,27 +1954,24 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let llfn = get_item_val(ccx, item.id); let llfn = get_item_val(ccx, item.id);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
if abi != Rust { if abi != Rust {
foreign::trans_rust_fn_with_foreign_abi(ccx, foreign::trans_rust_fn_with_foreign_abi(ccx, &**decl, &**body, &item.attrs,
&**decl, llfn, empty_substs, item.id, None);
&**body,
&item.attrs,
llfn,
empty_substs,
item.id,
None);
} else { } else {
trans_fn(ccx, trans_fn(ccx, &**decl, &**body, llfn, empty_substs, item.id, &item.attrs);
&**decl,
&**body,
llfn,
empty_substs,
item.id,
&item.attrs);
} }
update_linkage(ccx, update_linkage(ccx, llfn, Some(item.id),
llfn,
Some(item.id),
if is_origin { OriginalTranslation } else { InlinedCopy }); if is_origin { OriginalTranslation } else { InlinedCopy });
if is_entry_fn(ccx.sess(), item.id) {
create_entry_wrapper(ccx, item.span, llfn);
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if ty::has_attr(ccx.tcx(), local_def(item.id), "rustc_error") {
ccx.tcx().sess.span_fatal(item.span, "compilation successful");
}
}
} }
} }
@ -2122,8 +2007,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let mut v = TransItemVisitor{ ccx: ccx }; let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(&**expr); v.visit_expr(&**expr);
consts::trans_static(ccx, m, item.id); let g = consts::trans_static(ccx, m, item.id);
let g = get_item_val(ccx, item.id);
update_linkage(ccx, g, Some(item.id), OriginalTranslation); update_linkage(ccx, g, Some(item.id), OriginalTranslation);
// Do static_assert checking. It can't really be done much earlier // Do static_assert checking. It can't really be done much earlier
@ -2175,7 +2059,25 @@ pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) {
} }
} }
fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::NodeId,
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId,
cc: llvm::CallConv,
llfty: Type) -> ValueRef {
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
let llfn = declare::define_fn(ccx, &sym[..], cc, llfty,
ty::FnConverging(ty::mk_nil(ccx.tcx()))).unwrap_or_else(||{
ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
});
finish_register_fn(ccx, sym, node_id, llfn);
llfn
}
fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
llfn: ValueRef) { llfn: ValueRef) {
ccx.item_symbols().borrow_mut().insert(node_id, sym); ccx.item_symbols().borrow_mut().insert(node_id, sym);
@ -2190,19 +2092,6 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N
if ccx.tcx().lang_items.eh_personality() == Some(def) { if ccx.tcx().lang_items.eh_personality() == Some(def) {
llvm::SetLinkage(llfn, llvm::ExternalLinkage); llvm::SetLinkage(llfn, llvm::ExternalLinkage);
} }
if is_entry_fn(ccx.sess(), node_id) {
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if ty::has_attr(ccx.tcx(), local_def(node_id), "rustc_error") {
ccx.tcx().sess.span_fatal(sp, "compilation successful");
}
create_entry_wrapper(ccx, sp, llfn);
}
} }
fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
@ -2221,26 +2110,10 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.sess().span_bug(sp, "expected bare rust function") ccx.sess().span_bug(sp, "expected bare rust function")
} }
let llfn = decl_rust_fn(ccx, node_type, &sym[..]); let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(||{
finish_register_fn(ccx, sp, sym, node_id, llfn); ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
llfn });
} finish_register_fn(ccx, sym, node_id, llfn);
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId,
cc: llvm::CallConv,
llfty: Type) -> ValueRef {
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
let llfn = decl_fn(ccx,
&sym[..],
cc,
llfty,
ty::FnConverging(ty::mk_nil(ccx.tcx())));
finish_register_fn(ccx, sp, sym, node_id, llfn);
llfn llfn
} }
@ -2251,27 +2124,36 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool {
} }
} }
// Create a _rust_main(args: ~[str]) function which will be called from the /// Create the `main` function which will initialise the rust runtime and call users main
// runtime rust_start function /// function.
pub fn create_entry_wrapper(ccx: &CrateContext, pub fn create_entry_wrapper(ccx: &CrateContext,
_sp: Span, _sp: Span,
main_llfn: ValueRef) { main_llfn: ValueRef) {
let et = ccx.sess().entry_type.get().unwrap(); let et = ccx.sess().entry_type.get().unwrap();
match et { match et {
config::EntryMain => { config::EntryMain => {
create_entry_fn(ccx, main_llfn, true); create_entry_fn(ccx, _sp, main_llfn, true);
} }
config::EntryStart => create_entry_fn(ccx, main_llfn, false), config::EntryStart => create_entry_fn(ccx, _sp, main_llfn, false),
config::EntryNone => {} // Do nothing. config::EntryNone => {} // Do nothing.
} }
#[inline(never)]
fn create_entry_fn(ccx: &CrateContext, fn create_entry_fn(ccx: &CrateContext,
_sp: Span,
rust_main: ValueRef, rust_main: ValueRef,
use_start_lang_item: bool) { use_start_lang_item: bool) {
let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()],
&ccx.int_type()); &ccx.int_type());
let llfn = decl_cdecl_fn(ccx, "main", llfty, ty::mk_nil(ccx.tcx())); let llfn = declare::define_cfn(ccx, "main", llfty,
ty::mk_nil(ccx.tcx())).unwrap_or_else(||{
ccx.sess().span_err(_sp, "entry symbol `main` defined multiple times");
// FIXME: We should be smart and show a better diagnostic here.
ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead");
ccx.sess().abort_if_errors();
panic!();
});
// FIXME: #16581: Marking a symbol in the executable with `dllexport` // FIXME: #16581: Marking a symbol in the executable with `dllexport`
// linkage forces MinGW's linker to output a `.reloc` section for ASLR // linkage forces MinGW's linker to output a `.reloc` section for ASLR
@ -2407,14 +2289,15 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
} else { } else {
llvm::LLVMTypeOf(v) llvm::LLVMTypeOf(v)
}; };
if contains_null(&sym[..]) {
ccx.sess().fatal( // FIXME(nagisa): probably should be declare_global, because no definition
&format!("Illegal null byte in export_name \ // is happening here, but we depend on it being defined here from
value: `{}`", sym)); // const::trans_static. This all logic should be replaced.
} let g = declare::define_global(ccx, &sym[..],
let buf = CString::new(sym.clone()).unwrap(); Type::from_ref(llty)).unwrap_or_else(||{
let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, ccx.sess().span_fatal(i.span, &format!("symbol `{}` is already defined",
buf.as_ptr()); sym))
});
if attr::contains_name(&i.attrs, if attr::contains_name(&i.attrs,
"thread_local") { "thread_local") {
@ -2430,10 +2313,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
let llfn = if abi == Rust { let llfn = if abi == Rust {
register_fn(ccx, i.span, sym, i.id, ty) register_fn(ccx, i.span, sym, i.id, ty)
} else { } else {
foreign::register_rust_fn_with_foreign_abi(ccx, foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id)
i.span,
sym,
i.id)
}; };
attributes::from_fn_attrs(ccx, &i.attrs, llfn); attributes::from_fn_attrs(ccx, &i.attrs, llfn);
llfn llfn

View File

@ -41,6 +41,7 @@ use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
use trans::consts; use trans::consts;
use trans::datum::*; use trans::datum::*;
use trans::debuginfo::{DebugLoc, ToDebugLoc}; use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::declare;
use trans::expr; use trans::expr;
use trans::glue; use trans::glue;
use trans::inline; use trans::inline;
@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
// //
let function_name = let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, "fn_pointer_shim");
"fn_pointer_shim"); let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty);
let llfn =
decl_internal_rust_fn(ccx,
tuple_fn_ty,
&function_name[..]);
// //
let empty_substs = tcx.mk_substs(Substs::trans_empty()); let empty_substs = tcx.mk_substs(Substs::trans_empty());

View File

@ -126,6 +126,7 @@ use trans::callee;
use trans::common; use trans::common;
use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
use trans::debuginfo::{DebugLoc, ToDebugLoc}; use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::declare;
use trans::glue; use trans::glue;
use middle::region; use middle::region;
use trans::type_::Type; use trans::type_::Type;
@ -844,10 +845,8 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx
Some(llpersonality) => llpersonality, Some(llpersonality) => llpersonality,
None => { None => {
let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = base::decl_cdecl_fn(self.ccx, let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty,
"rust_eh_personality", self.ccx.tcx().types.i32);
fty,
self.ccx.tcx().types.i32);
*personality = Some(f); *personality = Some(f);
f f
} }

View File

@ -21,6 +21,7 @@ use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
use trans::common::*; use trans::common::*;
use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue};
use trans::debuginfo::{self, DebugLoc}; use trans::debuginfo::{self, DebugLoc};
use trans::declare;
use trans::expr; use trans::expr;
use trans::monomorphize::{self, MonoId}; use trans::monomorphize::{self, MonoId};
use trans::type_of::*; use trans::type_of::*;
@ -162,7 +163,11 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
mangle_internal_name_by_path_and_seq(path, "closure") mangle_internal_name_by_path_and_seq(path, "closure")
}); });
let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); // Currently theres only a single user of get_or_create_declaration_if_closure and it
// unconditionally defines the function, therefore we use define_* here.
let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
});
// set an inline hint for all closures // set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint); attributes::inline(llfn, attributes::InlineAttr::Hint);

View File

@ -31,6 +31,7 @@ use trans::cleanup;
use trans::consts; use trans::consts;
use trans::datum; use trans::datum;
use trans::debuginfo::{self, DebugLoc}; use trans::debuginfo::{self, DebugLoc};
use trans::declare;
use trans::machine; use trans::machine;
use trans::monomorphize; use trans::monomorphize;
use trans::type_::Type; use trans::type_::Type;
@ -872,9 +873,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
!null_terminated as Bool); !null_terminated as Bool);
let gsym = token::gensym("str"); let gsym = token::gensym("str");
let buf = CString::new(format!("str{}", gsym.usize())); let sym = format!("str{}", gsym.usize());
let buf = buf.unwrap(); let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{
let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); cx.sess().bug(&format!("symbol `{}` is already defined", sym));
});
llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetInitializer(g, sc);
llvm::LLVMSetGlobalConstant(g, True); llvm::LLVMSetGlobalConstant(g, True);
llvm::SetLinkage(g, llvm::InternalLinkage); llvm::SetLinkage(g, llvm::InternalLinkage);

View File

@ -25,6 +25,7 @@ use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr};
use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt}; use trans::base::{self, push_ctxt};
use trans::common::*; use trans::common::*;
use trans::declare;
use trans::monomorphize; use trans::monomorphize;
use trans::type_::Type; use trans::type_::Type;
use trans::type_of; use trans::type_of;
@ -35,6 +36,7 @@ use util::ppaux::{Repr, ty_to_string};
use std::iter::repeat; use std::iter::repeat;
use libc::c_uint; use libc::c_uint;
use syntax::{ast, ast_util}; use syntax::{ast, ast_util};
use syntax::parse::token;
use syntax::ptr::P; use syntax::ptr::P;
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
@ -96,13 +98,16 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
fn addr_of_mut(ccx: &CrateContext, fn addr_of_mut(ccx: &CrateContext,
cv: ValueRef, cv: ValueRef,
kind: &str, kind: &str)
id: ast::NodeId)
-> ValueRef { -> ValueRef {
unsafe { unsafe {
let name = format!("{}{}\0", kind, id); // FIXME: this totally needs a better name generation scheme, perhaps a simple global
let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(), // counter? Also most other uses of gensym in trans.
name.as_ptr() as *const _); let gsym = token::gensym("_");
let name = format!("{}{}", kind, gsym.usize());
let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
});
llvm::LLVMSetInitializer(gv, cv); llvm::LLVMSetInitializer(gv, cv);
SetLinkage(gv, InternalLinkage); SetLinkage(gv, InternalLinkage);
SetUnnamedAddr(gv, true); SetUnnamedAddr(gv, true);
@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext,
pub fn addr_of(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext,
cv: ValueRef, cv: ValueRef,
kind: &str, kind: &str)
id: ast::NodeId)
-> ValueRef { -> ValueRef {
match ccx.const_globals().borrow().get(&cv) { match ccx.const_globals().borrow().get(&cv) {
Some(&gv) => return gv, Some(&gv) => return gv,
None => {} None => {}
} }
let gv = addr_of_mut(ccx, cv, kind, id); let gv = addr_of_mut(ccx, cv, kind);
unsafe { unsafe {
llvm::LLVMSetGlobalConstant(gv, True); llvm::LLVMSetGlobalConstant(gv, True);
} }
@ -233,7 +237,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} }
}; };
let lvalue = addr_of(ccx, val, "const", expr.id); let lvalue = addr_of(ccx, val, "const");
ccx.const_values().borrow_mut().insert(key, lvalue); ccx.const_values().borrow_mut().insert(key, lvalue);
lvalue lvalue
} }
@ -284,7 +288,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
if adj.autoderefs == 0 { if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref // Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref). // (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref", e.id); llconst = addr_of(cx, llconst, "autoref");
} else { } else {
// Seeing as we are deref'ing here and take a reference // Seeing as we are deref'ing here and take a reference
// again to make the pointer part of the far pointer below, // again to make the pointer part of the far pointer below,
@ -312,7 +316,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
None => {} None => {}
Some(box ty::AutoUnsafe(_, None)) | Some(box ty::AutoUnsafe(_, None)) |
Some(box ty::AutoPtr(_, _, None)) => { Some(box ty::AutoPtr(_, _, None)) => {
llconst = addr_of(cx, llconst, "autoref", e.id); llconst = addr_of(cx, llconst, "autoref");
} }
Some(box ty::AutoUnsize(ref k)) => { Some(box ty::AutoUnsize(ref k)) => {
let info = let info =
@ -711,12 +715,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// If this isn't the address of a static, then keep going through // If this isn't the address of a static, then keep going through
// normal constant evaluation. // normal constant evaluation.
let (v, _) = const_expr(cx, &**sub, param_substs); let (v, _) = const_expr(cx, &**sub, param_substs);
addr_of(cx, v, "ref", e.id) addr_of(cx, v, "ref")
} }
} }
ast::ExprAddrOf(ast::MutMutable, ref sub) => { ast::ExprAddrOf(ast::MutMutable, ref sub) => {
let (v, _) = const_expr(cx, &**sub, param_substs); let (v, _) = const_expr(cx, &**sub, param_substs);
addr_of_mut(cx, v, "ref_mut_slice", e.id) addr_of_mut(cx, v, "ref_mut_slice")
} }
ast::ExprTup(ref es) => { ast::ExprTup(ref es) => {
let repr = adt::represent_type(cx, ety); let repr = adt::represent_type(cx, ety);
@ -862,7 +866,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
} }
} }
pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> ValueRef {
unsafe { unsafe {
let _icx = push_ctxt("trans_static"); let _icx = push_ctxt("trans_static");
let g = base::get_item_val(ccx, id); let g = base::get_item_val(ccx, id);
@ -888,6 +892,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
} }
} }
debuginfo::create_global_var_metadata(ccx, id, g); debuginfo::create_global_var_metadata(ccx, id, g);
g
} }
} }

View File

@ -20,6 +20,7 @@ use trans::base;
use trans::builder::Builder; use trans::builder::Builder;
use trans::common::{ExternMap,BuilderRef_res}; use trans::common::{ExternMap,BuilderRef_res};
use trans::debuginfo; use trans::debuginfo;
use trans::declare;
use trans::monomorphize::MonoId; use trans::monomorphize::MonoId;
use trans::type_::{Type, TypeNames}; use trans::type_::{Type, TypeNames};
use middle::subst::Substs; use middle::subst::Substs;
@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> {
llsizingtypes: RefCell<FnvHashMap<Ty<'tcx>, Type>>, llsizingtypes: RefCell<FnvHashMap<Ty<'tcx>, Type>>,
adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>, adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>,
type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>, type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>,
all_llvm_symbols: RefCell<FnvHashSet<String>>,
int_type: Type, int_type: Type,
opaque_vec_type: Type, opaque_vec_type: Type,
builder: BuilderRef_res, builder: BuilderRef_res,
@ -413,7 +413,6 @@ impl<'tcx> LocalCrateContext<'tcx> {
llsizingtypes: RefCell::new(FnvHashMap()), llsizingtypes: RefCell::new(FnvHashMap()),
adt_reprs: RefCell::new(FnvHashMap()), adt_reprs: RefCell::new(FnvHashMap()),
type_hashcodes: RefCell::new(FnvHashMap()), type_hashcodes: RefCell::new(FnvHashMap()),
all_llvm_symbols: RefCell::new(FnvHashSet()),
int_type: Type::from_ref(ptr::null_mut()), int_type: Type::from_ref(ptr::null_mut()),
opaque_vec_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()),
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
@ -653,10 +652,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
&self.local.type_hashcodes &self.local.type_hashcodes
} }
pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
&self.local.all_llvm_symbols
}
pub fn stats<'a>(&'a self) -> &'a Stats { pub fn stats<'a>(&'a self) -> &'a Stats {
&self.shared.stats &self.shared.stats
} }
@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
macro_rules! ifn { macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => ( ($name:expr, fn() -> $ret:expr) => (
if *key == $name { if *key == $name {
let f = base::decl_cdecl_fn( let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret),
ccx, $name, Type::func(&[], &$ret), ty::mk_nil(ccx.tcx()));
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone()); ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f); return Some(f);
} }
); );
($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( ($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
if *key == $name { if *key == $name {
let f = base::decl_cdecl_fn(ccx, $name, let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret),
Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx())); ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone()); ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f); return Some(f);
} }
@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
// The `if key == $name` is already in ifn! // The `if key == $name` is already in ifn!
ifn!($name, fn($($arg),*) -> $ret); ifn!($name, fn($($arg),*) -> $ret);
} else if *key == $name { } else if *key == $name {
let f = base::decl_cdecl_fn(ccx, stringify!($cname), let f = declare::declare_cfn(ccx, stringify!($cname),
Type::func(&[$($arg),*], &$ret), Type::func(&[$($arg),*], &$ret),
ty::mk_nil(ccx.tcx())); ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone()); ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f); return Some(f);
} }

View File

@ -417,8 +417,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let filename = C_str_slice(ccx, filename); let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32); let line = C_u32(ccx, loc.line as u32);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false); let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc");
"panic_loc", call_info.id);
let args = vec!(expr_file_line); let args = vec!(expr_file_line);
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem); let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
let bcx = callee::trans_lang_call(bcx, let bcx = callee::trans_lang_call(bcx,
@ -450,8 +449,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let filename = C_str_slice(ccx, filename); let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32); let line = C_u32(ccx, loc.line as u32);
let file_line_const = C_struct(ccx, &[filename, line], false); let file_line_const = C_struct(ccx, &[filename, line], false);
let file_line = consts::addr_of(ccx, file_line_const, let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc");
"panic_bounds_check_loc", call_info.id);
let args = vec!(file_line, index, len); let args = vec!(file_line, index, len);
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
let bcx = callee::trans_lang_call(bcx, let bcx = callee::trans_lang_call(bcx,

View File

@ -196,8 +196,9 @@ use llvm::debuginfo::*;
use metadata::csearch; use metadata::csearch;
use middle::subst::{self, Substs}; use middle::subst::{self, Substs};
use trans::{self, adt, machine, type_of}; use trans::{self, adt, machine, type_of};
use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes,
C_bytes, NormalizingClosureTyper}; NormalizingClosureTyper};
use trans::declare;
use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use trans::monomorphize; use trans::monomorphize;
use trans::type_::Type; use trans::type_::Type;
@ -4071,7 +4072,7 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext)
/// section. /// section.
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
-> llvm::ValueRef { -> llvm::ValueRef {
let section_var_name = b"__rustc_debug_gdb_scripts_section__\0"; let section_var_name = "__rustc_debug_gdb_scripts_section__";
let section_var = unsafe { let section_var = unsafe {
llvm::LLVMGetNamedGlobal(ccx.llmod(), llvm::LLVMGetNamedGlobal(ccx.llmod(),
@ -4085,10 +4086,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
unsafe { unsafe {
let llvm_type = Type::array(&Type::i8(ccx), let llvm_type = Type::array(&Type::i8(ccx),
section_contents.len() as u64); section_contents.len() as u64);
let section_var = llvm::LLVMAddGlobal(ccx.llmod(),
llvm_type.to_ref(), let section_var = declare::define_global(ccx, section_var_name,
section_var_name.as_ptr() llvm_type).unwrap_or_else(||{
as *const _); ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name))
});
llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
llvm::LLVMSetGlobalConstant(section_var, llvm::True); llvm::LLVMSetGlobalConstant(section_var, llvm::True);

View File

@ -0,0 +1,263 @@
// Copyright 2012-2015 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.
//! Declare various LLVM values.
//!
//! Prefer using functions and methods from this module rather than calling LLVM functions
//! directly. These functions do some additional work to ensure we do the right thing given
//! the preconceptions of trans.
//!
//! Some useful guidelines:
//!
//! * Use declare_* family of methods if you are declaring, but are not interested in defining the
//! ValueRef they return.
//! * Use define_* family of methods when you might be defining the ValueRef.
//! * When in doubt, define.
#![allow(dead_code)]
use llvm::{self, ValueRef};
use middle::ty::{self, ClosureTyper};
use syntax::abi;
use trans::attributes;
use trans::base;
use trans::common;
use trans::context::CrateContext;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use util::ppaux::Repr;
use std::ffi::CString;
use libc::c_uint;
/// Declare a global value.
///
/// If theres a value with the same name already declared, the function will return its ValueRef
/// instead.
pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef {
debug!("declare_global(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
unsafe {
llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref())
}
}
/// Declare a function.
///
/// For rust functions use `declare_rust_fn` instead.
///
/// If theres a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type,
output: ty::FnOutput) -> ValueRef {
debug!("declare_fn(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
let llfn = unsafe {
llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref())
};
llvm::SetFunctionCallConv(llfn, callconv);
// Function addresses in Rust are never significant, allowing functions to be merged.
llvm::SetUnnamedAddr(llfn, true);
if output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
}
if ccx.tcx().sess.opts.cg.no_redzone
.unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute)
}
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
attributes::split_stack(llfn, true);
}
llfn
}
/// Declare a C ABI function.
///
/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
/// instead.
///
/// If theres a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef {
declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output))
}
/// Declare a Rust function.
///
/// If theres a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx()));
let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
debug!("declare_rust_fn (after normalised associated types) fn_type={}",
fn_type.repr(ccx.tcx()));
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_type.sty {
ty::ty_bare_fn(_, ref f) => {
(&f.sig, f.abi, None)
}
ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
debug!("declare_rust_fn function_type={} self_type={}",
function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx()));
(&function_type.sig, abi::RustCall, Some(llenvironment_type))
}
_ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig));
debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx()));
let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi);
debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty));
// it is ok to directly access sig.0.output because we erased all late-bound-regions above
let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output);
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
llfn
}
/// Declare a Rust function with internal linkage.
///
/// If theres a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
let llfn = declare_rust_fn(ccx, name, fn_type);
llvm::SetLinkage(llfn, llvm::InternalLinkage);
llfn
}
/// Declare a global with an intention to define it.
///
/// Use this function when you intend to define a global. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_global(ccx, name, ty))
}
}
/// Declare a function with an intention to define it.
///
/// For rust functions use `define_rust_fn` instead.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
output: ty::FnOutput) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_fn(ccx, name, callconv, fn_type, output))
}
}
/// Declare a C ABI function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
///
/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
/// instead.
pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type,
output: ty::Ty) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_cfn(ccx, name, fn_type, output))
}
}
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_rust_fn(ccx, name, fn_type))
}
}
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_internal_rust_fn(ccx, name, fn_type))
}
}
/// Get defined or externally defined (AvailableExternally linkage) value by name.
fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
debug!("get_defined_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) };
if val.is_null() {
debug!("get_defined_value: {:?} value is null", name);
None
} else {
let (declaration, aext_link) = unsafe {
let linkage = llvm::LLVMGetLinkage(val);
(llvm::LLVMIsDeclaration(val) != 0,
linkage == llvm::AvailableExternallyLinkage as c_uint)
};
debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name,
declaration, aext_link);
if !declaration || aext_link {
Some(val)
} else {
None
}
}
}

View File

@ -20,6 +20,7 @@ use trans::build::*;
use trans::cabi; use trans::cabi;
use trans::common::*; use trans::common::*;
use trans::debuginfo::DebugLoc; use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::machine; use trans::machine;
use trans::monomorphize; use trans::monomorphize;
use trans::type_::Type; use trans::type_::Type;
@ -28,7 +29,6 @@ use trans::type_of;
use middle::ty::{self, Ty}; use middle::ty::{self, Ty};
use middle::subst::Substs; use middle::subst::Substs;
use std::ffi::CString;
use std::cmp; use std::cmp;
use libc::c_uint; use libc::c_uint;
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
@ -136,9 +136,7 @@ pub fn register_static(ccx: &CrateContext,
}; };
unsafe { unsafe {
// Declare a symbol `foo` with the desired linkage. // Declare a symbol `foo` with the desired linkage.
let buf = CString::new(ident.as_bytes()).unwrap(); let g1 = declare::declare_global(ccx, &ident[..], llty2);
let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(),
buf.as_ptr());
llvm::SetLinkage(g1, linkage); llvm::SetLinkage(g1, linkage);
// Declare an internal global `extern_with_linkage_foo` which // Declare an internal global `extern_with_linkage_foo` which
@ -149,19 +147,17 @@ pub fn register_static(ccx: &CrateContext,
// zero. // zero.
let mut real_name = "_rust_extern_with_linkage_".to_string(); let mut real_name = "_rust_extern_with_linkage_".to_string();
real_name.push_str(&ident); real_name.push_str(&ident);
let real_name = CString::new(real_name).unwrap(); let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{
let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), ccx.sess().span_fatal(foreign_item.span,
real_name.as_ptr()); &format!("symbol `{}` is already defined", ident))
});
llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::SetLinkage(g2, llvm::InternalLinkage);
llvm::LLVMSetInitializer(g2, g1); llvm::LLVMSetInitializer(g2, g1);
g2 g2
} }
} }
None => unsafe { None => // Generate an external declaration.
// Generate an external declaration. declare::declare_global(ccx, &ident[..], llty),
let buf = CString::new(ident.as_bytes()).unwrap();
llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr())
}
} }
} }
@ -177,7 +173,7 @@ pub fn get_extern_fn(ccx: &CrateContext,
Some(n) => return *n, Some(n) => return *n,
None => {} None => {}
} }
let f = base::decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output));
externs.insert(name.to_string(), f); externs.insert(name.to_string(), f);
f f
} }
@ -534,7 +530,8 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
} }
_ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi") _ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
}; };
let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil(ccx.tcx()))); let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty,
ty::FnConverging(ty::mk_nil(ccx.tcx())));
add_argument_attributes(&tys, llfn); add_argument_attributes(&tys, llfn);
debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})", debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn)); ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
@ -623,7 +620,9 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.tcx().map.path_to_string(id), ccx.tcx().map.path_to_string(id),
id, t.repr(tcx)); id, t.repr(tcx));
let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]); let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", ps));
});
attributes::from_fn_attrs(ccx, attrs, llfn); attributes::from_fn_attrs(ccx, attrs, llfn);
base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
llfn llfn

View File

@ -33,6 +33,7 @@ use trans::common::*;
use trans::consts; use trans::consts;
use trans::datum; use trans::datum;
use trans::debuginfo::DebugLoc; use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr; use trans::expr;
use trans::foreign; use trans::foreign;
use trans::inline; use trans::inline;
@ -184,7 +185,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
// To avoid infinite recursion, don't `make_drop_glue` until after we've // To avoid infinite recursion, don't `make_drop_glue` until after we've
// added the entry to the `drop_glues` cache. // added the entry to the `drop_glues` cache.
if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) { if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) {
let llfn = decl_cdecl_fn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx())); let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx()));
ccx.drop_glues().borrow_mut().insert(t, llfn); ccx.drop_glues().borrow_mut().insert(t, llfn);
return llfn; return llfn;
}; };
@ -294,12 +295,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
did, did,
&[get_drop_glue_type(ccx, t)], &[get_drop_glue_type(ccx, t)],
ty::mk_nil(ccx.tcx())); ty::mk_nil(ccx.tcx()));
foreign::get_extern_fn(ccx, foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv,
&mut *ccx.externs().borrow_mut(), llty, dtor_ty)
&name[..],
llvm::CCallConv,
llty,
dtor_ty)
} }
} }

View File

@ -28,6 +28,7 @@ use trans::common::*;
use trans::consts; use trans::consts;
use trans::datum::*; use trans::datum::*;
use trans::debuginfo::DebugLoc; use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr::SaveIn; use trans::expr::SaveIn;
use trans::expr; use trans::expr;
use trans::glue; use trans::glue;
@ -590,10 +591,10 @@ pub fn trans_object_shim<'a, 'tcx>(
// //
let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty); let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty);
let function_name = let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
let llfn = ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
decl_internal_rust_fn(ccx, shim_fn_ty, &function_name); });
let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig); let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig);
@ -756,8 +757,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
C_uint(ccx, align) C_uint(ccx, align)
].into_iter().chain(methods).collect(); ].into_iter().chain(methods).collect();
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
"vtable", trait_ref.def_id().node);
ccx.vtables().borrow_mut().insert(trait_ref, vtable); ccx.vtables().borrow_mut().insert(trait_ref, vtable);
vtable vtable

View File

@ -43,6 +43,7 @@ mod context;
mod controlflow; mod controlflow;
mod datum; mod datum;
mod debuginfo; mod debuginfo;
mod declare;
mod expr; mod expr;
mod foreign; mod foreign;
mod glue; mod glue;

View File

@ -19,9 +19,10 @@ use middle::traits;
use middle::ty_fold::{TypeFolder, TypeFoldable}; use middle::ty_fold::{TypeFolder, TypeFoldable};
use trans::attributes; use trans::attributes;
use trans::base::{trans_enum_variant, push_ctxt, get_item_val}; use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::{trans_fn, decl_internal_rust_fn}; use trans::base::trans_fn;
use trans::base; use trans::base;
use trans::common::*; use trans::common::*;
use trans::declare;
use trans::foreign; use trans::foreign;
use middle::ty::{self, HasProjectionTypes, Ty}; use middle::ty::{self, HasProjectionTypes, Ty};
use util::ppaux::Repr; use util::ppaux::Repr;
@ -143,7 +144,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let lldecl = if abi != abi::Rust { let lldecl = if abi != abi::Rust {
foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
} else { } else {
decl_internal_rust_fn(ccx, mono_ty, &s[..]) // FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below.
declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", s));
})
}; };
ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl); ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);