提交 f1dabed8 编写于 作者: S Simonas Kazlauskas

Introduce trans::declare

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.
上级 caea0449
......@@ -64,6 +64,7 @@
use trans::controlflow;
use trans::datum;
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
use trans::declare;
use trans::expr;
use trans::foreign;
use trans::glue;
......@@ -179,44 +180,6 @@ fn drop(&mut self) {
}
}
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
ty: Type, output: ty::FnOutput) -> ValueRef {
let buf = CString::new(name).unwrap();
let llfn: ValueRef = unsafe {
llvm::LLVMGetOrInsertFunction(ccx.llmod(), buf.as_ptr(), ty.to_ref())
};
// diverging functions may unwind, but can never return normally
if output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
}
if ccx.tcx().sess.opts.cg.no_redzone
.unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute)
}
llvm::SetFunctionCallConv(llfn, cc);
// Function addresses in Rust are never significant, allowing functions to be merged.
llvm::SetUnnamedAddr(llfn, true);
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
attributes::split_stack(llfn, true);
}
llfn
}
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_cdecl_fn(ccx: &CrateContext,
name: &str,
ty: Type,
output: Ty) -> ValueRef {
decl_fn(ccx, name, llvm::CCallConv, ty, ty::FnConverging(output))
}
fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
name: &str, did: ast::DefId) -> ValueRef {
match ccx.externs().borrow().get(name) {
......@@ -224,7 +187,7 @@ fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_ty: Ty<'tcx>,
None => ()
}
let f = decl_rust_fn(ccx, fn_ty, name);
let f = declare::declare_rust_fn(ccx, name, fn_ty);
let attrs = csearch::get_item_attrs(&ccx.sess().cstore, did);
attributes::from_fn_attrs(ccx, &attrs[..], f);
......@@ -254,63 +217,6 @@ pub fn kind_for_closure(ccx: &CrateContext, closure_id: ast::DefId) -> ty::Closu
*ccx.tcx().closure_kinds.borrow().get(&closure_id).unwrap()
}
pub fn decl_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
debug!("decl_rust_fn(fn_ty={}, name={:?})",
fn_ty.repr(ccx.tcx()),
name);
let fn_ty = monomorphize::normalize_associated_type(ccx.tcx(), &fn_ty);
debug!("decl_rust_fn: fn_ty={} (after normalized associated types)",
fn_ty.repr(ccx.tcx()));
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_ty.sty {
ty::ty_bare_fn(_, ref f) => {
(&f.sig, f.abi, None)
}
ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = self_type_for_closure(ccx, closure_did, fn_ty);
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
debug!("decl_rust_fn: function_type={} self_type={}",
function_type.repr(ccx.tcx()),
self_type.repr(ccx.tcx()));
(&function_type.sig, RustCall, Some(llenvironment_type))
}
_ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::erase_late_bound_regions(ccx.tcx(), sig);
let sig = ty::Binder(sig);
debug!("decl_rust_fn: sig={} (after erasing regions)",
sig.repr(ccx.tcx()));
let llfty = type_of_rust_fn(ccx, env, &sig, abi);
debug!("decl_rust_fn: llfty={}",
ccx.tn().type_to_string(llfty));
let llfn = decl_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output /* (1) */);
let attrs = get_fn_llvm_attributes(ccx, fn_ty);
attrs.apply_llfn(llfn);
// (1) it's ok to directly access sig.0.output because we erased all late-bound-regions above
llfn
}
pub fn decl_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_ty: Ty<'tcx>, name: &str) -> ValueRef {
let llfn = decl_rust_fn(ccx, fn_ty, name);
llvm::SetLinkage(llfn, llvm::InternalLinkage);
llfn
}
pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
t: Ty<'tcx>) -> ValueRef {
let name = csearch::get_symbol(&ccx.sess().cstore, did);
......@@ -319,23 +225,22 @@ pub fn get_extern_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, did: ast::DefId,
Some(n) => return *n,
None => ()
}
unsafe {
let buf = CString::new(name.clone()).unwrap();
let c = llvm::LLVMAddGlobal(ccx.llmod(), ty.to_ref(), buf.as_ptr());
// Thread-local statics in some other crate need to *always* be linked
// against in a thread-local fashion, so we need to be sure to apply the
// thread-local attribute locally if it was present remotely. If we
// don't do this then linker errors can be generated where the linker
// complains that one object files has a thread local version of the
// symbol and another one doesn't.
for attr in &*ty::get_attrs(ccx.tcx(), did) {
if attr.check_name("thread_local") {
llvm::set_thread_local(c, true);
}
// FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
// FIXME(nagisa): investigate whether it can be changed into define_global
let c = declare::declare_global(ccx, &name[..], ty);
// Thread-local statics in some other crate need to *always* be linked
// against in a thread-local fashion, so we need to be sure to apply the
// thread-local attribute locally if it was present remotely. If we
// don't do this then linker errors can be generated where the linker
// complains that one object files has a thread local version of the
// symbol and another one doesn't.
for attr in &*ty::get_attrs(ccx.tcx(), did) {
if attr.check_name("thread_local") {
llvm::set_thread_local(c, true);
}
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
}
ccx.externs().borrow_mut().insert(name.to_string(), c);
return c;
}
fn require_alloc_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
......@@ -373,15 +278,6 @@ pub fn malloc_raw_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
}
// Double-check that we never ask LLVM to declare the same symbol twice. It
// silently mangles such symbols, breaking our linkage model.
pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: String) {
if ccx.all_llvm_symbols().borrow().contains(&sym) {
ccx.sess().bug(&format!("duplicate LLVM symbol: {}", sym));
}
ccx.all_llvm_symbols().borrow_mut().insert(sym);
}
pub fn bin_op_to_icmp_predicate(ccx: &CrateContext, op: ast::BinOp_, signed: bool)
-> llvm::IntPredicate {
match op {
......@@ -1713,15 +1609,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let fn_ty = ty::node_id_to_type(ccx.tcx(), id);
let output_type = ty::erase_late_bound_regions(ccx.tcx(), &ty::ty_fn_ret(fn_ty));
let abi = ty::ty_fn_abi(fn_ty);
trans_closure(ccx,
decl,
body,
llfndecl,
param_substs,
id,
attrs,
output_type,
abi,
trans_closure(ccx, decl, body, llfndecl, param_substs, id, attrs, output_type, abi,
closure::ClosureEnv::NotClosure);
}
......@@ -2066,27 +1954,24 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let llfn = get_item_val(ccx, item.id);
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
if abi != Rust {
foreign::trans_rust_fn_with_foreign_abi(ccx,
&**decl,
&**body,
&item.attrs,
llfn,
empty_substs,
item.id,
None);
foreign::trans_rust_fn_with_foreign_abi(ccx, &**decl, &**body, &item.attrs,
llfn, empty_substs, item.id, None);
} else {
trans_fn(ccx,
&**decl,
&**body,
llfn,
empty_substs,
item.id,
&item.attrs);
trans_fn(ccx, &**decl, &**body, llfn, empty_substs, item.id, &item.attrs);
}
update_linkage(ccx,
llfn,
Some(item.id),
update_linkage(ccx, llfn, Some(item.id),
if is_origin { OriginalTranslation } else { InlinedCopy });
if is_entry_fn(ccx.sess(), item.id) {
create_entry_wrapper(ccx, item.span, llfn);
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if ty::has_attr(ccx.tcx(), local_def(item.id), "rustc_error") {
ccx.tcx().sess.span_fatal(item.span, "compilation successful");
}
}
}
}
......@@ -2122,8 +2007,7 @@ pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let mut v = TransItemVisitor{ ccx: ccx };
v.visit_expr(&**expr);
consts::trans_static(ccx, m, item.id);
let g = get_item_val(ccx, item.id);
let g = consts::trans_static(ccx, m, item.id);
update_linkage(ccx, g, Some(item.id), OriginalTranslation);
// Do static_assert checking. It can't really be done much earlier
......@@ -2175,7 +2059,25 @@ pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) {
}
}
fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::NodeId,
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId,
cc: llvm::CallConv,
llfty: Type) -> ValueRef {
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
let llfn = declare::define_fn(ccx, &sym[..], cc, llfty,
ty::FnConverging(ty::mk_nil(ccx.tcx()))).unwrap_or_else(||{
ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
});
finish_register_fn(ccx, sym, node_id, llfn);
llfn
}
fn finish_register_fn(ccx: &CrateContext, sym: String, node_id: ast::NodeId,
llfn: ValueRef) {
ccx.item_symbols().borrow_mut().insert(node_id, sym);
......@@ -2190,19 +2092,6 @@ fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: String, node_id: ast::N
if ccx.tcx().lang_items.eh_personality() == Some(def) {
llvm::SetLinkage(llfn, llvm::ExternalLinkage);
}
if is_entry_fn(ccx.sess(), node_id) {
// check for the #[rustc_error] annotation, which forces an
// error in trans. This is used to write compile-fail tests
// that actually test that compilation succeeds without
// reporting an error.
if ty::has_attr(ccx.tcx(), local_def(node_id), "rustc_error") {
ccx.tcx().sess.span_fatal(sp, "compilation successful");
}
create_entry_wrapper(ccx, sp, llfn);
}
}
fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
......@@ -2221,26 +2110,10 @@ fn register_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.sess().span_bug(sp, "expected bare rust function")
}
let llfn = decl_rust_fn(ccx, node_type, &sym[..]);
finish_register_fn(ccx, sp, sym, node_id, llfn);
llfn
}
// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
pub fn register_fn_llvmty(ccx: &CrateContext,
sp: Span,
sym: String,
node_id: ast::NodeId,
cc: llvm::CallConv,
llfty: Type) -> ValueRef {
debug!("register_fn_llvmty id={} sym={}", node_id, sym);
let llfn = decl_fn(ccx,
&sym[..],
cc,
llfty,
ty::FnConverging(ty::mk_nil(ccx.tcx())));
finish_register_fn(ccx, sp, sym, node_id, llfn);
let llfn = declare::define_rust_fn(ccx, &sym[..], node_type).unwrap_or_else(||{
ccx.sess().span_fatal(sp, &format!("symbol `{}` is already defined", sym));
});
finish_register_fn(ccx, sym, node_id, llfn);
llfn
}
......@@ -2251,27 +2124,36 @@ pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool {
}
}
// Create a _rust_main(args: ~[str]) function which will be called from the
// runtime rust_start function
/// Create the `main` function which will initialise the rust runtime and call users’ main
/// function.
pub fn create_entry_wrapper(ccx: &CrateContext,
_sp: Span,
main_llfn: ValueRef) {
let et = ccx.sess().entry_type.get().unwrap();
match et {
config::EntryMain => {
create_entry_fn(ccx, main_llfn, true);
create_entry_fn(ccx, _sp, main_llfn, true);
}
config::EntryStart => create_entry_fn(ccx, main_llfn, false),
config::EntryStart => create_entry_fn(ccx, _sp, main_llfn, false),
config::EntryNone => {} // Do nothing.
}
#[inline(never)]
fn create_entry_fn(ccx: &CrateContext,
_sp: Span,
rust_main: ValueRef,
use_start_lang_item: bool) {
let llfty = Type::func(&[ccx.int_type(), Type::i8p(ccx).ptr_to()],
&ccx.int_type());
let llfn = decl_cdecl_fn(ccx, "main", llfty, ty::mk_nil(ccx.tcx()));
let llfn = declare::define_cfn(ccx, "main", llfty,
ty::mk_nil(ccx.tcx())).unwrap_or_else(||{
ccx.sess().span_err(_sp, "entry symbol `main` defined multiple times");
// FIXME: We should be smart and show a better diagnostic here.
ccx.sess().help("did you use #[no_mangle] on `fn main`? Use #[start] instead");
ccx.sess().abort_if_errors();
panic!();
});
// FIXME: #16581: Marking a symbol in the executable with `dllexport`
// linkage forces MinGW's linker to output a `.reloc` section for ASLR
......@@ -2407,14 +2289,15 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
} else {
llvm::LLVMTypeOf(v)
};
if contains_null(&sym[..]) {
ccx.sess().fatal(
&format!("Illegal null byte in export_name \
value: `{}`", sym));
}
let buf = CString::new(sym.clone()).unwrap();
let g = llvm::LLVMAddGlobal(ccx.llmod(), llty,
buf.as_ptr());
// FIXME(nagisa): probably should be declare_global, because no definition
// is happening here, but we depend on it being defined here from
// const::trans_static. This all logic should be replaced.
let g = declare::define_global(ccx, &sym[..],
Type::from_ref(llty)).unwrap_or_else(||{
ccx.sess().span_fatal(i.span, &format!("symbol `{}` is already defined",
sym))
});
if attr::contains_name(&i.attrs,
"thread_local") {
......@@ -2430,10 +2313,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
let llfn = if abi == Rust {
register_fn(ccx, i.span, sym, i.id, ty)
} else {
foreign::register_rust_fn_with_foreign_abi(ccx,
i.span,
sym,
i.id)
foreign::register_rust_fn_with_foreign_abi(ccx, i.span, sym, i.id)
};
attributes::from_fn_attrs(ccx, &i.attrs, llfn);
llfn
......
......@@ -41,6 +41,7 @@
use trans::consts;
use trans::datum::*;
use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::declare;
use trans::expr;
use trans::glue;
use trans::inline;
......@@ -326,13 +327,9 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx));
//
let function_name =
link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
"fn_pointer_shim");
let llfn =
decl_internal_rust_fn(ccx,
tuple_fn_ty,
&function_name[..]);
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
"fn_pointer_shim");
let llfn = declare::declare_internal_rust_fn(ccx, &function_name[..], tuple_fn_ty);
//
let empty_substs = tcx.mk_substs(Substs::trans_empty());
......
......@@ -126,6 +126,7 @@
use trans::common;
use trans::common::{Block, FunctionContext, ExprId, NodeIdAndSpan};
use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::declare;
use trans::glue;
use middle::region;
use trans::type_::Type;
......@@ -844,10 +845,8 @@ fn get_or_create_landing_pad(&'blk self) -> BasicBlockRef {
Some(llpersonality) => llpersonality,
None => {
let fty = Type::variadic_func(&[], &Type::i32(self.ccx));
let f = base::decl_cdecl_fn(self.ccx,
"rust_eh_personality",
fty,
self.ccx.tcx().types.i32);
let f = declare::declare_cfn(self.ccx, "rust_eh_personality", fty,
self.ccx.tcx().types.i32);
*personality = Some(f);
f
}
......
......@@ -21,6 +21,7 @@
use trans::common::*;
use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue};
use trans::debuginfo::{self, DebugLoc};
use trans::declare;
use trans::expr;
use trans::monomorphize::{self, MonoId};
use trans::type_of::*;
......@@ -162,7 +163,11 @@ pub fn get_or_create_declaration_if_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tc
mangle_internal_name_by_path_and_seq(path, "closure")
});
let llfn = decl_internal_rust_fn(ccx, function_type, &symbol[..]);
// Currently there’s only a single user of get_or_create_declaration_if_closure and it
// unconditionally defines the function, therefore we use define_* here.
let llfn = declare::define_internal_rust_fn(ccx, &symbol[..], function_type).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", symbol));
});
// set an inline hint for all closures
attributes::inline(llfn, attributes::InlineAttr::Hint);
......
......@@ -31,6 +31,7 @@
use trans::consts;
use trans::datum;
use trans::debuginfo::{self, DebugLoc};
use trans::declare;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
......@@ -872,9 +873,10 @@ pub fn C_cstr(cx: &CrateContext, s: InternedString, null_terminated: bool) -> Va
!null_terminated as Bool);
let gsym = token::gensym("str");
let buf = CString::new(format!("str{}", gsym.usize()));
let buf = buf.unwrap();
let g = llvm::LLVMAddGlobal(cx.llmod(), val_ty(sc).to_ref(), buf.as_ptr());
let sym = format!("str{}", gsym.usize());
let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{
cx.sess().bug(&format!("symbol `{}` is already defined", sym));
});
llvm::LLVMSetInitializer(g, sc);
llvm::LLVMSetGlobalConstant(g, True);
llvm::SetLinkage(g, llvm::InternalLinkage);
......
......@@ -25,6 +25,7 @@
use trans::{adt, closure, debuginfo, expr, inline, machine};
use trans::base::{self, push_ctxt};
use trans::common::*;
use trans::declare;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
......@@ -35,6 +36,7 @@
use std::iter::repeat;
use libc::c_uint;
use syntax::{ast, ast_util};
use syntax::parse::token;
use syntax::ptr::P;
pub fn const_lit(cx: &CrateContext, e: &ast::Expr, lit: &ast::Lit)
......@@ -96,13 +98,16 @@ pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef {
fn addr_of_mut(ccx: &CrateContext,
cv: ValueRef,
kind: &str,
id: ast::NodeId)
kind: &str)
-> ValueRef {
unsafe {
let name = format!("{}{}\0", kind, id);
let gv = llvm::LLVMAddGlobal(ccx.llmod(), val_ty(cv).to_ref(),
name.as_ptr() as *const _);
// FIXME: this totally needs a better name generation scheme, perhaps a simple global
// counter? Also most other uses of gensym in trans.
let gsym = token::gensym("_");
let name = format!("{}{}", kind, gsym.usize());
let gv = declare::define_global(ccx, &name[..], val_ty(cv)).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` is already defined", name));
});
llvm::LLVMSetInitializer(gv, cv);
SetLinkage(gv, InternalLinkage);
SetUnnamedAddr(gv, true);
......@@ -112,14 +117,13 @@ fn addr_of_mut(ccx: &CrateContext,
pub fn addr_of(ccx: &CrateContext,
cv: ValueRef,
kind: &str,
id: ast::NodeId)
kind: &str)
-> ValueRef {
match ccx.const_globals().borrow().get(&cv) {
Some(&gv) => return gv,
None => {}
}
let gv = addr_of_mut(ccx, cv, kind, id);
let gv = addr_of_mut(ccx, cv, kind);
unsafe {
llvm::LLVMSetGlobalConstant(gv, True);
}
......@@ -233,7 +237,7 @@ pub fn get_const_expr_as_global<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
};
let lvalue = addr_of(ccx, val, "const", expr.id);
let lvalue = addr_of(ccx, val, "const");
ccx.const_values().borrow_mut().insert(key, lvalue);
lvalue
}
......@@ -284,7 +288,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
if adj.autoderefs == 0 {
// Don't copy data to do a deref+ref
// (i.e., skip the last auto-deref).
llconst = addr_of(cx, llconst, "autoref", e.id);
llconst = addr_of(cx, llconst, "autoref");
} else {
// Seeing as we are deref'ing here and take a reference
// again to make the pointer part of the far pointer below,
......@@ -312,7 +316,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
None => {}
Some(box ty::AutoUnsafe(_, None)) |
Some(box ty::AutoPtr(_, _, None)) => {
llconst = addr_of(cx, llconst, "autoref", e.id);
llconst = addr_of(cx, llconst, "autoref");
}
Some(box ty::AutoUnsize(ref k)) => {
let info =
......@@ -711,12 +715,12 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// If this isn't the address of a static, then keep going through
// normal constant evaluation.
let (v, _) = const_expr(cx, &**sub, param_substs);
addr_of(cx, v, "ref", e.id)
addr_of(cx, v, "ref")
}
}
ast::ExprAddrOf(ast::MutMutable, ref sub) => {
let (v, _) = const_expr(cx, &**sub, param_substs);
addr_of_mut(cx, v, "ref_mut_slice", e.id)
addr_of_mut(cx, v, "ref_mut_slice")
}
ast::ExprTup(ref es) => {
let repr = adt::represent_type(cx, ety);
......@@ -862,7 +866,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
}
}
pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) -> ValueRef {
unsafe {
let _icx = push_ctxt("trans_static");
let g = base::get_item_val(ccx, id);
......@@ -888,6 +892,7 @@ pub fn trans_static(ccx: &CrateContext, m: ast::Mutability, id: ast::NodeId) {
}
}
debuginfo::create_global_var_metadata(ccx, id, g);
g
}
}
......
......@@ -20,6 +20,7 @@
use trans::builder::Builder;
use trans::common::{ExternMap,BuilderRef_res};
use trans::debuginfo;
use trans::declare;
use trans::monomorphize::MonoId;
use trans::type_::{Type, TypeNames};
use middle::subst::Substs;
......@@ -133,7 +134,6 @@ pub struct LocalCrateContext<'tcx> {
llsizingtypes: RefCell<FnvHashMap<Ty<'tcx>, Type>>,
adt_reprs: RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>>,
type_hashcodes: RefCell<FnvHashMap<Ty<'tcx>, String>>,
all_llvm_symbols: RefCell<FnvHashSet<String>>,
int_type: Type,
opaque_vec_type: Type,
builder: BuilderRef_res,
......@@ -413,7 +413,6 @@ fn new(shared: &SharedCrateContext<'tcx>,
llsizingtypes: RefCell::new(FnvHashMap()),
adt_reprs: RefCell::new(FnvHashMap()),
type_hashcodes: RefCell::new(FnvHashMap()),
all_llvm_symbols: RefCell::new(FnvHashSet()),
int_type: Type::from_ref(ptr::null_mut()),
opaque_vec_type: Type::from_ref(ptr::null_mut()),
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
......@@ -653,10 +652,6 @@ pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, String>>
&self.local.type_hashcodes
}
pub fn all_llvm_symbols<'a>(&'a self) -> &'a RefCell<FnvHashSet<String>> {
&self.local.all_llvm_symbols
}
pub fn stats<'a>(&'a self) -> &'a Stats {
&self.shared.stats
}
......@@ -743,17 +738,16 @@ fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef
macro_rules! ifn {
($name:expr, fn() -> $ret:expr) => (
if *key == $name {
let f = base::decl_cdecl_fn(
ccx, $name, Type::func(&[], &$ret),
ty::mk_nil(ccx.tcx()));
let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret),
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f);
}
);
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
if *key == $name {
let f = base::decl_cdecl_fn(ccx, $name,
Type::func(&[$($arg),*], &$ret), ty::mk_nil(ccx.tcx()));
let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret),
ty::mk_nil(ccx.tcx()));
ccx.intrinsics().borrow_mut().insert($name, f.clone());
return Some(f);
}
......@@ -888,9 +882,9 @@ 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);
}
......
......@@ -417,8 +417,7 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32);
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
let expr_file_line = consts::addr_of(ccx, expr_file_line_const,
"panic_loc", call_info.id);
let expr_file_line = consts::addr_of(ccx, expr_file_line_const, "panic_loc");
let args = vec!(expr_file_line);
let did = langcall(bcx, Some(call_info.span), "", PanicFnLangItem);
let bcx = callee::trans_lang_call(bcx,
......@@ -450,8 +449,7 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let filename = C_str_slice(ccx, filename);
let line = C_u32(ccx, loc.line as u32);
let file_line_const = C_struct(ccx, &[filename, line], false);
let file_line = consts::addr_of(ccx, file_line_const,
"panic_bounds_check_loc", call_info.id);
let file_line = consts::addr_of(ccx, file_line_const, "panic_bounds_check_loc");
let args = vec!(file_line, index, len);
let did = langcall(bcx, Some(call_info.span), "", PanicBoundsCheckFnLangItem);
let bcx = callee::trans_lang_call(bcx,
......
......@@ -196,8 +196,9 @@
use metadata::csearch;
use middle::subst::{self, Substs};
use trans::{self, adt, machine, type_of};
use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block,
C_bytes, NormalizingClosureTyper};
use trans::common::{self, NodeIdAndSpan, CrateContext, FunctionContext, Block, C_bytes,
NormalizingClosureTyper};
use trans::declare;
use trans::_match::{BindingInfo, TrByCopy, TrByMove, TrByRef};
use trans::monomorphize;
use trans::type_::Type;
......@@ -4071,7 +4072,7 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(ccx: &CrateContext)
/// section.
fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
-> llvm::ValueRef {
let section_var_name = b"__rustc_debug_gdb_scripts_section__\0";
let section_var_name = "__rustc_debug_gdb_scripts_section__";
let section_var = unsafe {
llvm::LLVMGetNamedGlobal(ccx.llmod(),
......@@ -4085,10 +4086,11 @@ fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
unsafe {
let llvm_type = Type::array(&Type::i8(ccx),
section_contents.len() as u64);
let section_var = llvm::LLVMAddGlobal(ccx.llmod(),
llvm_type.to_ref(),
section_var_name.as_ptr()
as *const _);
let section_var = declare::define_global(ccx, section_var_name,
llvm_type).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` is already defined", section_var_name))
});
llvm::LLVMSetSection(section_var, section_name.as_ptr() as *const _);
llvm::LLVMSetInitializer(section_var, C_bytes(ccx, section_contents));
llvm::LLVMSetGlobalConstant(section_var, llvm::True);
......
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Declare various LLVM values.
//!
//! Prefer using functions and methods from this module rather than calling LLVM functions
//! directly. These functions do some additional work to ensure we do the right thing given
//! the preconceptions of trans.
//!
//! Some useful guidelines:
//!
//! * Use declare_* family of methods if you are declaring, but are not interested in defining the
//! ValueRef they return.
//! * Use define_* family of methods when you might be defining the ValueRef.
//! * When in doubt, define.
#![allow(dead_code)]
use llvm::{self, ValueRef};
use middle::ty::{self, ClosureTyper};
use syntax::abi;
use trans::attributes;
use trans::base;
use trans::common;
use trans::context::CrateContext;
use trans::monomorphize;
use trans::type_::Type;
use trans::type_of;
use util::ppaux::Repr;
use std::ffi::CString;
use libc::c_uint;
/// Declare a global value.
///
/// If there’s a value with the same name already declared, the function will return its ValueRef
/// instead.
pub fn declare_global(ccx: &CrateContext, name: &str, ty: Type) -> llvm::ValueRef {
debug!("declare_global(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
unsafe {
llvm::LLVMGetOrInsertGlobal(ccx.llmod(), namebuf.as_ptr(), ty.to_ref())
}
}
/// Declare a function.
///
/// For rust functions use `declare_rust_fn` instead.
///
/// If there’s a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, ty: Type,
output: ty::FnOutput) -> ValueRef {
debug!("declare_fn(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
let llfn = unsafe {
llvm::LLVMGetOrInsertFunction(ccx.llmod(), namebuf.as_ptr(), ty.to_ref())
};
llvm::SetFunctionCallConv(llfn, callconv);
// Function addresses in Rust are never significant, allowing functions to be merged.
llvm::SetUnnamedAddr(llfn, true);
if output == ty::FnDiverging {
llvm::SetFunctionAttribute(llfn, llvm::NoReturnAttribute);
}
if ccx.tcx().sess.opts.cg.no_redzone
.unwrap_or(ccx.tcx().sess.target.target.options.disable_redzone) {
llvm::SetFunctionAttribute(llfn, llvm::NoRedZoneAttribute)
}
if ccx.is_split_stack_supported() && !ccx.sess().opts.cg.no_stack_check {
attributes::split_stack(llfn, true);
}
llfn
}
/// Declare a C ABI function.
///
/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
/// instead.
///
/// If there’s a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type, output: ty::Ty) -> ValueRef {
declare_fn(ccx, name, llvm::CCallConv, fn_type, ty::FnConverging(output))
}
/// Declare a Rust function.
///
/// If there’s a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={})", name, fn_type.repr(ccx.tcx()));
let fn_type = monomorphize::normalize_associated_type(ccx.tcx(), &fn_type);
debug!("declare_rust_fn (after normalised associated types) fn_type={}",
fn_type.repr(ccx.tcx()));
let function_type; // placeholder so that the memory ownership works out ok
let (sig, abi, env) = match fn_type.sty {
ty::ty_bare_fn(_, ref f) => {
(&f.sig, f.abi, None)
}
ty::ty_closure(closure_did, substs) => {
let typer = common::NormalizingClosureTyper::new(ccx.tcx());
function_type = typer.closure_type(closure_did, substs);
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
let llenvironment_type = type_of::type_of_explicit_arg(ccx, self_type);
debug!("declare_rust_fn function_type={} self_type={}",
function_type.repr(ccx.tcx()), self_type.repr(ccx.tcx()));
(&function_type.sig, abi::RustCall, Some(llenvironment_type))
}
_ => ccx.sess().bug("expected closure or fn")
};
let sig = ty::Binder(ty::erase_late_bound_regions(ccx.tcx(), sig));
debug!("declare_rust_fn (after region erasure) sig={}", sig.repr(ccx.tcx()));
let llfty = type_of::type_of_rust_fn(ccx, env, &sig, abi);
debug!("declare_rust_fn llfty={}", ccx.tn().type_to_string(llfty));
// it is ok to directly access sig.0.output because we erased all late-bound-regions above
let llfn = declare_fn(ccx, name, llvm::CCallConv, llfty, sig.0.output);
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
llfn
}
/// Declare a Rust function with internal linkage.
///
/// If there’s a value with the same name already declared, the function will update the
/// declaration and return existing ValueRef instead.
pub fn declare_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
let llfn = declare_rust_fn(ccx, name, fn_type);
llvm::SetLinkage(llfn, llvm::InternalLinkage);
llfn
}
/// Declare a global with an intention to define it.
///
/// Use this function when you intend to define a global. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_global(ccx: &CrateContext, name: &str, ty: Type) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_global(ccx, name, ty))
}
}
/// Declare a function with an intention to define it.
///
/// For rust functions use `define_rust_fn` instead.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_fn(ccx: &CrateContext, name: &str, callconv: llvm::CallConv, fn_type: Type,
output: ty::FnOutput) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_fn(ccx, name, callconv, fn_type, output))
}
}
/// Declare a C ABI function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
///
/// Only use this for foreign function ABIs and glue. For Rust functions use `declare_rust_fn`
/// instead.
pub fn define_cfn(ccx: &CrateContext, name: &str, fn_type: Type,
output: ty::Ty) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_cfn(ccx, name, fn_type, output))
}
}
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_rust_fn(ccx, name, fn_type))
}
}
/// Declare a Rust function with an intention to define it.
///
/// Use this function when you intend to define a function. This function will return None if the
/// name already has a definition associated with it. In that case an error should be reported to
/// the user, because it usually happens due to user’s fault (e.g. misuse of #[no_mangle] or
/// #[export_name] attributes).
pub fn define_internal_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> Option<ValueRef> {
if get_defined_value(ccx, name).is_some() {
None
} else {
Some(declare_internal_rust_fn(ccx, name, fn_type))
}
}
/// Get defined or externally defined (AvailableExternally linkage) value by name.
fn get_defined_value(ccx: &CrateContext, name: &str) -> Option<ValueRef> {
debug!("get_defined_value(name={:?})", name);
let namebuf = CString::new(name).unwrap_or_else(|_|{
ccx.sess().bug(&format!("name {:?} contains an interior null byte", name))
});
let val = unsafe { llvm::LLVMGetNamedValue(ccx.llmod(), namebuf.as_ptr()) };
if val.is_null() {
debug!("get_defined_value: {:?} value is null", name);
None
} else {
let (declaration, aext_link) = unsafe {
let linkage = llvm::LLVMGetLinkage(val);
(llvm::LLVMIsDeclaration(val) != 0,
linkage == llvm::AvailableExternallyLinkage as c_uint)
};
debug!("get_defined_value: found {:?} value (declaration: {}, aext_link: {})", name,
declaration, aext_link);
if !declaration || aext_link {
Some(val)
} else {
None
}
}
}
......@@ -20,6 +20,7 @@
use trans::cabi;
use trans::common::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::machine;
use trans::monomorphize;
use trans::type_::Type;
......@@ -28,7 +29,6 @@
use middle::ty::{self, Ty};
use middle::subst::Substs;
use std::ffi::CString;
use std::cmp;
use libc::c_uint;
use syntax::abi::{Cdecl, Aapcs, C, Win64, Abi};
......@@ -136,9 +136,7 @@ pub fn register_static(ccx: &CrateContext,
};
unsafe {
// Declare a symbol `foo` with the desired linkage.
let buf = CString::new(ident.as_bytes()).unwrap();
let g1 = llvm::LLVMAddGlobal(ccx.llmod(), llty2.to_ref(),
buf.as_ptr());
let g1 = declare::declare_global(ccx, &ident[..], llty2);
llvm::SetLinkage(g1, linkage);
// Declare an internal global `extern_with_linkage_foo` which
......@@ -149,19 +147,17 @@ pub fn register_static(ccx: &CrateContext,
// zero.
let mut real_name = "_rust_extern_with_linkage_".to_string();
real_name.push_str(&ident);
let real_name = CString::new(real_name).unwrap();
let g2 = llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(),
real_name.as_ptr());
let g2 = declare::define_global(ccx, &real_name[..], llty).unwrap_or_else(||{
ccx.sess().span_fatal(foreign_item.span,
&format!("symbol `{}` is already defined", ident))
});
llvm::SetLinkage(g2, llvm::InternalLinkage);
llvm::LLVMSetInitializer(g2, g1);
g2
}
}
None => unsafe {
// Generate an external declaration.
let buf = CString::new(ident.as_bytes()).unwrap();
llvm::LLVMAddGlobal(ccx.llmod(), llty.to_ref(), buf.as_ptr())
}
None => // Generate an external declaration.
declare::declare_global(ccx, &ident[..], llty),
}
}
......@@ -177,7 +173,7 @@ pub fn get_extern_fn(ccx: &CrateContext,
Some(n) => return *n,
None => {}
}
let f = base::decl_fn(ccx, name, cc, ty, ty::FnConverging(output));
let f = declare::declare_fn(ccx, name, cc, ty, ty::FnConverging(output));
externs.insert(name.to_string(), f);
f
}
......@@ -534,7 +530,8 @@ pub fn decl_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
}
_ => panic!("expected bare fn in decl_rust_fn_with_foreign_abi")
};
let llfn = base::decl_fn(ccx, name, cconv, llfn_ty, ty::FnConverging(ty::mk_nil(ccx.tcx())));
let llfn = declare::declare_fn(ccx, name, cconv, llfn_ty,
ty::FnConverging(ty::mk_nil(ccx.tcx())));
add_argument_attributes(&tys, llfn);
debug!("decl_rust_fn_with_foreign_abi(llfn_ty={}, llfn={})",
ccx.tn().type_to_string(llfn_ty), ccx.tn().val_to_string(llfn));
......@@ -623,7 +620,9 @@ fn build_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ccx.tcx().map.path_to_string(id),
id, t.repr(tcx));
let llfn = base::decl_internal_rust_fn(ccx, t, &ps[..]);
let llfn = declare::define_internal_rust_fn(ccx, &ps[..], t).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", ps));
});
attributes::from_fn_attrs(ccx, attrs, llfn);
base::trans_fn(ccx, decl, body, llfn, param_substs, id, &[]);
llfn
......
......@@ -33,6 +33,7 @@
use trans::consts;
use trans::datum;
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
use trans::foreign;
use trans::inline;
......@@ -184,7 +185,7 @@ pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Val
// To avoid infinite recursion, don't `make_drop_glue` until after we've
// added the entry to the `drop_glues` cache.
if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&t) {
let llfn = decl_cdecl_fn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx()));
let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ty::mk_nil(ccx.tcx()));
ccx.drop_glues().borrow_mut().insert(t, llfn);
return llfn;
};
......@@ -294,12 +295,8 @@ pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
did,
&[get_drop_glue_type(ccx, t)],
ty::mk_nil(ccx.tcx()));
foreign::get_extern_fn(ccx,
&mut *ccx.externs().borrow_mut(),
&name[..],
llvm::CCallConv,
llty,
dtor_ty)
foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv,
llty, dtor_ty)
}
}
......
......@@ -28,6 +28,7 @@
use trans::consts;
use trans::datum::*;
use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr::SaveIn;
use trans::expr;
use trans::glue;
......@@ -590,10 +591,10 @@ pub fn trans_object_shim<'a, 'tcx>(
//
let shim_fn_ty = ty::mk_bare_fn(tcx, None, fty);
let method_bare_fn_ty = ty::mk_bare_fn(tcx, None, method_ty);
let function_name =
link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
let llfn =
decl_internal_rust_fn(ccx, shim_fn_ty, &function_name);
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
let llfn = declare::define_internal_rust_fn(ccx, &function_name, shim_fn_ty).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", function_name));
});
let sig = ty::erase_late_bound_regions(ccx.tcx(), &fty.sig);
......@@ -756,8 +757,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
C_uint(ccx, align)
].into_iter().chain(methods).collect();
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false),
"vtable", trait_ref.def_id().node);
let vtable = consts::addr_of(ccx, C_struct(ccx, &components, false), "vtable");
ccx.vtables().borrow_mut().insert(trait_ref, vtable);
vtable
......
......@@ -43,6 +43,7 @@
mod controlflow;
mod datum;
mod debuginfo;
mod declare;
mod expr;
mod foreign;
mod glue;
......
......@@ -19,9 +19,10 @@
use middle::ty_fold::{TypeFolder, TypeFoldable};
use trans::attributes;
use trans::base::{trans_enum_variant, push_ctxt, get_item_val};
use trans::base::{trans_fn, decl_internal_rust_fn};
use trans::base::trans_fn;
use trans::base;
use trans::common::*;
use trans::declare;
use trans::foreign;
use middle::ty::{self, HasProjectionTypes, Ty};
use util::ppaux::Repr;
......@@ -143,7 +144,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let lldecl = if abi != abi::Rust {
foreign::decl_rust_fn_with_foreign_abi(ccx, mono_ty, &s[..])
} else {
decl_internal_rust_fn(ccx, mono_ty, &s[..])
// FIXME(nagisa): perhaps needs a more fine grained selection? See setup_lldecl below.
declare::define_internal_rust_fn(ccx, &s[..], mono_ty).unwrap_or_else(||{
ccx.sess().bug(&format!("symbol `{}` already defined", s));
})
};
ccx.monomorphized().borrow_mut().insert(hash_id.take().unwrap(), lldecl);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册