trans: Load and cache cross-crate Mir instances in the shared context.
This commit is contained in:
parent
47cd05c8c1
commit
6c551b3766
@ -77,6 +77,7 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
|
||||
use trans::declare;
|
||||
use trans::expr;
|
||||
use trans::glue;
|
||||
use trans::inline;
|
||||
use trans::intrinsic;
|
||||
use trans::machine;
|
||||
use trans::machine::{llalign_of_min, llsize_of, llsize_of_real};
|
||||
@ -1392,34 +1393,53 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
pub fn new(ccx: &'blk CrateContext<'blk, 'tcx>,
|
||||
llfndecl: ValueRef,
|
||||
fn_ty: FnType,
|
||||
id: ast::NodeId,
|
||||
def_id: Option<DefId>,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
sp: Option<Span>,
|
||||
block_arena: &'blk TypedArena<common::BlockS<'blk, 'tcx>>)
|
||||
-> FunctionContext<'blk, 'tcx> {
|
||||
common::validate_substs(param_substs);
|
||||
|
||||
debug!("FunctionContext::new(path={}, id={}, param_substs={:?})",
|
||||
if id == !0 {
|
||||
"".to_string()
|
||||
} else {
|
||||
let inlined_did = def_id.and_then(|def_id| inline::get_local_instance(ccx, def_id));
|
||||
let inlined_id = inlined_did.and_then(|id| ccx.tcx().map.as_local_node_id(id));
|
||||
let local_id = def_id.and_then(|id| ccx.tcx().map.as_local_node_id(id));
|
||||
|
||||
debug!("FunctionContext::new(path={}, def_id={:?}, param_substs={:?})",
|
||||
inlined_id.map_or(String::new(), |id| {
|
||||
ccx.tcx().map.path_to_string(id).to_string()
|
||||
},
|
||||
id,
|
||||
}),
|
||||
def_id,
|
||||
param_substs);
|
||||
|
||||
let debug_context = debuginfo::create_function_debug_context(ccx, id,
|
||||
param_substs,
|
||||
llfndecl);
|
||||
let (blk_id, cfg) = build_cfg(ccx.tcx(), id);
|
||||
let nested_returns = if let Some(ref cfg) = cfg {
|
||||
let debug_context = debuginfo::create_function_debug_context(ccx,
|
||||
inlined_id.unwrap_or(ast::DUMMY_NODE_ID), param_substs, llfndecl);
|
||||
|
||||
let cfg = inlined_id.map(|id| build_cfg(ccx.tcx(), id));
|
||||
let nested_returns = if let Some((blk_id, Some(ref cfg))) = cfg {
|
||||
has_nested_returns(ccx.tcx(), cfg, blk_id)
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let check_attrs = |attrs: &[ast::Attribute]| {
|
||||
attrs.iter().any(|item| item.check_name("rustc_mir"))
|
||||
};
|
||||
|
||||
let use_mir = if let Some(id) = local_id {
|
||||
check_attrs(ccx.tcx().map.attrs(id))
|
||||
} else if let Some(def_id) = def_id {
|
||||
check_attrs(&ccx.sess().cstore.item_attrs(def_id))
|
||||
} else {
|
||||
check_attrs(&[])
|
||||
};
|
||||
|
||||
let mir = if use_mir {
|
||||
def_id.and_then(|id| ccx.get_mir(id))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
FunctionContext {
|
||||
mir: ccx.mir_map().map.get(&id),
|
||||
mir: mir,
|
||||
llfn: llfndecl,
|
||||
llretslotptr: Cell::new(None),
|
||||
param_env: ccx.tcx().empty_parameter_environment(),
|
||||
@ -1431,21 +1451,21 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
llupvars: RefCell::new(NodeMap()),
|
||||
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
|
||||
fn_ty: fn_ty,
|
||||
id: id,
|
||||
param_substs: param_substs,
|
||||
span: sp,
|
||||
span: inlined_id.and_then(|id| ccx.tcx().map.opt_span(id)),
|
||||
block_arena: block_arena,
|
||||
lpad_arena: TypedArena::new(),
|
||||
ccx: ccx,
|
||||
debug_context: debug_context,
|
||||
scopes: RefCell::new(Vec::new()),
|
||||
cfg: cfg,
|
||||
cfg: cfg.and_then(|(_, cfg)| cfg)
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs setup on a newly created function, creating the entry
|
||||
/// scope block and allocating space for the return pointer.
|
||||
pub fn init(&'blk self, skip_retptr: bool) -> Block<'blk, 'tcx> {
|
||||
pub fn init(&'blk self, skip_retptr: bool, fn_did: Option<DefId>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let entry_bcx = self.new_temp_block("entry-block");
|
||||
|
||||
// Use a dummy instruction as the insertion point for all allocas.
|
||||
@ -1493,7 +1513,6 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
|
||||
// Create the drop-flag hints for every unfragmented path in the function.
|
||||
let tcx = self.ccx.tcx();
|
||||
let fn_did = tcx.map.local_def_id(self.id);
|
||||
let tables = tcx.tables.borrow();
|
||||
let mut hints = self.lldropflag_hints.borrow_mut();
|
||||
let fragment_infos = tcx.fragment_infos.borrow();
|
||||
@ -1501,7 +1520,8 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
// Intern table for drop-flag hint datums.
|
||||
let mut seen = HashMap::new();
|
||||
|
||||
if let Some(fragment_infos) = fragment_infos.get(&fn_did) {
|
||||
let fragment_infos = fn_did.and_then(|did| fragment_infos.get(&did));
|
||||
if let Some(fragment_infos) = fragment_infos {
|
||||
for &info in fragment_infos {
|
||||
|
||||
let make_datum = |id| {
|
||||
@ -1558,11 +1578,13 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
fn bind_args(&'blk self,
|
||||
args: &[hir::Arg],
|
||||
abi: Abi,
|
||||
id: ast::NodeId,
|
||||
closure_env: closure::ClosureEnv,
|
||||
arg_scope: cleanup::CustomScopeIndex)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("FunctionContext::bind_args");
|
||||
let mut bcx = self.init(false);
|
||||
let fn_did = self.ccx.tcx().map.local_def_id(id);
|
||||
let mut bcx = self.init(false, Some(fn_did));
|
||||
let arg_scope_id = cleanup::CustomScope(arg_scope);
|
||||
|
||||
let mut idx = 0;
|
||||
@ -1774,19 +1796,24 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
|
||||
/// 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: &hir::FnDecl,
|
||||
body: &hir::Block,
|
||||
llfndecl: ValueRef,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
fn_ast_id: ast::NodeId,
|
||||
attributes: &[ast::Attribute],
|
||||
fn_ty: FnType,
|
||||
abi: Abi,
|
||||
closure_env: closure::ClosureEnv<'b>) {
|
||||
pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
decl: &hir::FnDecl,
|
||||
body: &hir::Block,
|
||||
llfndecl: ValueRef,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
def_id: DefId,
|
||||
inlined_id: ast::NodeId,
|
||||
fn_ty: FnType,
|
||||
abi: Abi,
|
||||
closure_env: closure::ClosureEnv) {
|
||||
ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
|
||||
|
||||
record_translation_item_as_generated(ccx, fn_ast_id, param_substs);
|
||||
if collector::collecting_debug_information(ccx) {
|
||||
ccx.record_translation_item_as_generated(TransItem::Fn(Instance {
|
||||
def: def_id,
|
||||
params: ¶m_substs.types
|
||||
}))
|
||||
}
|
||||
|
||||
let _icx = push_ctxt("trans_closure");
|
||||
attributes::emit_uwtable(llfndecl, true);
|
||||
@ -1795,23 +1822,20 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfndecl, fn_ty, fn_ast_id,
|
||||
param_substs, Some(body.span), &arena);
|
||||
fcx = FunctionContext::new(ccx, llfndecl, fn_ty, Some(def_id), param_substs, &arena);
|
||||
|
||||
if attributes.iter().any(|item| item.check_name("rustc_mir")) {
|
||||
if fcx.mir.is_some() {
|
||||
return mir::trans_mir(&fcx);
|
||||
}
|
||||
|
||||
// cleanup scope for the incoming arguments
|
||||
let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(ccx,
|
||||
fn_ast_id,
|
||||
body.span,
|
||||
true);
|
||||
let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(
|
||||
ccx, inlined_id, body.span, true);
|
||||
let arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);
|
||||
|
||||
// Set up arguments to the function.
|
||||
debug!("trans_closure: function: {:?}", Value(fcx.llfn));
|
||||
let bcx = fcx.bind_args(&decl.inputs, abi, closure_env, arg_scope);
|
||||
let bcx = fcx.bind_args(&decl.inputs, abi, inlined_id, closure_env, arg_scope);
|
||||
|
||||
// Up until here, IR instructions for this function have explicitly not been annotated with
|
||||
// source code location, so we don't step into call setup code. From here on, source location
|
||||
@ -1862,28 +1886,6 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// Insert the mandatory first few basic blocks before lltop.
|
||||
fcx.finish(bcx, ret_debug_loc);
|
||||
|
||||
fn record_translation_item_as_generated<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
node_id: ast::NodeId,
|
||||
param_substs: &'tcx Substs<'tcx>) {
|
||||
if !collector::collecting_debug_information(ccx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let def_id = match ccx.tcx().node_id_to_type(node_id).sty {
|
||||
ty::TyClosure(def_id, _) => def_id,
|
||||
_ => ccx.external_srcs()
|
||||
.borrow()
|
||||
.get(&node_id)
|
||||
.map(|did| *did)
|
||||
.unwrap_or_else(|| ccx.tcx().map.local_def_id(node_id)),
|
||||
};
|
||||
|
||||
ccx.record_translation_item_as_generated(TransItem::Fn(Instance {
|
||||
def: def_id,
|
||||
params: ¶m_substs.types,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an LLVM function corresponding to a source language function.
|
||||
@ -1892,8 +1894,7 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
body: &hir::Block,
|
||||
llfndecl: ValueRef,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
id: ast::NodeId,
|
||||
attrs: &[ast::Attribute]) {
|
||||
id: ast::NodeId) {
|
||||
let _s = StatRecorder::new(ccx, ccx.tcx().map.path_to_string(id).to_string());
|
||||
debug!("trans_fn(param_substs={:?})", param_substs);
|
||||
let _icx = push_ctxt("trans_fn");
|
||||
@ -1903,13 +1904,18 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
|
||||
let abi = fn_ty.fn_abi();
|
||||
let fn_ty = FnType::new(ccx, abi, &sig, &[]);
|
||||
let def_id = if let Some(&def_id) = ccx.external_srcs().borrow().get(&id) {
|
||||
def_id
|
||||
} else {
|
||||
ccx.tcx().map.local_def_id(id)
|
||||
};
|
||||
trans_closure(ccx,
|
||||
decl,
|
||||
body,
|
||||
llfndecl,
|
||||
param_substs,
|
||||
def_id,
|
||||
id,
|
||||
attrs,
|
||||
fn_ty,
|
||||
abi,
|
||||
closure::ClosureEnv::NotClosure);
|
||||
@ -2001,9 +2007,10 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfndecl, fn_ty, ctor_id,
|
||||
param_substs, None, &arena);
|
||||
let bcx = fcx.init(false);
|
||||
fcx = FunctionContext::new(ccx, llfndecl, fn_ty,
|
||||
Some(ccx.tcx().map.local_def_id(ctor_id)),
|
||||
param_substs, &arena);
|
||||
let bcx = fcx.init(false, None);
|
||||
|
||||
assert!(!fcx.needs_ret_allocas);
|
||||
|
||||
@ -2239,7 +2246,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
|
||||
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
||||
let def_id = tcx.map.local_def_id(item.id);
|
||||
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
|
||||
trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id, &item.attrs);
|
||||
trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id);
|
||||
set_global_section(ccx, llfn, item);
|
||||
update_linkage(ccx,
|
||||
llfn,
|
||||
@ -2278,8 +2285,7 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
|
||||
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
||||
let def_id = tcx.map.local_def_id(impl_item.id);
|
||||
let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
|
||||
trans_fn(ccx, &sig.decl, body, llfn, empty_substs,
|
||||
impl_item.id, &impl_item.attrs);
|
||||
trans_fn(ccx, &sig.decl, body, llfn, empty_substs, impl_item.id);
|
||||
update_linkage(ccx, llfn, Some(impl_item.id),
|
||||
if is_origin {
|
||||
OriginalTranslation
|
||||
|
@ -387,9 +387,8 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
block_arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, ast::DUMMY_NODE_ID,
|
||||
empty_substs, None, &block_arena);
|
||||
let mut bcx = fcx.init(false);
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
|
||||
let mut bcx = fcx.init(false, None);
|
||||
|
||||
let llargs = get_params(fcx.llfn);
|
||||
|
||||
|
@ -34,7 +34,6 @@ use middle::ty::{self, Ty, TyCtxt};
|
||||
use session::config::FullDebugInfo;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr::{ThinAttributes, ThinAttributesExt};
|
||||
|
||||
use rustc_front::hir;
|
||||
|
||||
@ -43,7 +42,7 @@ use libc::c_uint;
|
||||
fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
closure_def_id: DefId,
|
||||
arg_scope_id: ScopeId,
|
||||
freevars: &[ty::Freevar]) {
|
||||
id: ast::NodeId) {
|
||||
let _icx = push_ctxt("closure::load_closure_environment");
|
||||
let kind = kind_for_closure(bcx.ccx(), closure_def_id);
|
||||
|
||||
@ -52,7 +51,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
|
||||
// Special case for small by-value selfs.
|
||||
let llenv = if kind == ty::ClosureKind::FnOnce && !env_arg.is_indirect() {
|
||||
let closure_ty = node_id_type(bcx, bcx.fcx.id);
|
||||
let closure_ty = node_id_type(bcx, id);
|
||||
let llenv = rvalue_scratch_datum(bcx, closure_ty, "closure_env").val;
|
||||
env_arg.store_fn_arg(bcx, &mut env_idx, llenv);
|
||||
llenv
|
||||
@ -70,52 +69,52 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
None
|
||||
};
|
||||
|
||||
for (i, freevar) in freevars.iter().enumerate() {
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
|
||||
closure_expr_id: bcx.fcx.id };
|
||||
let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
|
||||
let mut upvar_ptr = StructGEP(bcx, llenv, i);
|
||||
let captured_by_ref = match upvar_capture {
|
||||
ty::UpvarCapture::ByValue => false,
|
||||
ty::UpvarCapture::ByRef(..) => {
|
||||
upvar_ptr = Load(bcx, upvar_ptr);
|
||||
true
|
||||
bcx.tcx().with_freevars(id, |fv| {
|
||||
for (i, freevar) in fv.iter().enumerate() {
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
|
||||
closure_expr_id: id };
|
||||
let upvar_capture = bcx.tcx().upvar_capture(upvar_id).unwrap();
|
||||
let mut upvar_ptr = StructGEP(bcx, llenv, i);
|
||||
let captured_by_ref = match upvar_capture {
|
||||
ty::UpvarCapture::ByValue => false,
|
||||
ty::UpvarCapture::ByRef(..) => {
|
||||
upvar_ptr = Load(bcx, upvar_ptr);
|
||||
true
|
||||
}
|
||||
};
|
||||
let node_id = freevar.def.var_id();
|
||||
bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
|
||||
|
||||
if kind == ty::ClosureKind::FnOnce && !captured_by_ref {
|
||||
let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
|
||||
bcx.fcx.schedule_drop_mem(arg_scope_id,
|
||||
upvar_ptr,
|
||||
node_id_type(bcx, node_id),
|
||||
hint)
|
||||
}
|
||||
};
|
||||
let node_id = freevar.def.var_id();
|
||||
bcx.fcx.llupvars.borrow_mut().insert(node_id, upvar_ptr);
|
||||
|
||||
if kind == ty::ClosureKind::FnOnce && !captured_by_ref {
|
||||
let hint = bcx.fcx.lldropflag_hints.borrow().hint_datum(upvar_id.var_id);
|
||||
bcx.fcx.schedule_drop_mem(arg_scope_id,
|
||||
upvar_ptr,
|
||||
node_id_type(bcx, node_id),
|
||||
hint)
|
||||
if let Some(env_pointer_alloca) = env_pointer_alloca {
|
||||
debuginfo::create_captured_var_metadata(
|
||||
bcx,
|
||||
node_id,
|
||||
env_pointer_alloca,
|
||||
i,
|
||||
captured_by_ref,
|
||||
freevar.span);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(env_pointer_alloca) = env_pointer_alloca {
|
||||
debuginfo::create_captured_var_metadata(
|
||||
bcx,
|
||||
node_id,
|
||||
env_pointer_alloca,
|
||||
i,
|
||||
captured_by_ref,
|
||||
freevar.span);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub enum ClosureEnv<'a> {
|
||||
pub enum ClosureEnv {
|
||||
NotClosure,
|
||||
Closure(DefId, &'a [ty::Freevar]),
|
||||
Closure(DefId, ast::NodeId),
|
||||
}
|
||||
|
||||
impl<'a> ClosureEnv<'a> {
|
||||
impl ClosureEnv {
|
||||
pub fn load<'blk,'tcx>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId) {
|
||||
if let ClosureEnv::Closure(def_id, freevars) = self {
|
||||
if !freevars.is_empty() {
|
||||
load_closure_environment(bcx, def_id, arg_scope, freevars);
|
||||
}
|
||||
if let ClosureEnv::Closure(def_id, id) = self {
|
||||
load_closure_environment(bcx, def_id, arg_scope, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -198,8 +197,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||
body: &hir::Block,
|
||||
id: ast::NodeId,
|
||||
closure_def_id: DefId, // (*)
|
||||
closure_substs: &'tcx ty::ClosureSubsts<'tcx>,
|
||||
closure_expr_attrs: &ThinAttributes)
|
||||
closure_substs: &ty::ClosureSubsts<'tcx>)
|
||||
-> Option<Block<'a, 'tcx>>
|
||||
{
|
||||
// (*) Note that in the case of inlined functions, the `closure_def_id` will be the
|
||||
@ -229,9 +227,6 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(), &ccx.tcx().tables, ProjectionMode::Any);
|
||||
let function_type = infcx.closure_type(closure_def_id, closure_substs);
|
||||
|
||||
let freevars: Vec<ty::Freevar> =
|
||||
tcx.with_freevars(id, |fv| fv.iter().cloned().collect());
|
||||
|
||||
let sig = tcx.erase_late_bound_regions(&function_type.sig);
|
||||
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
|
||||
|
||||
@ -250,11 +245,11 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||
body,
|
||||
llfn,
|
||||
param_substs,
|
||||
closure_def_id,
|
||||
id,
|
||||
closure_expr_attrs.as_attr_slice(),
|
||||
fn_ty,
|
||||
Abi::RustCall,
|
||||
ClosureEnv::Closure(closure_def_id, &freevars));
|
||||
ClosureEnv::Closure(closure_def_id, id));
|
||||
|
||||
// Don't hoist this to the top of the function. It's perfectly legitimate
|
||||
// to have a zero-size closure (in which case dest will be `Ignore`) and
|
||||
@ -270,21 +265,23 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
||||
let repr = adt::represent_type(ccx, node_id_type(bcx, id));
|
||||
|
||||
// Create the closure.
|
||||
for (i, freevar) in freevars.iter().enumerate() {
|
||||
let datum = expr::trans_var(bcx, freevar.def);
|
||||
let upvar_slot_dest = adt::trans_field_ptr(
|
||||
bcx, &repr, adt::MaybeSizedValue::sized(dest_addr), Disr(0), i);
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
|
||||
closure_expr_id: id };
|
||||
match tcx.upvar_capture(upvar_id).unwrap() {
|
||||
ty::UpvarCapture::ByValue => {
|
||||
bcx = datum.store_to(bcx, upvar_slot_dest);
|
||||
}
|
||||
ty::UpvarCapture::ByRef(..) => {
|
||||
Store(bcx, datum.to_llref(), upvar_slot_dest);
|
||||
tcx.with_freevars(id, |fv| {
|
||||
for (i, freevar) in fv.iter().enumerate() {
|
||||
let datum = expr::trans_var(bcx, freevar.def);
|
||||
let upvar_slot_dest = adt::trans_field_ptr(
|
||||
bcx, &repr, adt::MaybeSizedValue::sized(dest_addr), Disr(0), i);
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.var_id(),
|
||||
closure_expr_id: id };
|
||||
match tcx.upvar_capture(upvar_id).unwrap() {
|
||||
ty::UpvarCapture::ByValue => {
|
||||
bcx = datum.store_to(bcx, upvar_slot_dest);
|
||||
}
|
||||
ty::UpvarCapture::ByRef(..) => {
|
||||
Store(bcx, datum.to_llref(), upvar_slot_dest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
adt::trans_set_discr(bcx, &repr, dest_addr, Disr(0));
|
||||
|
||||
Some(bcx)
|
||||
@ -394,9 +391,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
||||
|
||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
block_arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, lloncefn, fn_ty, ast::DUMMY_NODE_ID,
|
||||
substs.func_substs, None, &block_arena);
|
||||
let mut bcx = fcx.init(false);
|
||||
fcx = FunctionContext::new(ccx, lloncefn, fn_ty, None, substs.func_substs, &block_arena);
|
||||
let mut bcx = fcx.init(false, None);
|
||||
|
||||
|
||||
// the first argument (`self`) will be the (by value) closure env.
|
||||
|
@ -217,7 +217,6 @@ use trans::monomorphize::{self, Instance};
|
||||
use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap};
|
||||
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::rc::Rc;
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
|
||||
pub enum TransItemCollectionMode {
|
||||
@ -263,14 +262,9 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
debug!("Building translation item graph, beginning at roots");
|
||||
let mut visited = FnvHashSet();
|
||||
let mut recursion_depths = DefIdMap();
|
||||
let mut mir_cache = DefIdMap();
|
||||
|
||||
for root in roots {
|
||||
collect_items_rec(ccx,
|
||||
root,
|
||||
&mut visited,
|
||||
&mut recursion_depths,
|
||||
&mut mir_cache);
|
||||
collect_items_rec(ccx, root, &mut visited, &mut recursion_depths);
|
||||
}
|
||||
|
||||
visited
|
||||
@ -300,27 +294,11 @@ fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
roots
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
enum CachedMir<'mir, 'tcx: 'mir> {
|
||||
Ref(&'mir mir::Mir<'tcx>),
|
||||
Owned(Rc<mir::Mir<'tcx>>)
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> CachedMir<'mir, 'tcx> {
|
||||
fn get_ref<'a>(&'a self) -> &'a mir::Mir<'tcx> {
|
||||
match *self {
|
||||
CachedMir::Ref(r) => r,
|
||||
CachedMir::Owned(ref rc) => &rc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all monomorphized translation items reachable from `starting_point`
|
||||
fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
starting_point: TransItem<'tcx>,
|
||||
visited: &mut FnvHashSet<TransItem<'tcx>>,
|
||||
recursion_depths: &mut DefIdMap<usize>,
|
||||
mir_cache: &mut DefIdMap<CachedMir<'a, 'tcx>>) {
|
||||
recursion_depths: &mut DefIdMap<usize>) {
|
||||
if !visited.insert(starting_point.clone()) {
|
||||
// We've been here already, no need to search again.
|
||||
return;
|
||||
@ -346,11 +324,12 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
||||
// Scan the MIR in order to find function calls, closures, and
|
||||
// drop-glue
|
||||
let mir = load_mir(ccx, instance.def, mir_cache);
|
||||
let mir = errors::expect(ccx.sess().diagnostic(), ccx.get_mir(instance.def),
|
||||
|| format!("Could not find MIR for function: {}", instance));
|
||||
|
||||
let mut visitor = MirNeighborCollector {
|
||||
ccx: ccx,
|
||||
mir: mir.get_ref(),
|
||||
mir: &mir,
|
||||
output: &mut neighbors,
|
||||
param_substs: ccx.tcx().mk_substs(Substs {
|
||||
types: instance.params.clone(),
|
||||
@ -358,12 +337,12 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
})
|
||||
};
|
||||
|
||||
visitor.visit_mir(mir.get_ref());
|
||||
visitor.visit_mir(&mir);
|
||||
}
|
||||
}
|
||||
|
||||
for neighbour in neighbors {
|
||||
collect_items_rec(ccx, neighbour, visited, recursion_depths, mir_cache);
|
||||
collect_items_rec(ccx, neighbour, visited, recursion_depths);
|
||||
}
|
||||
|
||||
if let Some((def_id, depth)) = recursion_depth_reset {
|
||||
@ -373,37 +352,6 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
debug!("END collect_items_rec({})", starting_point.to_string(ccx));
|
||||
}
|
||||
|
||||
fn load_mir<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
def_id: DefId,
|
||||
mir_cache: &mut DefIdMap<CachedMir<'a, 'tcx>>)
|
||||
-> CachedMir<'a, 'tcx> {
|
||||
let mir_not_found_error_message = || {
|
||||
format!("Could not find MIR for function: {}",
|
||||
ccx.tcx().item_path_str(def_id))
|
||||
};
|
||||
|
||||
if def_id.is_local() {
|
||||
let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap();
|
||||
let mir_opt = ccx.mir_map().map.get(&node_id);
|
||||
let mir = errors::expect(ccx.sess().diagnostic(),
|
||||
mir_opt,
|
||||
mir_not_found_error_message);
|
||||
CachedMir::Ref(mir)
|
||||
} else {
|
||||
if let Some(mir) = mir_cache.get(&def_id) {
|
||||
return mir.clone();
|
||||
}
|
||||
|
||||
let mir_opt = ccx.sess().cstore.maybe_get_item_mir(ccx.tcx(), def_id);
|
||||
let mir = errors::expect(ccx.sess().diagnostic(),
|
||||
mir_opt,
|
||||
mir_not_found_error_message);
|
||||
let cached = CachedMir::Owned(Rc::new(mir));
|
||||
mir_cache.insert(def_id, cached.clone());
|
||||
cached
|
||||
}
|
||||
}
|
||||
|
||||
fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
|
||||
instance: Instance<'tcx>,
|
||||
recursion_depths: &mut DefIdMap<usize>)
|
||||
|
@ -33,6 +33,7 @@ use trans::datum;
|
||||
use trans::debuginfo::{self, DebugLoc};
|
||||
use trans::declare;
|
||||
use trans::machine;
|
||||
use trans::mir::CachedMir;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::value::Value;
|
||||
@ -40,7 +41,6 @@ use middle::ty::{self, Ty, TyCtxt};
|
||||
use middle::traits::{self, SelectionContext, ProjectionMode};
|
||||
use middle::ty::fold::{TypeFolder, TypeFoldable};
|
||||
use rustc_front::hir;
|
||||
use rustc::mir::repr::Mir;
|
||||
use util::nodemap::NodeMap;
|
||||
|
||||
use arena::TypedArena;
|
||||
@ -273,7 +273,7 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
|
||||
// The MIR for this function. At present, this is optional because
|
||||
// we only have MIR available for things that are local to the
|
||||
// crate.
|
||||
pub mir: Option<&'a Mir<'tcx>>,
|
||||
pub mir: Option<CachedMir<'a, 'tcx>>,
|
||||
|
||||
// The ValueRef returned from a call to llvm::LLVMAddFunction; the
|
||||
// address of the first instruction in the sequence of
|
||||
@ -325,10 +325,6 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
|
||||
// Describes the return/argument LLVM types and their ABI handling.
|
||||
pub fn_ty: FnType,
|
||||
|
||||
// The NodeId of the function, or -1 if it doesn't correspond to
|
||||
// a user-defined function.
|
||||
pub id: ast::NodeId,
|
||||
|
||||
// If this function is being monomorphized, this contains the type
|
||||
// substitutions used.
|
||||
pub param_substs: &'tcx Substs<'tcx>,
|
||||
@ -356,8 +352,8 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
|
||||
pub fn mir(&self) -> &'a Mir<'tcx> {
|
||||
self.mir.unwrap()
|
||||
pub fn mir(&self) -> CachedMir<'a, 'tcx> {
|
||||
self.mir.clone().expect("fcx.mir was empty")
|
||||
}
|
||||
|
||||
pub fn cleanup(&self) {
|
||||
@ -584,7 +580,7 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> {
|
||||
self.lpad.get()
|
||||
}
|
||||
|
||||
pub fn mir(&self) -> &'blk Mir<'tcx> {
|
||||
pub fn mir(&self) -> CachedMir<'blk, 'tcx> {
|
||||
self.fcx.mir()
|
||||
}
|
||||
|
||||
@ -709,7 +705,7 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
|
||||
self.bcx.llbb
|
||||
}
|
||||
|
||||
pub fn mir(&self) -> &'blk Mir<'tcx> {
|
||||
pub fn mir(&self) -> CachedMir<'blk, 'tcx> {
|
||||
self.bcx.mir()
|
||||
}
|
||||
|
||||
|
@ -1003,8 +1003,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
body,
|
||||
e.id,
|
||||
def_id,
|
||||
substs,
|
||||
&e.attrs);
|
||||
substs);
|
||||
}
|
||||
_ =>
|
||||
cx.sess().span_bug(
|
||||
|
@ -16,6 +16,7 @@ use middle::def::ExportMap;
|
||||
use middle::def_id::DefId;
|
||||
use middle::traits;
|
||||
use rustc::mir::mir_map::MirMap;
|
||||
use rustc::mir::repr as mir;
|
||||
use trans::adt;
|
||||
use trans::base;
|
||||
use trans::builder::Builder;
|
||||
@ -23,6 +24,7 @@ use trans::common::BuilderRef_res;
|
||||
use trans::debuginfo;
|
||||
use trans::declare;
|
||||
use trans::glue::DropGlueKind;
|
||||
use trans::mir::CachedMir;
|
||||
use trans::monomorphize::Instance;
|
||||
use trans::collector::{TransItem, TransItemState};
|
||||
use trans::type_::{Type, TypeNames};
|
||||
@ -75,6 +77,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
|
||||
check_overflow: bool,
|
||||
check_drop_flag_for_sanity: bool,
|
||||
mir_map: &'a MirMap<'tcx>,
|
||||
mir_cache: RefCell<DefIdMap<Rc<mir::Mir<'tcx>>>>,
|
||||
|
||||
available_drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, String>>,
|
||||
use_dll_storage_attrs: bool,
|
||||
@ -338,6 +341,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
|
||||
symbol_hasher: RefCell::new(symbol_hasher),
|
||||
tcx: tcx,
|
||||
mir_map: mir_map,
|
||||
mir_cache: RefCell::new(DefIdMap()),
|
||||
stats: Stats {
|
||||
n_glues_created: Cell::new(0),
|
||||
n_null_glues: Cell::new(0),
|
||||
@ -817,8 +821,22 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
|
||||
self.shared.use_dll_storage_attrs()
|
||||
}
|
||||
|
||||
pub fn mir_map(&self) -> &'b MirMap<'tcx> {
|
||||
self.shared.mir_map
|
||||
pub fn get_mir(&self, def_id: DefId) -> Option<CachedMir<'b, 'tcx>> {
|
||||
if def_id.is_local() {
|
||||
let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
|
||||
self.shared.mir_map.map.get(&node_id).map(CachedMir::Ref)
|
||||
} else {
|
||||
if let Some(mir) = self.shared.mir_cache.borrow().get(&def_id).cloned() {
|
||||
return Some(CachedMir::Owned(mir));
|
||||
}
|
||||
|
||||
let mir = self.sess().cstore.maybe_get_item_mir(self.tcx(), def_id);
|
||||
let cached = mir.map(Rc::new);
|
||||
if let Some(ref mir) = cached {
|
||||
self.shared.mir_cache.borrow_mut().insert(def_id, mir.clone());
|
||||
}
|
||||
cached.map(CachedMir::Owned)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
|
||||
|
@ -1141,8 +1141,7 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
body,
|
||||
expr.id,
|
||||
def_id,
|
||||
substs,
|
||||
&expr.attrs).unwrap_or(bcx)
|
||||
substs).unwrap_or(bcx)
|
||||
}
|
||||
hir::ExprCall(ref f, ref args) => {
|
||||
let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
|
||||
|
@ -41,7 +41,6 @@ use trans::type_::Type;
|
||||
use trans::value::Value;
|
||||
|
||||
use arena::TypedArena;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
pub fn trans_exchange_free_dyn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
@ -271,10 +270,9 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
||||
let (arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, ast::DUMMY_NODE_ID,
|
||||
empty_substs, None, &arena);
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &arena);
|
||||
|
||||
let bcx = fcx.init(false);
|
||||
let bcx = fcx.init(false, None);
|
||||
|
||||
update_linkage(ccx, llfn, None, OriginalTranslation);
|
||||
|
||||
|
@ -152,8 +152,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
|
||||
body,
|
||||
llfn,
|
||||
empty_substs,
|
||||
impl_item.id,
|
||||
&impl_item.attrs);
|
||||
impl_item.id);
|
||||
// See linkage comments on items.
|
||||
if ccx.sess().opts.cg.codegen_units == 1 {
|
||||
SetLinkage(llfn, InternalLinkage);
|
||||
|
@ -1267,12 +1267,11 @@ fn gen_fn<'a, 'tcx>(fcx: &FunctionContext<'a, 'tcx>,
|
||||
sig: ty::Binder(sig)
|
||||
});
|
||||
let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
|
||||
let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
|
||||
let (fcx, block_arena);
|
||||
block_arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, ast::DUMMY_NODE_ID,
|
||||
ccx.tcx().mk_substs(Substs::trans_empty()),
|
||||
None, &block_arena);
|
||||
let bcx = fcx.init(true);
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
|
||||
let bcx = fcx.init(true, None);
|
||||
trans(bcx);
|
||||
fcx.cleanup();
|
||||
llfn
|
||||
|
@ -35,7 +35,7 @@ use trans::type_of::*;
|
||||
use trans::value::Value;
|
||||
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
|
||||
use syntax::ast::{self, Name};
|
||||
use syntax::ast::Name;
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
|
||||
// drop_glue pointer, size, align.
|
||||
@ -95,9 +95,8 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
let empty_substs = tcx.mk_substs(Substs::trans_empty());
|
||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
block_arena = TypedArena::new();
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, ast::DUMMY_NODE_ID,
|
||||
empty_substs, None, &block_arena);
|
||||
let mut bcx = fcx.init(false);
|
||||
fcx = FunctionContext::new(ccx, llfn, fn_ty, None, empty_substs, &block_arena);
|
||||
let mut bcx = fcx.init(false, None);
|
||||
assert!(!fcx.needs_ret_allocas);
|
||||
|
||||
|
||||
|
@ -34,7 +34,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
debug!("trans_block({:?})", bb);
|
||||
|
||||
let mut bcx = self.bcx(bb);
|
||||
let data = self.mir.basic_block_data(bb);
|
||||
let mir = self.mir.clone();
|
||||
let data = mir.basic_block_data(bb);
|
||||
|
||||
// MSVC SEH bits
|
||||
let (cleanup_pad, cleanup_bundle) = if let Some((cp, cb)) = self.make_cleanup_pad(bb) {
|
||||
|
@ -10,20 +10,41 @@
|
||||
|
||||
use libc::c_uint;
|
||||
use llvm::{self, ValueRef};
|
||||
use middle::ty;
|
||||
use rustc::mir::repr as mir;
|
||||
use rustc::mir::tcx::LvalueTy;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::common::{self, Block, BlockAndBuilder, FunctionContext};
|
||||
use trans::expr;
|
||||
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
|
||||
use self::lvalue::LvalueRef;
|
||||
use self::operand::OperandRef;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum CachedMir<'mir, 'tcx: 'mir> {
|
||||
Ref(&'mir mir::Mir<'tcx>),
|
||||
Owned(Rc<mir::Mir<'tcx>>)
|
||||
}
|
||||
|
||||
impl<'mir, 'tcx: 'mir> Deref for CachedMir<'mir, 'tcx> {
|
||||
type Target = mir::Mir<'tcx>;
|
||||
fn deref(&self) -> &mir::Mir<'tcx> {
|
||||
match *self {
|
||||
CachedMir::Ref(r) => r,
|
||||
CachedMir::Owned(ref rc) => rc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME DebugLoc is always None right now
|
||||
|
||||
/// Master context for translating MIR.
|
||||
pub struct MirContext<'bcx, 'tcx:'bcx> {
|
||||
mir: &'bcx mir::Mir<'tcx>,
|
||||
mir: CachedMir<'bcx, 'tcx>,
|
||||
|
||||
/// Function context
|
||||
fcx: &'bcx common::FunctionContext<'bcx, 'tcx>,
|
||||
@ -77,7 +98,7 @@ enum TempRef<'tcx> {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
|
||||
let bcx = fcx.init(false).build();
|
||||
let bcx = fcx.init(false, None).build();
|
||||
let mir = bcx.mir();
|
||||
|
||||
let mir_blocks = mir.all_basic_blocks();
|
||||
@ -85,7 +106,7 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
|
||||
// Analyze the temps to determine which must be lvalues
|
||||
// FIXME
|
||||
let lvalue_temps = bcx.with_block(|bcx| {
|
||||
analyze::lvalue_temps(bcx, mir)
|
||||
analyze::lvalue_temps(bcx, &mir)
|
||||
});
|
||||
|
||||
// Allocate variable and temp allocas
|
||||
@ -107,7 +128,7 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
|
||||
TempRef::Operand(None)
|
||||
})
|
||||
.collect();
|
||||
let args = arg_value_refs(&bcx, mir);
|
||||
let args = arg_value_refs(&bcx, &mir);
|
||||
|
||||
// Allocate a `Block` for every basic block
|
||||
let block_bcxs: Vec<Block<'blk,'tcx>> =
|
||||
|
@ -151,7 +151,7 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
}
|
||||
|
||||
if trans_everywhere || is_first {
|
||||
trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id, attrs);
|
||||
trans_fn(ccx, decl, body, lldecl, psubsts, fn_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user