Auto merge of #23011 - nagisa:the-war-of-symbol-and-symbol, r=pnkfelix

We provide tools to tell what exact symbols to emit for any fn or static, but
don’t quite check if that won’t cause any issues later on. Some of the issues
include LLVM mangling our names again and our names pointing to wrong locations,
us generating dumb foreign call wrappers, linker errors, extern functions
resolving to different symbols altogether (`extern {fn fail();} fail();` in some
cases calling `fail1()`), etc.

Before the commit we had a function called `note_unique_llvm_symbol`, so it is
clear somebody was aware of the issue at some point, but the function was barely
used, mostly in irrelevant locations.

Along with working on it I took liberty to start refactoring trans/base into
a few smaller modules. The refactoring is incomplete and I hope I will find some
motivation to carry on with it.

This is possibly a [breaking-change] because it makes dumbly written code
properly invalid.

This fixes all those issues about incorrect use of #[no_mangle] being not reported/misreported/ICEd by the compiler.

NB. This PR does not attempt to tackle the parallel codegen issue that was mentioned in https://github.com/rust-lang/rust/pull/22811, but I believe it should be very straightforward in a follow up PR by modifying `trans::declare::get_defined_value` to look at all the contexts.

cc @alexcrichton @huonw @nrc because you commented on the original RFC issue.

EDIT: wow, this became much bigger than I initially intended.
This commit is contained in:
bors 2015-04-12 01:26:53 +00:00
commit 5afa2704a6
27 changed files with 1038 additions and 670 deletions

View File

@ -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;

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! 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<U>` 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
}

View File

@ -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 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// 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<U>` 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");

View File

@ -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());

View File

@ -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
}

View File

@ -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 theres 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);

View File

@ -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);

View File

@ -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
}
}

View File

@ -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<FnvHashMap<Ty<'tcx>, Type>>,
adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>,
type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>,
all_llvm_symbols: RefCell<FnvHashSet<String>>,
int_type: Type,
opaque_vec_type: Type,
builder: BuilderRef_res,
@ -413,7 +413,6 @@ 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<FnvHashSet<String>> {
&self.local.all_llvm_symbols
}
pub fn stats<'a>(&'a self) -> &'a Stats {
&self.shared.stats
}
@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => (
if *key == $name {
let f = base::decl_cdecl_fn(
ccx, $name, Type::func(&[], &$ret),
ty::mk_nil(ccx.tcx()));
let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret),
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f);
}
);
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
if *key == $name {
let f = base::decl_cdecl_fn(ccx, $name,
Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx()));
let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret),
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f);
}
@ -888,9 +882,9 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
// The `if key == $name` is already in ifn!
ifn!($name, fn($($arg),*) -> $ret);
} else if *key == $name {
let f = base::decl_cdecl_fn(ccx, stringify!($cname),
Type::func(&[$($arg),*], &$ret),
ty::mk_nil(ccx.tcx()));
let f = declare::declare_cfn(ccx, stringify!($cname),
Type::func(&[$($arg),*], &$ret),
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f);
}

View File

@ -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,

View File

@ -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);

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Declare various LLVM values.
//!
//! Prefer using functions and methods from this module rather than calling LLVM functions
//! directly. These functions do some additional work to ensure we do the right thing given
//! the preconceptions of trans.
//!
//! Some useful guidelines:
//!
//! * Use declare_* family of methods if you are declaring, but are not interested in defining the
//! ValueRef they return.
//! * Use define_* family of methods when you might be defining the ValueRef.
//! * When in doubt, define.
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 theres 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 theres 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 theres 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 theres 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 theres 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 users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_global(ccx, name, ty))
}
}
/// Declare a function with an intention to define it.
///
/// For rust functions use `define_rust_fn` instead.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users 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 users 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 users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_rust_fn(ccx, name, fn_type))
}
}
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to users fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_internal_rust_fn(ccx, name, fn_type))
}
}
/// Get defined or externally defined (AvailableExternally linkage) value by name.
fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
debug!("get_defined_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) };
if val.is_null() {
debug!("get_defined_value: {:?} value is null", name);
None
} else {
let (declaration, aext_link) = unsafe {
let linkage = llvm::LLVMGetLinkage(val);
(llvm::LLVMIsDeclaration(val) != 0,
linkage == llvm::AvailableExternallyLinkage as c_uint)
};
debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name,
declaration, aext_link);
if !declaration || aext_link {
Some(val)
} else {
None
}
}
}

View File

@ -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,22 +147,37 @@ 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.
pub fn register_foreign_item_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
abi: Abi, fty: Ty<'tcx>,
@ -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.

View File

@ -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,

View File

@ -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

View File

@ -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_aarch64;
mod cabi_arm;
mod cabi_mips;
mod cabi_powerpc;
mod cabi_x86;
mod cabi_x86_64;
mod cabi_x86_win64;
mod cabi_arm;
mod cabi_aarch64;
mod cabi_mips;
mod cabi_powerpc;
mod foreign;
mod intrinsic;
mod debuginfo;
mod machine;
mod adt;
mod asm;
mod type_;
mod value;
mod basic_block;
mod llrepr;
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 llrepr;
mod machine;
mod _match;
mod meth;
mod monomorphize;
mod tvec;
mod type_;
mod type_of;
mod value;
#[derive(Copy, Clone)]
pub struct ModuleTranslation {

View File

@ -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 \

View File

@ -282,6 +282,23 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<InternedString> {
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<InternedString> {
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,

View File

@ -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<FunctionType>(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)));
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
#![crate_type="rlib"]
#![allow(warnings)]
#[export_name="fail"]
pub fn a() {
}
#[export_name="fail"]
pub fn b() {
//~^ symbol `fail` is already defined
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
#![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
}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
#![crate_type="rlib"]
#![allow(warnings)]
#[export_name="fail"]
pub fn a() {
}
#[no_mangle]
pub fn fail() {
//~^ symbol `fail` is already defined
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// 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) {}
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
#![crate_type="rlib"]
#![allow(warnings)]
#[export_name="fail"]
static HELLO: u8 = 0;
#[export_name="fail"]
pub fn b() {
//~^ symbol `fail` is already defined
}

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![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

View File

@ -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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// error-pattern: entry symbol `main` defined multiple times
#![allow(warnings)]
#[no_mangle]
fn main(){}

View File

@ -15,9 +15,6 @@
extern crate issue_15562 as i;
pub fn main() {
extern {
fn transmute();
}
unsafe {
transmute();
i::transmute();