]> git.lizzy.rs Git - rust.git/commitdiff
Introduce trans::declare
authorSimonas Kazlauskas <git@kazlauskas.me>
Tue, 3 Mar 2015 23:08:06 +0000 (01:08 +0200)
committerSimonas Kazlauskas <git@kazlauskas.me>
Fri, 3 Apr 2015 12:48:07 +0000 (15:48 +0300)
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.

15 files changed:
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/callee.rs
src/librustc_trans/trans/cleanup.rs
src/librustc_trans/trans/closure.rs
src/librustc_trans/trans/common.rs
src/librustc_trans/trans/consts.rs
src/librustc_trans/trans/context.rs
src/librustc_trans/trans/controlflow.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/declare.rs [new file with mode: 0644]
src/librustc_trans/trans/foreign.rs
src/librustc_trans/trans/glue.rs
src/librustc_trans/trans/meth.rs
src/librustc_trans/trans/mod.rs
src/librustc_trans/trans/monomorphize.rs

index a1fa4e77a131bb02935ac8231849e39c56e026a1..c7200fc8bb256157c4d0c5f01bcbc995fc175916 100644 (file)
@@ -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
index 9eb46d3ff549a80bd33a7ef06295fc67f8a676a8..604f185f396b81994230f77d4738dd73d1334a0f 100644 (file)
@@ -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());
index 19891e9307229fa52ee380c21b743b0f67fe9d5b..61af5bfaef8dee5db3da83e9ff959fad99ab1963 100644 (file)
 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
                     }
index c343d705e866f029b3e3868cf9981dcfcdd1f120..60d54cdebeb83ff670462d84edea05702ec05453 100644 (file)
@@ -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);
index c5985e930e97b98b72fc9e3ffdb72a3c6e1af935..153242353d49f5e5c9ac2cfefb482df90fc77861 100644 (file)
@@ -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);
index c32cb28ec78dbb9bbdbf83fced5510b615f2780e..336e68f1e8b496288cb20729e57a9ae93a596b03 100644 (file)
@@ -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
     }
 }
 
index 8919a386a45fb0ac1182174d8dbc65301f9f0318..e54962dc085524e1b41fc337fc453503379c231d 100644 (file)
@@ -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<FnvHashMap<Ty<'tcx>, Type>>,
     adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>,
     type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>,
-    all_llvm_symbols: RefCell<FnvHashSet<String>>,
     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<FnvHashMap<Ty<'tcx>, String>>
         &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 {
         &self.shared.stats
     }
@@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
     macro_rules! ifn {
         ($name:expr, fn() -> $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 @@ macro_rules! compatible_ifn {
                 // The `if key == $name` is already in ifn!
                 ifn!($name, fn($($arg),*) -> $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);
             }
index 5b1ac88c2089b951113911b16527cba09b547af8..3ce883af07f6a56e94296a3d238bd2a286e5c024 100644 (file)
@@ -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,
index 2747288b60755c9245156bb496e4278d859e1aef..a32b40dc2b640b673e70a371c580d856831b24e1 100644 (file)
 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 (file)
index 0000000..147b516
--- /dev/null
@@ -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 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<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 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<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 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<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 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<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 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<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
+        }
+    }
+}
index 20da3c1c9f89518ebfb31bdbccc4ef70486fbe88..8f3a51a5007096984835901d54f13b8f07b21150 100644 (file)
@@ -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
index 898d4216e5a6b6addef3209163d538c38880a5e9..abcd2882b173e90e41e4e69dd5409c6c9986d6cc 100644 (file)
@@ -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)
     }
 }
 
index 190e44c9674cb5a13d10826aa60156fb15b40adc..e2f965a95fff78f130638f508f322287d2845e2c 100644 (file)
@@ -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
index 0face6860dce533e9250e558c397f6de6b6f7812..7d568ff90ea43cbc0dbfe078f258000fa807b88b 100644 (file)
@@ -43,6 +43,7 @@
 mod controlflow;
 mod datum;
 mod debuginfo;
+mod declare;
 mod expr;
 mod foreign;
 mod glue;
index 862eb31303e4fa9eda58493877e94dc44763a9c3..1c8d020494fabfa0788d0c053d3ea0a37d38c3bb 100644 (file)
 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);