From f1dabed82bfed643fbbfc93203473e384c58d20a Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Wed, 4 Mar 2015 01:08:06 +0200 Subject: [PATCH] Introduce trans::declare MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- src/librustc_trans/trans/base.rs | 280 +++++++---------------- src/librustc_trans/trans/callee.rs | 11 +- src/librustc_trans/trans/cleanup.rs | 7 +- src/librustc_trans/trans/closure.rs | 7 +- src/librustc_trans/trans/common.rs | 8 +- src/librustc_trans/trans/consts.rs | 33 +-- src/librustc_trans/trans/context.rs | 22 +- src/librustc_trans/trans/controlflow.rs | 6 +- src/librustc_trans/trans/debuginfo.rs | 16 +- src/librustc_trans/trans/declare.rs | 263 +++++++++++++++++++++ src/librustc_trans/trans/foreign.rs | 29 ++- src/librustc_trans/trans/glue.rs | 11 +- src/librustc_trans/trans/meth.rs | 12 +- src/librustc_trans/trans/mod.rs | 1 + src/librustc_trans/trans/monomorphize.rs | 8 +- 15 files changed, 430 insertions(+), 284 deletions(-) create mode 100644 src/librustc_trans/trans/declare.rs diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index a1fa4e77a13..c7200fc8bb2 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -64,6 +64,7 @@ use trans::controlflow; use trans::datum; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::foreign; use trans::glue; @@ -179,44 +180,6 @@ fn drop(&mut self) { } } -// 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>, name: &str, did: ast::DefId) -> ValueRef { 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 => () } - 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); 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() } -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, t: Ty<'tcx>) -> ValueRef { 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, None => () } - unsafe { - let buf = CString::new(name.clone()).unwrap(); - let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr()); - // 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 - // thread-local attribute locally if it was present remotely. If we - // 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 - // symbol and another one doesn't. - for attr in &*ty::get_attrs(ccx.tcx(), did) { - if attr.check_name("thread_local") { - llvm::set_thread_local(c, true); - } + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + // FIXME(nagisa): investigate whether it can be changed into define_global + let c = declare::declare_global(ccx, &name[..], ty); + // 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 + // thread-local attribute locally if it was present remotely. If we + // 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 + // symbol and another one doesn't. + for attr in &*ty::get_attrs(ccx.tcx(), did) { + if attr.check_name("thread_local") { + 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>, @@ -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) -> llvm::IntPredicate { 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 output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty)); let abi = ty::ty_fn_abi(fn_ty); - trans_closure(ccx, - decl, - body, - llfndecl, - param_substs, - id, - attrs, - output_type, - abi, + trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi, 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 empty_substs = ccx.tcx().mk_substs(Substs::trans_empty()); if abi != Rust { - foreign::trans_rust_fn_with_foreign_abi(ccx, - &**decl, - &**body, - &item.attrs, - llfn, - empty_substs, - item.id, - None); + foreign::trans_rust_fn_with_foreign_abi(ccx, &**decl, &**body, &item.attrs, + llfn, empty_substs, item.id, None); } else { - trans_fn(ccx, - &**decl, - &**body, - llfn, - empty_substs, - item.id, - &item.attrs); + trans_fn(ccx, &**decl, &**body, llfn, empty_substs, item.id, &item.attrs); } - update_linkage(ccx, - llfn, - Some(item.id), + update_linkage(ccx, llfn, Some(item.id), 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 }; v.visit_expr(&**expr); - consts::trans_static(ccx, m, item.id); - let g = get_item_val(ccx, item.id); + let g = consts::trans_static(ccx, m, item.id); update_linkage(ccx, g, Some(item.id), OriginalTranslation); // 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) { 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) { 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>, @@ -2221,26 +2110,10 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().span_bug(sp, "expected bare rust function") } - let llfn = decl_rust_fn(ccx, node_type, &sym[..]); - finish_register_fn(ccx, sp, sym, node_id, llfn); - 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); + let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(||{ + ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym)); + }); + finish_register_fn(ccx, sym, node_id, 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 -// runtime rust_start function +/// Create the `main` function which will initialise the rust runtime and call users’ main +/// function. pub fn create_entry_wrapper(ccx: &CrateContext, _sp: Span, main_llfn: ValueRef) { let et = ccx.sess().entry_type.get().unwrap(); match et { 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. } + #[inline(never)] fn create_entry_fn(ccx: &CrateContext, + _sp: Span, rust_main: ValueRef, use_start_lang_item: bool) { let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()], &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` // 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 { llvm::LLVMTypeOf(v) }; - if contains_null(&sym[..]) { - ccx.sess().fatal( - &format!("Illegal null byte in export_name \ - value: `{}`", sym)); - } - let buf = CString::new(sym.clone()).unwrap(); - let g = llvm::LLVMAddGlobal(ccx.llmod(), llty, - buf.as_ptr()); + + // FIXME(nagisa): probably should be declare_global, because no definition + // is happening here, but we depend on it being defined here from + // const::trans_static. This all logic should be replaced. + let g = declare::define_global(ccx, &sym[..], + Type::from_ref(llty)).unwrap_or_else(||{ + ccx.sess().span_fatal(i.span, &format!("symbol `{}` is already defined", + sym)) + }); if attr::contains_name(&i.attrs, "thread_local") { @@ -2430,10 +2313,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let llfn = if abi == Rust { register_fn(ccx, i.span, sym, i.id, ty) } else { - foreign::register_rust_fn_with_foreign_abi(ccx, - i.span, - sym, - i.id) + foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id) }; attributes::from_fn_attrs(ccx, &i.attrs, llfn); llfn diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 9eb46d3ff54..604f185f396 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -41,6 +41,7 @@ use trans::consts; use trans::datum::*; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::glue; use trans::inline; @@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); - let llfn = - decl_internal_rust_fn(ccx, - tuple_fn_ty, - &function_name[..]); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, + "fn_pointer_shim"); + let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty); // let empty_substs = tcx.mk_substs(Substs::trans_empty()); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 19891e93072..61af5bfaef8 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -126,6 +126,7 @@ use trans::common; use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan}; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::glue; use middle::region; use trans::type_::Type; @@ -844,10 +845,8 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef { Some(llpersonality) => llpersonality, None => { let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = base::decl_cdecl_fn(self.ccx, - "rust_eh_personality", - fty, - self.ccx.tcx().types.i32); + let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty, + self.ccx.tcx().types.i32); *personality = Some(f); f } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c343d705e86..60d54cdebeb 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -21,6 +21,7 @@ use trans::common::*; use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue}; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::expr; use trans::monomorphize::{self, MonoId}; 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") }); - let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]); + // Currently there’s 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 attributes::inline(llfn, attributes::InlineAttr::Hint); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index c5985e930e9..153242353d4 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -31,6 +31,7 @@ use trans::consts; use trans::datum; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -872,9 +873,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let buf = CString::new(format!("str{}", gsym.usize())); - let buf = buf.unwrap(); - let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); + let sym = format!("str{}", gsym.usize()); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + cx.sess().bug(&format!("symbol `{}` is already defined", sym)); + }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c32cb28ec78..336e68f1e8b 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -25,6 +25,7 @@ use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::base::{self, push_ctxt}; use trans::common::*; +use trans::declare; use trans::monomorphize; use trans::type_::Type; use trans::type_of; @@ -35,6 +36,7 @@ use std::iter::repeat; use libc::c_uint; use syntax::{ast, ast_util}; +use syntax::parse::token; use syntax::ptr::P; 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, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { unsafe { - let name = format!("{}{}\0", kind, id); - let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(), - name.as_ptr() as *const _); + // FIXME: this totally needs a better name generation scheme, perhaps a simple global + // counter? Also most other uses of gensym in trans. + 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); SetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); @@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { match ccx.const_globals().borrow().get(&cv) { Some(&gv) => return gv, None => {} } - let gv = addr_of_mut(ccx, cv, kind, id); + let gv = addr_of_mut(ccx, cv, kind); unsafe { 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); lvalue } @@ -284,7 +288,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if adj.autoderefs == 0 { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref", e.id); + llconst = addr_of(cx, llconst, "autoref"); } else { // Seeing as we are deref'ing here and take a reference // 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 => {} Some(box ty::AutoUnsafe(_, 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)) => { 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 // normal constant evaluation. 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) => { 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) => { 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 { let _icx = push_ctxt("trans_static"); 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); + g } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 8919a386a45..e54962dc085 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -20,6 +20,7 @@ use trans::builder::Builder; use trans::common::{ExternMap,BuilderRef_res}; use trans::debuginfo; +use trans::declare; use trans::monomorphize::MonoId; use trans::type_::{Type, TypeNames}; use middle::subst::Substs; @@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> { llsizingtypes: RefCell, Type>>, adt_reprs: RefCell, Rc>>>, type_hashcodes: RefCell, String>>, - all_llvm_symbols: RefCell>, int_type: Type, opaque_vec_type: Type, builder: BuilderRef_res, @@ -413,7 +413,6 @@ fn new(shared: &SharedCrateContext<'tcx>, llsizingtypes: RefCell::new(FnvHashMap()), adt_reprs: RefCell::new(FnvHashMap()), type_hashcodes: RefCell::new(FnvHashMap()), - all_llvm_symbols: RefCell::new(FnvHashSet()), int_type: Type::from_ref(ptr::null_mut()), opaque_vec_type: Type::from_ref(ptr::null_mut()), builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)), @@ -653,10 +652,6 @@ pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell, String>> &self.local.type_hashcodes } - pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell> { - &self.local.all_llvm_symbols - } - pub fn stats<'a>(&'a self) -> &'a Stats { &self.shared.stats } @@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn( - ccx, $name, Type::func(&[], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn(ccx, $name, - Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret); } else if *key == $name { - let f = base::decl_cdecl_fn(ccx, stringify!($cname), - Type::func(&[$($arg),*], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, stringify!($cname), + Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index 5b1ac88c208..3ce883af07f 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -417,8 +417,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); 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 = consts::addr_of(ccx, expr_file_line_const, - "panic_loc", call_info.id); + let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc"); let args = vec!(expr_file_line); let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem); 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 line = C_u32(ccx, loc.line as u32); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::addr_of(ccx, file_line_const, - "panic_bounds_check_loc", call_info.id); + let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 2747288b607..a32b40dc2b6 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -196,8 +196,9 @@ use metadata::csearch; use middle::subst::{self, Substs}; use trans::{self, adt, machine, type_of}; -use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, - C_bytes, NormalizingClosureTyper}; +use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes, + NormalizingClosureTyper}; +use trans::declare; use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef}; use trans::monomorphize; use trans::type_::Type; @@ -4071,7 +4072,7 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext) /// section. fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) -> 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 { llvm::LLVMGetNamedGlobal(ccx.llmod(), @@ -4085,10 +4086,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) unsafe { let llvm_type = Type::array(&Type::i8(ccx), section_contents.len() as u64); - let section_var = llvm::LLVMAddGlobal(ccx.llmod(), - llvm_type.to_ref(), - section_var_name.as_ptr() - as *const _); + + let section_var = declare::define_global(ccx, section_var_name, + llvm_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name)) + }); llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs new file mode 100644 index 00000000000..147b5161a4a --- /dev/null +++ b/src/librustc_trans/trans/declare.rs @@ -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 or the MIT license +// , 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 there’s 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 there’s 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 there’s 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 there’s 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 there’s 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 user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option { + 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 user’s 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 { + 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 user’s 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 { + 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 user’s 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 { + 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 user’s 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 { + 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 { + 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 + } + } +} diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index 20da3c1c9f8..8f3a51a5007 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -20,6 +20,7 @@ use trans::cabi; use trans::common::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -28,7 +29,6 @@ use middle::ty::{self, Ty}; use middle::subst::Substs; -use std::ffi::CString; use std::cmp; use libc::c_uint; use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi}; @@ -136,9 +136,7 @@ pub fn register_static(ccx: &CrateContext, }; unsafe { // Declare a symbol `foo` with the desired linkage. - let buf = CString::new(ident.as_bytes()).unwrap(); - let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(), - buf.as_ptr()); + let g1 = declare::declare_global(ccx, &ident[..], llty2); llvm::SetLinkage(g1, linkage); // Declare an internal global `extern_with_linkage_foo` which @@ -149,19 +147,17 @@ pub fn register_static(ccx: &CrateContext, // zero. let mut real_name = "_rust_extern_with_linkage_".to_string(); real_name.push_str(&ident); - let real_name = CString::new(real_name).unwrap(); - let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), - real_name.as_ptr()); + let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{ + ccx.sess().span_fatal(foreign_item.span, + &format!("symbol `{}` is already defined", ident)) + }); llvm::SetLinkage(g2, llvm::InternalLinkage); llvm::LLVMSetInitializer(g2, g1); g2 } } - None => unsafe { - // Generate an external declaration. - let buf = CString::new(ident.as_bytes()).unwrap(); - llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr()) - } + None => // Generate an external declaration. + declare::declare_global(ccx, &ident[..], llty), } } @@ -177,7 +173,7 @@ pub fn get_extern_fn(ccx: &CrateContext, Some(n) => return *n, 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); 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") }; - 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); debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})", ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn)); @@ -623,7 +620,9 @@ fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.tcx().map.path_to_string(id), 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); base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]); llfn diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 898d4216e5a..abcd2882b17 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -33,6 +33,7 @@ use trans::consts; use trans::datum; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; use trans::foreign; 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 // added the entry to the `drop_glues` cache. 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); return llfn; }; @@ -294,12 +295,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did, &[get_drop_glue_type(ccx, t)], ty::mk_nil(ccx.tcx())); - foreign::get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - &name[..], - llvm::CCallConv, - llty, - dtor_ty) + foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv, + llty, dtor_ty) } } diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 190e44c9674..e2f965a95ff 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -28,6 +28,7 @@ use trans::consts; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr::SaveIn; use trans::expr; 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 method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = - decl_internal_rust_fn(ccx, shim_fn_ty, &function_name); + let function_name = 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(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); 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) ].into_iter().chain(methods).collect(); - let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), - "vtable", trait_ref.def_id().node); + let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 0face6860dc..7d568ff90ea 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -43,6 +43,7 @@ mod controlflow; mod datum; mod debuginfo; +mod declare; mod expr; mod foreign; mod glue; diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index 862eb31303e..1c8d020494f 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -19,9 +19,10 @@ use middle::ty_fold::{TypeFolder, TypeFoldable}; use trans::attributes; 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::common::*; +use trans::declare; use trans::foreign; use middle::ty::{self, HasProjectionTypes, Ty}; use util::ppaux::Repr; @@ -143,7 +144,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let lldecl = if abi != abi::Rust { foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..]) } 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); -- GitLab