diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 9b0ae2e9ef858..7030ee5697954 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -157,7 +157,7 @@ bitflags! { #[derive(Copy, Clone)] pub enum OtherAttribute { // The following are not really exposed in - // the LLVM c api so instead to add these + // the LLVM C api so instead to add these // we call a wrapper function in RustWrapper // that uses the C++ api. SanitizeAddressAttribute = 1 << 32, @@ -912,6 +912,7 @@ extern { AddressSpace: c_uint) -> ValueRef; pub fn LLVMGetNamedGlobal(M: ModuleRef, Name: *const c_char) -> ValueRef; + pub fn LLVMGetOrInsertGlobal(M: ModuleRef, Name: *const c_char, T: TypeRef) -> ValueRef; pub fn LLVMGetFirstGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetLastGlobal(M: ModuleRef) -> ValueRef; pub fn LLVMGetNextGlobal(GlobalVar: ValueRef) -> ValueRef; @@ -924,6 +925,7 @@ extern { pub fn LLVMSetThreadLocal(GlobalVar: ValueRef, IsThreadLocal: Bool); pub fn LLVMIsGlobalConstant(GlobalVar: ValueRef) -> Bool; pub fn LLVMSetGlobalConstant(GlobalVar: ValueRef, IsConstant: Bool); + pub fn LLVMGetNamedValue(M: ModuleRef, Name: *const c_char) -> ValueRef; /* Operations on aliases */ pub fn LLVMAddAlias(M: ModuleRef, @@ -957,6 +959,7 @@ extern { pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *const c_char); pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong; + pub fn LLVMRemoveFunctionAttr(Fn: ValueRef, val: c_ulonglong); /* Operations on parameters */ pub fn LLVMCountParams(Fn: ValueRef) -> c_uint; diff --git a/src/librustc_trans/trans/attributes.rs b/src/librustc_trans/trans/attributes.rs new file mode 100644 index 0000000000000..2615490a9fbc5 --- /dev/null +++ b/src/librustc_trans/trans/attributes.rs @@ -0,0 +1,281 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Set and unset common attributes on LLVM values. + +use libc::{c_uint, c_ulonglong}; +use llvm::{self, ValueRef, AttrHelper}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; +use syntax::ast; +pub use syntax::attr::InlineAttr; +use trans::base; +use trans::common; +use trans::context::CrateContext; +use trans::machine; +use trans::type_of; + +/// Mark LLVM function to use split stack. +#[inline] +pub fn split_stack(val: ValueRef, set: bool) { + unsafe { + let attr = "split-stack\0".as_ptr() as *const _; + if set { + llvm::LLVMAddFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } else { + llvm::LLVMRemoveFunctionAttrString(val, llvm::FunctionIndex as c_uint, attr); + } + } +} + +/// Mark LLVM function to use provided inline heuristic. +#[inline] +pub fn inline(val: ValueRef, inline: InlineAttr) { + use self::InlineAttr::*; + match inline { + Hint => llvm::SetFunctionAttribute(val, llvm::InlineHintAttribute), + Always => llvm::SetFunctionAttribute(val, llvm::AlwaysInlineAttribute), + Never => llvm::SetFunctionAttribute(val, llvm::NoInlineAttribute), + None => { + let attr = llvm::InlineHintAttribute | + llvm::AlwaysInlineAttribute | + llvm::NoInlineAttribute; + unsafe { + llvm::LLVMRemoveFunctionAttr(val, attr.bits() as c_ulonglong) + } + }, + }; +} + +/// Tell LLVM to emit or not emit the information necessary to unwind the stack for the function. +#[inline] +pub fn emit_uwtable(val: ValueRef, emit: bool) { + if emit { + llvm::SetFunctionAttribute(val, llvm::UWTableAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::UWTableAttribute.bits() as c_ulonglong); + } + } +} + +/// Tell LLVM whether the function can or cannot unwind. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn unwind(val: ValueRef, can_unwind: bool) { + if can_unwind { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::NoUnwindAttribute.bits() as c_ulonglong); + } + } else { + llvm::SetFunctionAttribute(val, llvm::NoUnwindAttribute); + } +} + +/// Tell LLVM whether it should optimise function for size. +#[inline] +#[allow(dead_code)] // possibly useful function +pub fn set_optimize_for_size(val: ValueRef, optimize: bool) { + if optimize { + llvm::SetFunctionAttribute(val, llvm::OptimizeForSizeAttribute); + } else { + unsafe { + llvm::LLVMRemoveFunctionAttr(val, llvm::OptimizeForSizeAttribute.bits() as c_ulonglong); + } + } +} + +/// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) +/// attributes. +pub fn from_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { + use syntax::attr::*; + inline(llfn, find_inline_attr(Some(ccx.sess().diagnostic()), attrs)); + + for attr in attrs { + if attr.check_name("no_stack_check") { + split_stack(llfn, false); + } else if attr.check_name("cold") { + unsafe { + llvm::LLVMAddFunctionAttribute(llfn, + llvm::FunctionIndex as c_uint, + llvm::ColdAttribute as u64) + } + } else if attr.check_name("allocator") { + llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); + } + } +} + +/// Composite function which converts function type into LLVM attributes for the function. +pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx>) + -> llvm::AttrBuilder { + use middle::ty::{BrAnon, ReLateBound}; + + let function_type; + let (fn_sig, abi, env_ty) = 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); + (&function_type.sig, abi::RustCall, Some(self_type)) + } + _ => ccx.sess().bug("expected closure or function.") + }; + + let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); + + let mut attrs = llvm::AttrBuilder::new(); + let ret_ty = fn_sig.output; + + // These have an odd calling convention, so we need to manually + // unpack the input ty's + let input_tys = match fn_type.sty { + ty::ty_closure(..) => { + assert!(abi == abi::RustCall); + + match fn_sig.inputs[0].sty { + ty::ty_tup(ref inputs) => { + let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; + full_inputs.push_all(inputs); + full_inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + }, + ty::ty_bare_fn(..) if abi == abi::RustCall => { + let mut inputs = vec![fn_sig.inputs[0]]; + + match fn_sig.inputs[1].sty { + ty::ty_tup(ref t_in) => { + inputs.push_all(&t_in[..]); + inputs + } + _ => ccx.sess().bug("expected tuple'd inputs") + } + } + _ => fn_sig.inputs.clone() + }; + + // Index 0 is the return value of the llvm func, so we start at 1 + let mut first_arg_offset = 1; + if let ty::FnConverging(ret_ty) = ret_ty { + // A function pointer is called without the declaration + // available, so we have to apply any attributes with ABI + // implications directly to the call instruction. Right now, + // the only attribute we need to worry about is `sret`. + if type_of::return_uses_outptr(ccx, ret_ty) { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); + + // The outptr can be noalias and nocapture because it's entirely + // invisible to the program. We also know it's nonnull as well + // as how many bytes we can dereference + attrs.arg(1, llvm::StructRetAttribute) + .arg(1, llvm::NoAliasAttribute) + .arg(1, llvm::NoCaptureAttribute) + .arg(1, llvm::DereferenceableAttribute(llret_sz)); + + // Add one more since there's an outptr + first_arg_offset += 1; + } else { + // The `noalias` attribute on the return value is useful to a + // function ptr caller. + match ret_ty.sty { + // `~` pointer return values never alias because ownership + // is transferred + ty::ty_uniq(it) if common::type_is_sized(ccx.tcx(), it) => { + attrs.ret(llvm::NoAliasAttribute); + } + _ => {} + } + + // We can also mark the return value as `dereferenceable` in certain cases + match ret_ty.sty { + // These are not really pointers but pairs, (pointer, len) + ty::ty_rptr(_, ty::mt { ty: inner, .. }) + | ty::ty_uniq(inner) if common::type_is_sized(ccx.tcx(), inner) => { + let llret_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + attrs.ret(llvm::DereferenceableAttribute(llret_sz)); + } + _ => {} + } + + if let ty::ty_bool = ret_ty.sty { + attrs.ret(llvm::ZExtAttribute); + } + } + } + + for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { + match t.sty { + // this needs to be first to prevent fat pointers from falling through + _ if !common::type_is_immediate(ccx, t) => { + let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t)); + + // For non-immediate arguments the callee gets its own copy of + // the value on the stack, so there are no aliases. It's also + // program-invisible so can't possibly capture + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); + } + + ty::ty_bool => { + attrs.arg(idx, llvm::ZExtAttribute); + } + + // `~` pointer parameters never alias because ownership is transferred + ty::ty_uniq(inner) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, inner)); + + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // `&mut` pointer parameters never alias other parameters, or mutable global data + // + // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both + // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on + // memory dependencies rather than pointer equality + ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || + !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { + + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoAliasAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + + if mt.mutbl == ast::MutImmutable { + attrs.arg(idx, llvm::ReadOnlyAttribute); + } + + if let ReLateBound(_, BrAnon(_)) = *b { + attrs.arg(idx, llvm::NoCaptureAttribute); + } + } + + // When a reference in an argument has no named lifetime, it's impossible for that + // reference to escape this function (returned or stored beyond the call by a closure). + ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::NoCaptureAttribute) + .arg(idx, llvm::DereferenceableAttribute(llsz)); + } + + // & pointer parameters are also never null and we know exactly how + // many bytes we can dereference + ty::ty_rptr(_, mt) => { + let llsz = machine::llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); + attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); + } + _ => () + } + } + + attrs +} diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 05c366a645e76..7c51a193b984b 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// 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. // @@ -7,21 +7,20 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. - -// trans.rs: Translate the completed AST to the LLVM IR. -// -// Some functions here, such as trans_block and trans_expr, return a value -- -// the result of the translation to LLVM -- while others, such as trans_fn, -// trans_impl, and trans_item, are called only for the side effect of adding a -// particular definition to the LLVM IR output we're producing. -// -// Hopefully useful general knowledge about trans: -// -// * There's no way to find out the Ty type of a ValueRef. Doing so -// would be "trying to get the eggs out of an omelette" (credit: -// pcwalton). You can, instead, find out its TypeRef by calling val_ty, -// but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, -// int) and rec(x=int, y=int, z=int) will have the same TypeRef. +//! Translate the completed AST to the LLVM IR. +//! +//! Some functions here, such as trans_block and trans_expr, return a value -- +//! the result of the translation to LLVM -- while others, such as trans_fn, +//! trans_impl, and trans_item, are called only for the side effect of adding a +//! particular definition to the LLVM IR output we're producing. +//! +//! Hopefully useful general knowledge about trans: +//! +//! * There's no way to find out the Ty type of a ValueRef. Doing so +//! would be "trying to get the eggs out of an omelette" (credit: +//! pcwalton). You can, instead, find out its TypeRef by calling val_ty, +//! but one TypeRef corresponds to many `Ty`s; for instance, tup(int, int, +//! int) and rec(x=int, y=int, z=int) will have the same TypeRef. #![allow(non_camel_case_types)] @@ -33,19 +32,20 @@ use super::ModuleTranslation; use back::link::mangle_exported_name; use back::{link, abi}; use lint; -use llvm::{AttrHelper, BasicBlockRef, Linkage, ValueRef, Vector, get_param}; +use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param}; use llvm; use metadata::{csearch, encoder, loader}; use middle::astencode; use middle::cfg; use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem}; use middle::weak_lang_items; -use middle::subst::{Subst, Substs}; +use middle::subst::Substs; use middle::ty::{self, Ty, ClosureTyper, type_is_simd, simd_size}; use session::config::{self, NoDebugInfo}; use session::Session; use trans::_match; use trans::adt; +use trans::attributes; use trans::build::*; use trans::builder::{Builder, noname}; use trans::callee; @@ -54,7 +54,7 @@ use trans::cleanup; use trans::closure; use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral}; use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; -use trans::common::{CrateContext, ExternMap, FunctionContext}; +use trans::common::{CrateContext, FunctionContext}; use trans::common::{Result, NodeIdAndSpan}; use trans::common::{node_id_type, return_type_is_void}; use trans::common::{type_is_immediate, type_is_zero_size, val_ty}; @@ -64,10 +64,10 @@ use trans::context::SharedCrateContext; use trans::controlflow; use trans::datum; use trans::debuginfo::{self, DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::foreign; use trans::glue; -use trans::inline; use trans::intrinsic; use trans::machine; use trans::machine::{llsize_of, llsize_of_real}; @@ -84,7 +84,7 @@ use util::sha2::Sha256; use util::nodemap::NodeMap; use arena::TypedArena; -use libc::{c_uint, uint64_t}; +use libc::c_uint; use std::ffi::{CStr, CString}; use std::cell::{Cell, RefCell}; use std::collections::HashSet; @@ -180,61 +180,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions -pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv, - ty: Type, output: ty::FnOutput) -> ValueRef { - - let buf = CString::new(name).unwrap(); - let llfn: ValueRef = unsafe { - llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref()) - }; - - // diverging functions may unwind, but can never return normally - if output == ty::FnDiverging { - llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); - } - - if ccx.tcx().sess.opts.cg.no_redzone - .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { - llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) - } - - llvm::SetFunctionCallConv(llfn, cc); - // Function addresses in Rust are never significant, allowing functions to be merged. - llvm::SetUnnamedAddr(llfn, true); - - if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { - set_split_stack(llfn); - } - - 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)) -} - -// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions -pub fn get_extern_fn(ccx: &CrateContext, - externs: &mut ExternMap, - name: &str, - cc: llvm::CallConv, - ty: Type, - output: Ty) - -> ValueRef { - match externs.get(name) { - Some(n) => return *n, - None => {} - } - let f = decl_fn(ccx, name, cc, ty, ty::FnConverging(output)); - externs.insert(name.to_string(), f); - f -} - 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) { @@ -242,10 +187,10 @@ 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); - set_llvm_fn_attrs(ccx, &attrs[..], f); + attributes::from_fn_attrs(ccx, &attrs[..], f); ccx.externs().borrow_mut().insert(name.to_string(), f); f @@ -272,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); @@ -337,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>, @@ -390,125 +277,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr)) } -#[allow(dead_code)] // useful -pub fn set_optimize_for_size(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::OptimizeForSizeAttribute) -} - -pub fn set_no_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoInlineAttribute) -} - -#[allow(dead_code)] // useful -pub fn set_no_unwind(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::NoUnwindAttribute) -} - -// Tell LLVM to emit the information necessary to unwind the stack for the -// function f. -pub fn set_uwtable(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::UWTableAttribute) -} - -pub fn set_inline_hint(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::InlineHintAttribute) -} - -pub fn set_llvm_fn_attrs(ccx: &CrateContext, attrs: &[ast::Attribute], llfn: ValueRef) { - use syntax::attr::{find_inline_attr, InlineAttr}; - // Set the inline hint if there is one - match find_inline_attr(Some(ccx.sess().diagnostic()), attrs) { - InlineAttr::Hint => set_inline_hint(llfn), - InlineAttr::Always => set_always_inline(llfn), - InlineAttr::Never => set_no_inline(llfn), - InlineAttr::None => { /* fallthrough */ } - } - - for attr in attrs { - let mut used = true; - match &attr.name()[..] { - "no_stack_check" => unset_split_stack(llfn), - "cold" => unsafe { - llvm::LLVMAddFunctionAttribute(llfn, - llvm::FunctionIndex as c_uint, - llvm::ColdAttribute as uint64_t) - }, - "allocator" => { - llvm::NoAliasAttribute.apply_llfn(llvm::ReturnIndex as c_uint, llfn); - } - _ => used = false, - } - if used { - attr::mark_used(attr); - } - } -} - -pub fn set_always_inline(f: ValueRef) { - llvm::SetFunctionAttribute(f, llvm::AlwaysInlineAttribute) -} - -pub fn set_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMAddFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -pub fn unset_split_stack(f: ValueRef) { - unsafe { - llvm::LLVMRemoveFunctionAttrString(f, llvm::FunctionIndex as c_uint, - "split-stack\0".as_ptr() as *const _); - } -} - -// 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 get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, - did: ast::DefId, - t: Ty<'tcx>, - parent_id: ast::DefId, - substs: &Substs<'tcx>) - -> ValueRef { - let _icx = push_ctxt("trans_res_dtor"); - let did = inline::maybe_instantiate_inline(ccx, did); - - if !substs.types.is_empty() { - assert_eq!(did.krate, ast::LOCAL_CRATE); - - // Since we're in trans we don't care for any region parameters - let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); - - let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); - - val - } else if did.krate == ast::LOCAL_CRATE { - get_item_val(ccx, did.node) - } else { - let tcx = ccx.tcx(); - let name = csearch::get_symbol(&ccx.sess().cstore, did); - let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); - let llty = type_of_dtor(ccx, class_ty); - let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), - did, - &[glue::get_drop_glue_type(ccx, t)], - ty::mk_nil(ccx.tcx())); - get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - &name[..], - llvm::CCallConv, - llty, - dtor_ty) - } -} pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool) -> llvm::IntPredicate { @@ -898,7 +666,7 @@ pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => { let llfn = foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name[..]); let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did); - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); llfn } } @@ -920,7 +688,7 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, return (C_null(Type::i8(bcx.ccx())), bcx); } - let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty); + let attributes = attributes::from_fn_type(bcx.ccx(), fn_ty); match bcx.opt_node_id { None => { @@ -1692,9 +1460,9 @@ pub fn build_return_block<'blk, 'tcx>(fcx: &FunctionContext<'blk, 'tcx>, } } -// trans_closure: Builds an LLVM function out of a source function. -// If the function closes over its environment a closure will be -// returned. +/// Builds an LLVM function out of a source function. +/// +/// If the function closes over its environment a closure will be returned. pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -1708,7 +1476,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1); let _icx = push_ctxt("trans_closure"); - set_uwtable(llfndecl); + attributes::emit_uwtable(llfndecl, true); debug!("trans_closure(..., param_substs={})", param_substs.repr(ccx.tcx())); @@ -1827,8 +1595,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, finish_fn(&fcx, bcx, output_type, ret_debug_loc); } -// trans_fn: creates an LLVM function corresponding to a source language -// function. +/// Creates an LLVM function corresponding to a source language function. pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, decl: &ast::FnDecl, body: &ast::Block, @@ -1842,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); } @@ -2195,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"); + } + } } } @@ -2251,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 @@ -2304,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); @@ -2313,25 +2086,12 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N // eh_personality functions need to be externally linkable. let def = ast_util::local_def(node_id); if ccx.tcx().lang_items.stack_exhausted() == Some(def) { - unset_split_stack(llfn); + attributes::split_stack(llfn, false); llvm::SetLinkage(llfn, llvm::ExternalLinkage); } 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>, @@ -2350,196 +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 -} - -pub fn get_fn_llvm_attributes<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>) - -> llvm::AttrBuilder -{ - use middle::ty::{BrAnon, ReLateBound}; - - let function_type; - let (fn_sig, abi, env_ty) = 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); - (&function_type.sig, RustCall, Some(self_type)) - } - _ => ccx.sess().bug("expected closure or function.") - }; - - let fn_sig = ty::erase_late_bound_regions(ccx.tcx(), fn_sig); - - let mut attrs = llvm::AttrBuilder::new(); - let ret_ty = fn_sig.output; - - // These have an odd calling convention, so we need to manually - // unpack the input ty's - let input_tys = match fn_ty.sty { - ty::ty_closure(..) => { - assert!(abi == RustCall); - - match fn_sig.inputs[0].sty { - ty::ty_tup(ref inputs) => { - let mut full_inputs = vec![env_ty.expect("Missing closure environment")]; - full_inputs.push_all(inputs); - full_inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - }, - ty::ty_bare_fn(..) if abi == RustCall => { - let mut inputs = vec![fn_sig.inputs[0]]; - - match fn_sig.inputs[1].sty { - ty::ty_tup(ref t_in) => { - inputs.push_all(&t_in[..]); - inputs - } - _ => ccx.sess().bug("expected tuple'd inputs") - } - } - _ => fn_sig.inputs.clone() - }; - - // Index 0 is the return value of the llvm func, so we start at 1 - let mut first_arg_offset = 1; - if let ty::FnConverging(ret_ty) = ret_ty { - // A function pointer is called without the declaration - // available, so we have to apply any attributes with ABI - // implications directly to the call instruction. Right now, - // the only attribute we need to worry about is `sret`. - if type_of::return_uses_outptr(ccx, ret_ty) { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, ret_ty)); - - // The outptr can be noalias and nocapture because it's entirely - // invisible to the program. We also know it's nonnull as well - // as how many bytes we can dereference - attrs.arg(1, llvm::StructRetAttribute) - .arg(1, llvm::NoAliasAttribute) - .arg(1, llvm::NoCaptureAttribute) - .arg(1, llvm::DereferenceableAttribute(llret_sz)); - - // Add one more since there's an outptr - first_arg_offset += 1; - } else { - // The `noalias` attribute on the return value is useful to a - // function ptr caller. - match ret_ty.sty { - // `~` pointer return values never alias because ownership - // is transferred - ty::ty_uniq(it) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(_) => { - attrs.ret(llvm::NoAliasAttribute); - } - _ => {} - } - - // We can also mark the return value as `dereferenceable` in certain cases - match ret_ty.sty { - // These are not really pointers but pairs, (pointer, len) - ty::ty_uniq(it) | - ty::ty_rptr(_, ty::mt { ty: it, .. }) if !common::type_is_sized(ccx.tcx(), it) => {} - ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => { - let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - attrs.ret(llvm::DereferenceableAttribute(llret_sz)); - } - _ => {} - } - - if let ty::ty_bool = ret_ty.sty { - attrs.ret(llvm::ZExtAttribute); - } - } - } - - for (idx, &t) in input_tys.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) { - match t.sty { - // this needs to be first to prevent fat pointers from falling through - _ if !type_is_immediate(ccx, t) => { - let llarg_sz = llsize_of_real(ccx, type_of::type_of(ccx, t)); - - // For non-immediate arguments the callee gets its own copy of - // the value on the stack, so there are no aliases. It's also - // program-invisible so can't possibly capture - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llarg_sz)); - } - - ty::ty_bool => { - attrs.arg(idx, llvm::ZExtAttribute); - } - - // `~` pointer parameters never alias because ownership is transferred - ty::ty_uniq(inner) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, inner)); - - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // `&mut` pointer parameters never alias other parameters, or mutable global data - // - // `&T` where `T` contains no `UnsafeCell` is immutable, and can be marked as both - // `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on - // memory dependencies rather than pointer equality - ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable || - !ty::type_contents(ccx.tcx(), mt.ty).interior_unsafe() => { - - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoAliasAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - - if mt.mutbl == ast::MutImmutable { - attrs.arg(idx, llvm::ReadOnlyAttribute); - } - - if let ReLateBound(_, BrAnon(_)) = *b { - attrs.arg(idx, llvm::NoCaptureAttribute); - } - } - - // When a reference in an argument has no named lifetime, it's impossible for that - // reference to escape this function (returned or stored beyond the call by a closure). - ty::ty_rptr(&ReLateBound(_, BrAnon(_)), mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::NoCaptureAttribute) - .arg(idx, llvm::DereferenceableAttribute(llsz)); - } - - // & pointer parameters are also never null and we know exactly how - // many bytes we can dereference - ty::ty_rptr(_, mt) => { - let llsz = llsize_of_real(ccx, type_of::type_of(ccx, mt.ty)); - attrs.arg(idx, llvm::DereferenceableAttribute(llsz)); - } - _ => () - } - } - - attrs -} - -// 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 } @@ -2550,27 +2124,35 @@ 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, + 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. } 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 @@ -2645,10 +2227,9 @@ fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, id: ast::NodeId, None => {} } - match attr::first_attr_value_str_by_name(attrs, "export_name") { + match attr::find_export_name_attr(ccx.sess().diagnostic(), attrs) { // Use provided name Some(name) => name.to_string(), - _ => ccx.tcx().map.with_path(id, |path| { if attr::contains_name(attrs, "no_mangle") { // Don't mangle @@ -2707,14 +2288,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") { @@ -2730,12 +2312,9 @@ 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) }; - set_llvm_fn_attrs(ccx, &i.attrs, llfn); + attributes::from_fn_attrs(ccx, &i.attrs, llfn); llfn } @@ -2796,7 +2375,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { let ty = ty::node_id_to_type(ccx.tcx(), ni.id); let name = foreign::link_name(&*ni); let llfn = foreign::register_foreign_item_fn(ccx, abi, ty, &name); - set_llvm_fn_attrs(ccx, &ni.attrs, llfn); + attributes::from_fn_attrs(ccx, &ni.attrs, llfn); llfn } ast::ForeignItemStatic(..) => { @@ -2828,7 +2407,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { } _ => ccx.sess().bug("NodeVariant, shouldn't happen") }; - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2850,7 +2429,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef { &struct_item.attrs); let llfn = register_fn(ccx, struct_item.span, sym, ctor_id, ty); - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); llfn } @@ -2885,7 +2464,7 @@ fn register_method(ccx: &CrateContext, id: ast::NodeId, } else { foreign::register_rust_fn_with_foreign_abi(ccx, span, sym, id) }; - set_llvm_fn_attrs(ccx, &attrs, llfn); + attributes::from_fn_attrs(ccx, &attrs, llfn); return llfn; } else { ccx.sess().span_bug(span, "expected bare rust function"); diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 9eb46d3ff549a..604f185f396b8 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -41,6 +41,7 @@ use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext, use trans::consts; use trans::datum::*; use trans::debuginfo::{DebugLoc, ToDebugLoc}; +use trans::declare; use trans::expr; use trans::glue; use trans::inline; @@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); // - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, - "fn_pointer_shim"); - let llfn = - decl_internal_rust_fn(ccx, - tuple_fn_ty, - &function_name[..]); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, + "fn_pointer_shim"); + let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty); // let empty_substs = tcx.mk_substs(Substs::trans_empty()); diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 19891e9307229..61af5bfaef8de 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -126,6 +126,7 @@ use trans::callee; 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 @@ impl<'blk, 'tcx> CleanupHelperMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx Some(llpersonality) => llpersonality, None => { let fty = Type::variadic_func(&[], &Type::i32(self.ccx)); - let f = base::decl_cdecl_fn(self.ccx, - "rust_eh_personality", - fty, - self.ccx.tcx().types.i32); + let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty, + self.ccx.tcx().types.i32); *personality = Some(f); f } diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index c1aade3663e6e..eb4acec25510a 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -13,6 +13,7 @@ use back::link::{self, mangle_internal_name_by_path_and_seq}; use llvm::{ValueRef, get_param}; use middle::mem_categorization::Typer; use trans::adt; +use trans::attributes; use trans::base::*; use trans::build::*; use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData}; @@ -20,6 +21,7 @@ use trans::cleanup::{CleanupMethods, CustomScope, ScopeId}; 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::*; @@ -161,10 +163,14 @@ 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 - set_inline_hint(llfn); + attributes::inline(llfn, attributes::InlineAttr::Hint); debug!("get_or_create_declaration_if_closure(): inserting new \ closure {:?} (type {})", @@ -380,7 +386,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( // Create the by-value helper. let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim"); - let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name); + let lloncefn = declare::define_internal_rust_fn(ccx, &function_name[..], llonce_fn_ty) + .unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig); let (block_arena, fcx): (TypedArena<_>, FunctionContext); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 2c8da2dc31c5d..168a294159d4f 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -31,6 +31,7 @@ use trans::cleanup; use trans::consts; use trans::datum; use trans::debuginfo::{self, DebugLoc}; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -871,9 +872,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va !null_terminated as Bool); let gsym = token::gensym("str"); - let buf = CString::new(format!("str{}", gsym.usize())); - let buf = buf.unwrap(); - let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr()); + let sym = format!("str{}", gsym.usize()); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + cx.sess().bug(&format!("symbol `{}` is already defined", sym)); + }); llvm::LLVMSetInitializer(g, sc); llvm::LLVMSetGlobalConstant(g, True); llvm::SetLinkage(g, llvm::InternalLinkage); diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index c32cb28ec78db..aff5f597bfd9f 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -25,6 +25,7 @@ use middle::const_eval::{const_int_checked_shr, const_uint_checked_shr}; use trans::{adt, closure, debuginfo, expr, inline, machine}; use trans::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 util::ppaux::{Repr, ty_to_string}; 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) @@ -83,7 +85,7 @@ pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit) ast::LitBool(b) => C_bool(cx, b), ast::LitStr(ref s, _) => C_str_slice(cx, (*s).clone()), ast::LitBinary(ref data) => { - addr_of(cx, C_bytes(cx, &data[..]), "binary", e.id) + addr_of(cx, C_bytes(cx, &data[..]), "binary") } } } @@ -96,13 +98,16 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { fn addr_of_mut(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { unsafe { - let name = format!("{}{}\0", kind, id); - let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(), - name.as_ptr() as *const _); + // FIXME: this totally needs a better name generation scheme, perhaps a simple global + // counter? Also most other uses of gensym in trans. + let gsym = token::gensym("_"); + let name = format!("{}{}", kind, gsym.usize()); + let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", name)); + }); llvm::LLVMSetInitializer(gv, cv); SetLinkage(gv, InternalLinkage); SetUnnamedAddr(gv, true); @@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext, pub fn addr_of(ccx: &CrateContext, cv: ValueRef, - kind: &str, - id: ast::NodeId) + kind: &str) -> ValueRef { match ccx.const_globals().borrow().get(&cv) { Some(&gv) => return gv, None => {} } - let gv = addr_of_mut(ccx, cv, kind, id); + let gv = addr_of_mut(ccx, cv, kind); unsafe { llvm::LLVMSetGlobalConstant(gv, True); } @@ -233,7 +237,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } }; - let lvalue = addr_of(ccx, val, "const", expr.id); + let lvalue = addr_of(ccx, val, "const"); ccx.const_values().borrow_mut().insert(key, lvalue); lvalue } @@ -284,7 +288,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, if adj.autoderefs == 0 { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). - llconst = addr_of(cx, llconst, "autoref", e.id); + llconst = addr_of(cx, llconst, "autoref"); } else { // Seeing as we are deref'ing here and take a reference // again to make the pointer part of the far pointer below, @@ -312,7 +316,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, None => {} Some(box ty::AutoUnsafe(_, None)) | Some(box ty::AutoPtr(_, _, None)) => { - llconst = addr_of(cx, llconst, "autoref", e.id); + llconst = addr_of(cx, llconst, "autoref"); } Some(box ty::AutoUnsize(ref k)) => { let info = @@ -711,12 +715,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, // If this isn't the address of a static, then keep going through // normal constant evaluation. let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of(cx, v, "ref", e.id) + addr_of(cx, v, "ref") } } ast::ExprAddrOf(ast::MutMutable, ref sub) => { let (v, _) = const_expr(cx, &**sub, param_substs); - addr_of_mut(cx, v, "ref_mut_slice", e.id) + addr_of_mut(cx, v, "ref_mut_slice") } ast::ExprTup(ref es) => { let repr = adt::represent_type(cx, ety); @@ -862,7 +866,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, } } -pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { +pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> ValueRef { unsafe { let _icx = push_ctxt("trans_static"); let g = base::get_item_val(ccx, id); @@ -888,6 +892,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) { } } debuginfo::create_global_var_metadata(ccx, id, g); + g } } diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 8919a386a45fb..e54962dc08552 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -20,6 +20,7 @@ use trans::base; use trans::builder::Builder; use trans::common::{ExternMap,BuilderRef_res}; use trans::debuginfo; +use trans::declare; use trans::monomorphize::MonoId; use trans::type_::{Type, TypeNames}; use middle::subst::Substs; @@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> { llsizingtypes: RefCell, Type>>, adt_reprs: RefCell, Rc>>>, type_hashcodes: RefCell, String>>, - all_llvm_symbols: RefCell>, int_type: Type, opaque_vec_type: Type, builder: BuilderRef_res, @@ -413,7 +413,6 @@ impl<'tcx> LocalCrateContext<'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 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { &self.local.type_hashcodes } - pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell> { - &self.local.all_llvm_symbols - } - pub fn stats<'a>(&'a self) -> &'a Stats { &self.shared.stats } @@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn( - ccx, $name, Type::func(&[], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } ); ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( if *key == $name { - let f = base::decl_cdecl_fn(ccx, $name, - Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } @@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option $ret); } else if *key == $name { - let f = base::decl_cdecl_fn(ccx, stringify!($cname), - Type::func(&[$($arg),*], &$ret), - ty::mk_nil(ccx.tcx())); + let f = declare::declare_cfn(ccx, stringify!($cname), + Type::func(&[$($arg),*], &$ret), + ty::mk_nil(ccx.tcx())); ccx.intrinsics().borrow_mut().insert($name, f.clone()); return Some(f); } diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index d1ecc1d6ddfb6..f544efe7401c4 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -416,8 +416,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, @@ -449,8 +448,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let filename = C_str_slice(ccx, filename); let line = C_u32(ccx, loc.line as u32); let file_line_const = C_struct(ccx, &[filename, line], false); - let file_line = consts::addr_of(ccx, file_line_const, - "panic_bounds_check_loc", call_info.id); + let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc"); let args = vec!(file_line, index, len); let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem); let bcx = callee::trans_lang_call(bcx, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 9efb91e0c1d73..a59616d09b1c1 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -196,8 +196,9 @@ use llvm::debuginfo::*; 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; @@ -4067,7 +4068,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(), @@ -4081,10 +4082,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext) unsafe { let llvm_type = Type::array(&Type::i8(ccx), section_contents.len() as u64); - let section_var = llvm::LLVMAddGlobal(ccx.llmod(), - llvm_type.to_ref(), - section_var_name.as_ptr() - as *const _); + + let section_var = declare::define_global(ccx, section_var_name, + llvm_type).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name)) + }); llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _); llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents)); llvm::LLVMSetGlobalConstant(section_var, llvm::True); diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs new file mode 100644 index 0000000000000..9e7449f670f0f --- /dev/null +++ b/src/librustc_trans/trans/declare.rs @@ -0,0 +1,261 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +//! Declare various LLVM values. +//! +//! Prefer using functions and methods from this module rather than calling LLVM functions +//! directly. These functions do some additional work to ensure we do the right thing given +//! the preconceptions of trans. +//! +//! Some useful guidelines: +//! +//! * Use declare_* family of methods if you are declaring, but are not interested in defining the +//! ValueRef they return. +//! * Use define_* family of methods when you might be defining the ValueRef. +//! * When in doubt, define. +use llvm::{self, ValueRef}; +use middle::ty::{self, ClosureTyper}; +use syntax::abi; +use trans::attributes; +use trans::base; +use trans::common; +use trans::context::CrateContext; +use trans::monomorphize; +use trans::type_::Type; +use trans::type_of; +use util::ppaux::Repr; + +use std::ffi::CString; +use libc::c_uint; + + +/// Declare a global value. +/// +/// If there’s a value with the same name already declared, the function will return its ValueRef +/// instead. +pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef { + debug!("declare_global(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + unsafe { + llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + } +} + + +/// Declare a function. +/// +/// For rust functions use `declare_rust_fn` instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type, + output: ty::FnOutput) -> ValueRef { + debug!("declare_fn(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let llfn = unsafe { + llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref()) + }; + + llvm::SetFunctionCallConv(llfn, callconv); + // Function addresses in Rust are never significant, allowing functions to be merged. + llvm::SetUnnamedAddr(llfn, true); + + if output == ty::FnDiverging { + llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute); + } + + if ccx.tcx().sess.opts.cg.no_redzone + .unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) { + llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute) + } + + if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check { + attributes::split_stack(llfn, true); + } + llfn +} + + +/// Declare a C ABI function. +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef { + declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output)) +} + + +/// Declare a Rust function. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx())); + let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type); + debug!("declare_rust_fn (after normalised associated types) fn_type={}", + fn_type.repr(ccx.tcx())); + + let function_type; // placeholder so that the memory ownership works out ok + let (sig, abi, env) = match fn_type.sty { + ty::ty_bare_fn(_, ref f) => { + (&f.sig, f.abi, None) + } + ty::ty_closure(closure_did, substs) => { + let typer = common::NormalizingClosureTyper::new(ccx.tcx()); + function_type = typer.closure_type(closure_did, substs); + let self_type = base::self_type_for_closure(ccx, closure_did, fn_type); + let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type); + debug!("declare_rust_fn function_type={} self_type={}", + function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx())); + (&function_type.sig, abi::RustCall, Some(llenvironment_type)) + } + _ => ccx.sess().bug("expected closure or fn") + }; + + let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig)); + debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx())); + let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi); + debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty)); + + // it is ok to directly access sig.0.output because we erased all late-bound-regions above + let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output); + attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn); + llfn +} + + +/// Declare a Rust function with internal linkage. +/// +/// If there’s a value with the same name already declared, the function will update the +/// declaration and return existing ValueRef instead. +pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> ValueRef { + let llfn = declare_rust_fn(ccx, name, fn_type); + llvm::SetLinkage(llfn, llvm::InternalLinkage); + llfn +} + + +/// Declare a global with an intention to define it. +/// +/// Use this function when you intend to define a global. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_global(ccx, name, ty)) + } +} + + +/// Declare a function with an intention to define it. +/// +/// For rust functions use `define_rust_fn` instead. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type, + output: ty::FnOutput) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_fn(ccx, name, callconv, fn_type, output)) + } +} + + +/// Declare a C ABI function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +/// +/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn` +/// instead. +pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type, + output: ty::Ty) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_cfn(ccx, name, fn_type, output)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_rust_fn(ccx, name, fn_type)) + } +} + + +/// Declare a Rust function with an intention to define it. +/// +/// Use this function when you intend to define a function. This function will return None if the +/// name already has a definition associated with it. In that case an error should be reported to +/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or +/// #[export_name] attributes). +pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str, + fn_type: ty::Ty<'tcx>) -> Option { + if get_defined_value(ccx, name).is_some() { + None + } else { + Some(declare_internal_rust_fn(ccx, name, fn_type)) + } +} + + +/// Get defined or externally defined (AvailableExternally linkage) value by name. +fn get_defined_value(ccx: &CrateContext, name: &str) -> Option { + debug!("get_defined_value(name={:?})", name); + let namebuf = CString::new(name).unwrap_or_else(|_|{ + ccx.sess().bug(&format!("name {:?} contains an interior null byte", name)) + }); + let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) }; + if val.is_null() { + debug!("get_defined_value: {:?} value is null", name); + None + } else { + let (declaration, aext_link) = unsafe { + let linkage = llvm::LLVMGetLinkage(val); + (llvm::LLVMIsDeclaration(val) != 0, + linkage == llvm::AvailableExternallyLinkage as c_uint) + }; + debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name, + declaration, aext_link); + if !declaration || aext_link { + Some(val) + } else { + None + } + } +} diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs index e87a5865df054..8f3a51a500709 100644 --- a/src/librustc_trans/trans/foreign.rs +++ b/src/librustc_trans/trans/foreign.rs @@ -13,12 +13,14 @@ use back::link; use llvm::{ValueRef, CallConv, get_param}; use llvm; use middle::weak_lang_items; +use trans::attributes; use trans::base::{llvm_linkage_by_name, push_ctxt}; use trans::base; use trans::build::*; use trans::cabi; use trans::common::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::machine; use trans::monomorphize; use trans::type_::Type; @@ -27,7 +29,6 @@ use trans::type_of; 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}; @@ -135,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 @@ -148,20 +147,35 @@ 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), + } +} + +// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions +pub fn get_extern_fn(ccx: &CrateContext, + externs: &mut ExternMap, + name: &str, + cc: llvm::CallConv, + ty: Type, + output: Ty) + -> ValueRef { + match externs.get(name) { + Some(n) => return *n, + None => {} } + let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output)); + externs.insert(name.to_string(), f); + f } /// Registers a foreign function found in a library. Just adds a LLVM global. @@ -189,14 +203,8 @@ pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Create the LLVM value for the C extern fn let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys); - let llfn = base::get_extern_fn(ccx, - &mut *ccx.externs().borrow_mut(), - name, - cc, - llfn_ty, - fty); + let llfn = get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), name, cc, llfn_ty, fty); add_argument_attributes(&tys, llfn); - llfn } @@ -471,7 +479,7 @@ pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) { } let llfn = register_foreign_item_fn(ccx, abi, ty, &lname); - base::set_llvm_fn_attrs(ccx, &foreign_item.attrs, llfn); + attributes::from_fn_attrs(ccx, &foreign_item.attrs, llfn); // Unlike for other items, we shouldn't call // `base::update_linkage` here. Foreign items have // special linkage requirements, which are handled @@ -522,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)); @@ -611,8 +620,10 @@ pub fn trans_rust_fn_with_foreign_abi<'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[..]); - base::set_llvm_fn_attrs(ccx, attrs, llfn); + 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 } @@ -642,6 +653,11 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // return r; // } + if llvm::LLVMCountBasicBlocks(llwrapfn) != 0 { + ccx.sess().bug("wrapping a function inside non-empty wrapper, most likely cause is \ + multiple functions being wrapped"); + } + let ptr = "the block\0".as_ptr(); let the_block = llvm::LLVMAppendBasicBlockInContext(ccx.llcx(), llwrapfn, ptr as *const _); @@ -800,7 +816,7 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, // Perform the call itself debug!("calling llrustfn = {}, t = {}", ccx.tn().val_to_string(llrustfn), t.repr(ccx.tcx())); - let attributes = base::get_fn_llvm_attributes(ccx, t); + let attributes = attributes::from_fn_type(ccx, t); let llrust_ret_val = builder.call(llrustfn, &llrust_args, Some(attributes)); // Get the return value where the foreign fn expects it. diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 32b4d14177c2a..f974796e69cad 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -15,11 +15,13 @@ use back::abi; use back::link::*; -use llvm::{ValueRef, get_param}; use llvm; +use llvm::{ValueRef, get_param}; +use metadata::csearch; use middle::lang_items::ExchangeFreeFnLangItem; use middle::subst; use middle::subst::{Subst, Substs}; +use middle::ty::{self, Ty}; use trans::adt; use trans::adt::GetDtorType; // for tcx.dtor_type() use trans::base::*; @@ -30,13 +32,16 @@ use trans::cleanup::CleanupMethods; use trans::common::*; use trans::datum; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr; +use trans::foreign; +use trans::inline; use trans::machine::*; +use trans::monomorphize; +use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of}; use trans::type_::Type; -use trans::type_of::{type_of, sizing_type_of, align_of}; -use middle::ty::{self, Ty}; -use util::ppaux::{ty_to_short_str, Repr}; use util::ppaux; +use util::ppaux::{ty_to_short_str, Repr}; use arena::TypedArena; use libc::c_uint; @@ -178,14 +183,15 @@ 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; }; let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "drop"); - let llfn = decl_cdecl_fn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())); - note_unique_llvm_symbol(ccx, fn_nm.clone()); + let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ty::mk_nil(ccx.tcx())).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm)); + }); ccx.available_drop_glues().borrow_mut().insert(t, fn_nm); let _s = StatRecorder::new(ccx, format!("drop {}", ty_to_short_str(ccx.tcx(), t))); @@ -259,6 +265,40 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, } +pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, + did: ast::DefId, + t: Ty<'tcx>, + parent_id: ast::DefId, + substs: &Substs<'tcx>) + -> ValueRef { + let _icx = push_ctxt("trans_res_dtor"); + let did = inline::maybe_instantiate_inline(ccx, did); + + if !substs.types.is_empty() { + assert_eq!(did.krate, ast::LOCAL_CRATE); + + // Since we're in trans we don't care for any region parameters + let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone())); + + let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None); + + val + } else if did.krate == ast::LOCAL_CRATE { + get_item_val(ccx, did.node) + } else { + let tcx = ccx.tcx(); + let name = csearch::get_symbol(&ccx.sess().cstore, did); + let class_ty = ty::lookup_item_type(tcx, parent_id).ty.subst(tcx, substs); + let llty = type_of_dtor(ccx, class_ty); + let dtor_ty = ty::mk_ctor_fn(ccx.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) + } +} + fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, v0: ValueRef, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 190e44c9674cb..e2f965a95fff7 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -28,6 +28,7 @@ use trans::common::*; use trans::consts; use trans::datum::*; use trans::debuginfo::DebugLoc; +use trans::declare; use trans::expr::SaveIn; use trans::expr; use trans::glue; @@ -590,10 +591,10 @@ pub fn trans_object_shim<'a, 'tcx>( // let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty); let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty); - let function_name = - link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); - let llfn = - decl_internal_rust_fn(ccx, shim_fn_ty, &function_name); + let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim"); + let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{ + ccx.sess().bug(&format!("symbol `{}` already defined", function_name)); + }); let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig); @@ -756,8 +757,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, C_uint(ccx, align) ].into_iter().chain(methods).collect(); - let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), - "vtable", trait_ref.def_id().node); + let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable"); ccx.vtables().borrow_mut().insert(trait_ref, vtable); vtable diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index c7857d6a775f3..7d568ff90ea43 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -19,43 +19,45 @@ pub use self::common::gensym_name; #[macro_use] mod macros; -mod inline; -mod monomorphize; -mod controlflow; -mod glue; -mod datum; -mod callee; -mod expr; -mod common; -mod context; -mod consts; -mod type_of; +mod adt; +mod asm; +mod attributes; +mod base; +mod basic_block; mod build; mod builder; -mod base; -mod _match; -mod closure; -mod tvec; -mod meth; mod cabi; -mod cabi_x86; -mod cabi_x86_64; -mod cabi_x86_win64; -mod cabi_arm; mod cabi_aarch64; +mod cabi_arm; mod cabi_mips; mod cabi_powerpc; +mod cabi_x86; +mod cabi_x86_64; +mod cabi_x86_win64; +mod callee; +mod cleanup; +mod closure; +mod common; +mod consts; +mod context; +mod controlflow; +mod datum; +mod debuginfo; +mod declare; +mod expr; mod foreign; +mod glue; +mod inline; mod intrinsic; -mod debuginfo; +mod llrepr; mod machine; -mod adt; -mod asm; +mod _match; +mod meth; +mod monomorphize; +mod tvec; mod type_; +mod type_of; mod value; -mod basic_block; -mod llrepr; -mod cleanup; #[derive(Copy, Clone)] pub struct ModuleTranslation { diff --git a/src/librustc_trans/trans/monomorphize.rs b/src/librustc_trans/trans/monomorphize.rs index dcb21c5cd93b1..1c8d020494fab 100644 --- a/src/librustc_trans/trans/monomorphize.rs +++ b/src/librustc_trans/trans/monomorphize.rs @@ -17,11 +17,12 @@ use middle::subst; use middle::subst::{Subst, Substs}; use middle::traits; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use trans::base::{set_llvm_fn_attrs, set_inline_hint}; +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); @@ -151,7 +155,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, }; let setup_lldecl = |lldecl, attrs: &[ast::Attribute]| { base::update_linkage(ccx, lldecl, None, base::OriginalTranslation); - set_llvm_fn_attrs(ccx, attrs, lldecl); + attributes::from_fn_attrs(ccx, attrs, lldecl); let is_first = !ccx.available_monomorphizations().borrow().contains(&s); if is_first { @@ -200,7 +204,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, let tvs = ty::enum_variants(ccx.tcx(), local_def(parent)); let this_tv = tvs.iter().find(|tv| { tv.id.node == fn_id.node}).unwrap(); let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineAttr::Hint); match v.node.kind { ast::TupleVariantKind(ref args) => { trans_enum_variant(ccx, @@ -259,7 +263,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, } ast_map::NodeStructCtor(struct_def) => { let d = mk_lldecl(abi::Rust); - set_inline_hint(d); + attributes::inline(d, attributes::InlineAttr::Hint); base::trans_tuple_struct(ccx, &struct_def.fields, struct_def.ctor_id.expect("ast-mapped tuple struct \ diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 29b0716c8174f..755dd3bb4586f 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -282,6 +282,23 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } +/// Find the value of #[export_name=*] attribute and check its validity. +pub fn find_export_name_attr(diag: &SpanHandler, attrs: &[Attribute]) -> Option { + attrs.iter().fold(None, |ia,attr| { + if attr.check_name("export_name") { + if let s@Some(_) = attr.value_str() { + s + } else { + diag.span_err(attr.span, "export_name attribute has invalid format"); + diag.handler.help("use #[export_name=\"*\"]"); + None + } + } else { + ia + } + }) +} + #[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 9a87c03f1c407..31f75ae03b099 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -77,6 +77,11 @@ extern "C" void LLVMRustPrintPassTimings() { TimerGroup::printAll(OS); } +extern "C" LLVMValueRef LLVMGetNamedValue(LLVMModuleRef M, + const char* Name) { + return wrap(unwrap(M)->getNamedValue(Name)); +} + extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, const char* Name, LLVMTypeRef FunctionTy) { @@ -84,6 +89,12 @@ extern "C" LLVMValueRef LLVMGetOrInsertFunction(LLVMModuleRef M, unwrap(FunctionTy))); } +extern "C" LLVMValueRef LLVMGetOrInsertGlobal(LLVMModuleRef M, + const char* Name, + LLVMTypeRef Ty) { + return wrap(unwrap(M)->getOrInsertGlobal(Name, unwrap(Ty))); +} + extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) { return wrap(Type::getMetadataTy(*unwrap(C))); } diff --git a/src/test/compile-fail/dupe-symbols-1.rs b/src/test/compile-fail/dupe-symbols-1.rs new file mode 100644 index 0000000000000..9fa4eafcad0ed --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-1.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-2.rs b/src/test/compile-fail/dupe-symbols-2.rs new file mode 100644 index 0000000000000..976a65589b869 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-2.rs @@ -0,0 +1,25 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +#![crate_type="rlib"] +#![allow(warnings)] + +mod a { + #[no_mangle] + pub extern fn fail() { + } +} + +mod b { + #[no_mangle] + pub extern fn fail() { + //~^ symbol `fail` is already defined + } +} diff --git a/src/test/compile-fail/dupe-symbols-3.rs b/src/test/compile-fail/dupe-symbols-3.rs new file mode 100644 index 0000000000000..98a61c33c584a --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-3.rs @@ -0,0 +1,21 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +pub fn a() { +} + +#[no_mangle] +pub fn fail() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-4.rs b/src/test/compile-fail/dupe-symbols-4.rs new file mode 100644 index 0000000000000..9e730699d2514 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-4.rs @@ -0,0 +1,31 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// error-pattern: symbol `fail` is already defined +#![crate_type="rlib"] +#![allow(warnings)] + + +pub trait A { + fn fail(self); +} + +struct B; +struct C; + +impl A for B { + #[no_mangle] + fn fail(self) {} +} + +impl A for C { + #[no_mangle] + fn fail(self) {} +} diff --git a/src/test/compile-fail/dupe-symbols-5.rs b/src/test/compile-fail/dupe-symbols-5.rs new file mode 100644 index 0000000000000..eb4b50d03ca65 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-5.rs @@ -0,0 +1,20 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +pub fn b() { +//~^ symbol `fail` is already defined +} diff --git a/src/test/compile-fail/dupe-symbols-6.rs b/src/test/compile-fail/dupe-symbols-6.rs new file mode 100644 index 0000000000000..6f412d9a0de15 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-6.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +#![crate_type="rlib"] +#![allow(warnings)] + +#[export_name="fail"] +static HELLO: u8 = 0; + +#[export_name="fail"] +static HELLO_TWICE: u16 = 0; +//~^ symbol `fail` is already defined diff --git a/src/test/compile-fail/dupe-symbols-7.rs b/src/test/compile-fail/dupe-symbols-7.rs new file mode 100644 index 0000000000000..c2880ba6f51e9 --- /dev/null +++ b/src/test/compile-fail/dupe-symbols-7.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// error-pattern: entry symbol `main` defined multiple times +#![allow(warnings)] + +#[no_mangle] +fn main(){} diff --git a/src/test/run-pass/issue-15562.rs b/src/test/run-pass/issue-15562.rs index f1ef57e44b1d5..da1e15d826d99 100644 --- a/src/test/run-pass/issue-15562.rs +++ b/src/test/run-pass/issue-15562.rs @@ -15,9 +15,6 @@ extern crate issue_15562 as i; pub fn main() { - extern { - fn transmute(); - } unsafe { transmute(); i::transmute();