diff options
Diffstat (limited to 'src/librustc_trans/trans/declare.rs')
-rw-r--r-- | src/librustc_trans/trans/declare.rs | 146 |
1 files changed, 29 insertions, 117 deletions
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs index 0c512200ff3..e63f17770bc 100644 --- a/src/librustc_trans/trans/declare.rs +++ b/src/librustc_trans/trans/declare.rs @@ -22,13 +22,10 @@ use llvm::{self, ValueRef}; use middle::ty; use middle::infer; -use middle::traits::ProjectionMode; -use syntax::abi::Abi; +use trans::abi::{Abi, FnType}; use trans::attributes; -use trans::base; use trans::context::CrateContext; use trans::type_::Type; -use trans::type_of; use std::ffi::CString; use libc::c_uint; @@ -51,13 +48,10 @@ pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRe /// 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); +fn declare_raw_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type) -> ValueRef { + debug!("declare_raw_fn(name={:?}, ty={:?})", name, ty); let namebuf = CString::new(name).unwrap_or_else(|_|{ ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) }); @@ -70,10 +64,6 @@ pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, // be merged. llvm::SetUnnamedAddr(llfn, true); - if output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn); - } - if ccx.tcx().sess.opts.cg.no_redzone .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoRedZone) @@ -86,13 +76,12 @@ pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, /// Declare a C ABI function. /// /// Only use this for foreign function ABIs and glue. For Rust functions use -/// `declare_rust_fn` instead. +/// `declare_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)) +pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef { + declare_raw_fn(ccx, name, llvm::CCallConv, fn_type) } @@ -100,53 +89,27 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, /// /// 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); - - let function_type; // placeholder so that the memory ownership works out ok - let (sig, abi, env) = match fn_type.sty { - ty::TyFnDef(_, _, f) | - ty::TyFnPtr(f) => { - (&f.sig, f.abi, None) - } - ty::TyClosure(closure_did, ref substs) => { - let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), - &ccx.tcx().tables, - ProjectionMode::Any); - function_type = infcx.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, self_type); - (&function_type.sig, Abi::RustCall, Some(llenvironment_type)) - } - _ => ccx.sess().bug("expected closure or fn") - }; - - let sig = ccx.tcx().erase_late_bound_regions(sig); +pub fn declare_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); + let abi = fn_type.fn_abi(); + let sig = ccx.tcx().erase_late_bound_regions(fn_type.fn_sig()); let sig = infer::normalize_associated_type(ccx.tcx(), &sig); debug!("declare_rust_fn (after region erasure) sig={:?}", sig); - 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.output); - attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); - llfn -} + let fty = FnType::new(ccx, abi, &sig, &[]); + let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx)); + if sig.output == ty::FnDiverging { + llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn); + } + + if abi != Abi::Rust && abi != Abi::RustCall { + attributes::unwind(llfn, false); + } + + fty.apply_attrs_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 } @@ -166,78 +129,27 @@ pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRe } -/// 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 panic if the name already has a definition associated with it. This /// can happen with #[no_mangle] or #[export_name], for example. -pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - name: &str, - fn_type: ty::Ty<'tcx>) -> ValueRef { +pub fn define_internal_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { if get_defined_value(ccx, name).is_some() { ccx.sess().fatal(&format!("symbol `{}` already defined", name)) } else { - declare_internal_rust_fn(ccx, name, fn_type) + let llfn = declare_fn(ccx, name, fn_type); + llvm::SetLinkage(llfn, llvm::InternalLinkage); + llfn } } /// Get defined or externally defined (AvailableExternally linkage) value by /// name. -fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> { +pub 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)) |