use trans::controlflow;
use trans::datum;
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
+use trans::declare;
use trans::expr;
use trans::foreign;
use trans::glue;
}
}
-// 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) {
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);
*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);
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>,
}
-// 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 {
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);
}
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");
+ }
+ }
}
}
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
}
}
-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);
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>,
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
}
}
}
-// 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
} 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") {
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
use trans::consts;
use trans::datum::*;
use trans::debuginfo::{DebugLoc, ToDebugLoc};
+use trans::declare;
use trans::expr;
use trans::glue;
use trans::inline;
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());
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;
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
}
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::*;
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);
use trans::consts;
use trans::datum;
use trans::debuginfo::{self, DebugLoc};
+use trans::declare;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
!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);
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;
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)
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);
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);
}
}
};
- 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
}
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,
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 =
// 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);
}
}
-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);
}
}
debuginfo::create_global_var_metadata(ccx, id, g);
+ g
}
}
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;
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,
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)),
&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
}
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);
}
// 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);
}
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,
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,
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;
/// 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(),
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);
--- /dev/null
+// 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
+ }
+ }
+}
use trans::cabi;
use trans::common::*;
use trans::debuginfo::DebugLoc;
+use trans::declare;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
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};
};
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
// 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),
}
}
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
}
}
_ => 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));
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
use trans::consts;
use trans::datum;
use trans::debuginfo::DebugLoc;
+use trans::declare;
use trans::expr;
use trans::foreign;
use trans::inline;
// 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;
};
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)
}
}
use trans::consts;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
+use trans::declare;
use trans::expr::SaveIn;
use trans::expr;
use trans::glue;
//
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);
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
mod controlflow;
mod datum;
mod debuginfo;
+mod declare;
mod expr;
mod foreign;
mod glue;
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;
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);