pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                   decl: &ast::FnDecl,
                                   body: &ast::Block,
                                   llfndecl: ValueRef,
                                   param_substs: &'tcx Substs<'tcx>,
                                   fn_ast_id: ast::NodeId,
                                   _attributes: &[ast::Attribute],
                                   output_type: ty::FnOutput<'tcx>,
                                   abi: Abi,
                                   closure_env: closure::ClosureEnv<'b>) {
    ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);

    let _icx = push_ctxt("trans_closure");
    attributes::emit_uwtable(llfndecl, true);

    debug!("trans_closure(..., param_substs={})",
           param_substs.repr(ccx.tcx()));

    let has_env = match closure_env {
        closure::ClosureEnv::Closure(_) => true,
        closure::ClosureEnv::NotClosure => false,
    };

    let (arena, fcx): (TypedArena<_>, FunctionContext);
    arena = TypedArena::new();
    fcx = new_fn_ctxt(ccx,
                      llfndecl,
                      fn_ast_id,
                      has_env,
                      output_type,
                      param_substs,
                      Some(body.span),
                      &arena);
    let mut bcx = init_function(&fcx, false, output_type);

    // 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 arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);

    let block_ty = node_id_type(bcx, body.id);

    // Set up arguments to the function.
    let monomorphized_arg_types =
        decl.inputs.iter()
                   .map(|arg| node_id_type(bcx, arg.id))
                   .collect::<Vec<_>>();
    let monomorphized_arg_types = match closure_env {
        closure::ClosureEnv::NotClosure => {
            monomorphized_arg_types
        }

        // Tuple up closure argument types for the "rust-call" ABI.
        closure::ClosureEnv::Closure(_) => {
            vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)]
        }
    };
    for monomorphized_arg_type in &monomorphized_arg_types {
        debug!("trans_closure: monomorphized_arg_type: {}",
               ty_to_string(ccx.tcx(), *monomorphized_arg_type));
    }
    debug!("trans_closure: function lltype: {}",
           bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));

    let arg_datums = match closure_env {
        closure::ClosureEnv::NotClosure if abi == RustCall => {
            create_datums_for_fn_args_under_call_abi(bcx, arg_scope, &monomorphized_arg_types[..])
        }
        _ => {
            let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi);
            create_datums_for_fn_args(&fcx, &arg_tys)
        }
    };

    bcx = copy_args_to_allocas(bcx, arg_scope, &decl.inputs, arg_datums);

    bcx = closure_env.load(bcx, cleanup::CustomScope(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
    // emitting should be enabled.
    debuginfo::start_emitting_source_locations(&fcx);

    let dest = match fcx.llretslotptr.get() {
        Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, ty::FnConverging(block_ty), "iret_slot")),
        None => {
            assert!(type_is_zero_size(bcx.ccx(), block_ty));
            expr::Ignore
        }
    };

    // This call to trans_block is the place where we bridge between
    // translation calls that don't have a return value (trans_crate,
    // trans_mod, trans_item, et cetera) and those that do
    // (trans_block, trans_expr, et cetera).
    bcx = controlflow::trans_block(bcx, body, dest);

    match dest {
        expr::SaveIn(slot) if fcx.needs_ret_allocas => {
            Store(bcx, slot, fcx.llretslotptr.get().unwrap());
        }
        _ => {}
    }

    match fcx.llreturn.get() {
        Some(_) => {
            Br(bcx, fcx.return_exit_block(), DebugLoc::None);
            fcx.pop_custom_cleanup_scope(arg_scope);
        }
        None => {
            // Microoptimization writ large: avoid creating a separate
            // llreturn basic block
            bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
        }
    };

    // Put return block after all other blocks.
    // This somewhat improves single-stepping experience in debugger.
    unsafe {
        let llreturn = fcx.llreturn.get();
        if let Some(llreturn) = llreturn {
            llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
        }
    }

    let ret_debug_loc = DebugLoc::At(fn_cleanup_debug_loc.id,
                                     fn_cleanup_debug_loc.span);

    // Insert the mandatory first few basic blocks before lltop.
    finish_fn(&fcx, bcx, output_type, ret_debug_loc);
}
/// 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.
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,
                                   llfndecl: ValueRef,
                                   param_substs: &'tcx Substs<'tcx>,
                                   fn_ast_id: ast::NodeId,
                                   _attributes: &[ast::Attribute],
                                   output_type: ty::FnOutput<'tcx>,
                                   abi: Abi,
                                   closure_env: closure::ClosureEnv<'b>) {
    ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
    let _icx = push_ctxt("trans_closure");
    attributes::emit_uwtable(llfndecl, true);
    debug!("trans_closure(..., param_substs={})",
           param_substs.repr(ccx.tcx()));
    let has_env = match closure_env {
        closure::ClosureEnv::Closure(_) => true,
        closure::ClosureEnv::NotClosure => false,
    };
    let (arena, fcx): (TypedArena<_>, FunctionContext);
    arena = TypedArena::new();
    fcx = new_fn_ctxt(ccx,
                      llfndecl,
                      fn_ast_id,
                      has_env,
                      output_type,
                      param_substs,
                      Some(body.span),
                      &arena);
    let mut bcx = init_function(&fcx, false, output_type);
    // 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 arg_scope = fcx.push_custom_cleanup_scope_with_debug_loc(fn_cleanup_debug_loc);
    let block_ty = node_id_type(bcx, body.id);
    // Set up arguments to the function.
    let monomorphized_arg_types =
        decl.inputs.iter()
                   .map(|arg| node_id_type(bcx, arg.id))
                   .collect::<Vec<_>>();
    let monomorphized_arg_types = match closure_env {
        closure::ClosureEnv::NotClosure => {
            monomorphized_arg_types
        }
        // Tuple up closure argument types for the "rust-call" ABI.
        closure::ClosureEnv::Closure(_) => {
            vec![ty::mk_tup(ccx.tcx(), monomorphized_arg_types)]
        }
    };
    for monomorphized_arg_type in &monomorphized_arg_types {
        debug!("trans_closure: monomorphized_arg_type: {}",
               ty_to_string(ccx.tcx(), *monomorphized_arg_type));
    }
    debug!("trans_closure: function lltype: {}",
           bcx.fcx.ccx.tn().val_to_string(bcx.fcx.llfn));
    let arg_datums = match closure_env {
        closure::ClosureEnv::NotClosure if abi == RustCall => {
            create_datums_for_fn_args_under_call_abi(bcx, arg_scope, &monomorphized_arg_types[..])
        }
        _ => {
            let arg_tys = untuple_arguments_if_necessary(ccx, &monomorphized_arg_types, abi);
            create_datums_for_fn_args(&fcx, &arg_tys)
        }
    };
    bcx = copy_args_to_allocas(bcx, arg_scope, &decl.inputs, arg_datums);
    bcx = closure_env.load(bcx, cleanup::CustomScope(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
    // emitting should be enabled.
    debuginfo::start_emitting_source_locations(&fcx);
    let dest = match fcx.llretslotptr.get() {
        Some(_) => expr::SaveIn(fcx.get_ret_slot(bcx, ty::FnConverging(block_ty), "iret_slot")),
        None => {
            assert!(type_is_zero_size(bcx.ccx(), block_ty));
            expr::Ignore
        }
    };
    // This call to trans_block is the place where we bridge between
    // translation calls that don't have a return value (trans_crate,
    // trans_mod, trans_item, et cetera) and those that do
    // (trans_block, trans_expr, et cetera).
    bcx = controlflow::trans_block(bcx, body, dest);
    match dest {
        expr::SaveIn(slot) if fcx.needs_ret_allocas => {
            Store(bcx, slot, fcx.llretslotptr.get().unwrap());
        }
        _ => {}
    }
    match fcx.llreturn.get() {
        Some(_) => {
            Br(bcx, fcx.return_exit_block(), DebugLoc::None);
            fcx.pop_custom_cleanup_scope(arg_scope);
        }
        None => {
            // Microoptimization writ large: avoid creating a separate
            // llreturn basic block
            bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
        }
    };
    // Put return block after all other blocks.
    // This somewhat improves single-stepping experience in debugger.
    unsafe {
        let llreturn = fcx.llreturn.get();
        if let Some(llreturn) = llreturn {
            llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
        }
    }
    let ret_debug_loc = DebugLoc::At(fn_cleanup_debug_loc.id,
                                     fn_cleanup_debug_loc.span);
    // Insert the mandatory first few basic blocks before lltop.
    finish_fn(&fcx, bcx, output_type, ret_debug_loc);
}
pub fn trans_closure < ' a , ' b , ' tcx > ( ccx : & CrateContext < ' a , ' tcx > , decl : & ast :: FnDecl , body : & ast :: Block , llfndecl : ValueRef , param_substs : & ' tcx Substs < ' tcx > , fn_ast_id : ast :: NodeId , _attributes : & [ ast :: Attribute ] , output_type : ty :: FnOutput < ' tcx > , abi : Abi , closure_env : closure :: ClosureEnv < ' b > ) { ccx . stats ( ) . n_closures . set ( ccx . stats ( ) . n_closures . get ( ) + 1 ) ; let _icx = push_ctxt ( " " ) ; attributes :: emit_uwtable ( llfndecl , true ) ; debug ! ( " " param_substs repr ( ccx tcx ( ) ) ) ; let has_env = match closure_env { closure :: ClosureEnv :: Closure ( _ ) => true , closure :: ClosureEnv :: NotClosure => false , } ; let ( arena , fcx ) : ( TypedArena < _ > , FunctionContext ) ; arena = TypedArena :: new ( ) ; fcx = new_fn_ctxt ( ccx , llfndecl , fn_ast_id , has_env , output_type , param_substs , Some ( body . span ) , & arena ) ; let mut bcx = init_function ( & fcx , false , output_type ) ; // 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 arg_scope = fcx . push_custom_cleanup_scope_with_debug_loc ( fn_cleanup_debug_loc ) ; let block_ty = node_id_type ( bcx , body . id ) ; // Set up arguments to the function. let monomorphized_arg_types = decl . inputs . iter ( ) . map ( | arg | node_id_type ( bcx , arg . id ) ) . collect :: < Vec < _ > > ( ) ; let monomorphized_arg_types = match closure_env { closure :: ClosureEnv :: NotClosure => { monomorphized_arg_types } // Tuple up closure argument types for the "rust-call" ABI. closure :: ClosureEnv :: Closure ( _ ) => { vec ! [ ty mk_tup ( ccx tcx ( ) monomorphized_arg_types ) ] } } ; for monomorphized_arg_type in & monomorphized_arg_types { debug ! ( " " ty_to_string ( ccx tcx ( ) monomorphized_arg_type ) ) ; } debug ! ( " " bcx fcx ccx tn ( ) val_to_string ( bcx fcx llfn ) ) ; let arg_datums = match closure_env { closure :: ClosureEnv :: NotClosure if abi == RustCall => { create_datums_for_fn_args_under_call_abi ( bcx , arg_scope , & monomorphized_arg_types [ .. ] ) } _ => { let arg_tys = untuple_arguments_if_necessary ( ccx , & monomorphized_arg_types , abi ) ; create_datums_for_fn_args ( & fcx , & arg_tys ) } } ; bcx = copy_args_to_allocas ( bcx , arg_scope , & decl . inputs , arg_datums ) ; bcx = closure_env . load ( bcx , cleanup :: CustomScope ( 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 // emitting should be enabled. debuginfo :: start_emitting_source_locations ( & fcx ) ; let dest = match fcx . llretslotptr . get ( ) { Some ( _ ) => expr :: SaveIn ( fcx . get_ret_slot ( bcx , ty :: FnConverging ( block_ty ) , " " ) ) , None => { assert ! ( type_is_zero_size ( bcx ccx ( ) block_ty ) ) ; expr :: Ignore } } ; // This call to trans_block is the place where we bridge between // translation calls that don't have a return value (trans_crate, // trans_mod, trans_item, et cetera) and those that do // (trans_block, trans_expr, et cetera). bcx = controlflow :: trans_block ( bcx , body , dest ) ; match dest { expr :: SaveIn ( slot ) if fcx . needs_ret_allocas => { Store ( bcx , slot , fcx . llretslotptr . get ( ) . unwrap ( ) ) ; } _ => { } } match fcx . llreturn . get ( ) { Some ( _ ) => { Br ( bcx , fcx . return_exit_block ( ) , DebugLoc :: None ) ; fcx . pop_custom_cleanup_scope ( arg_scope ) ; } None => { // Microoptimization writ large: avoid creating a separate // llreturn basic block bcx = fcx . pop_and_trans_custom_cleanup_scope ( bcx , arg_scope ) ; } } ; // Put return block after all other blocks. // This somewhat improves single-stepping experience in debugger. unsafe { let llreturn = fcx . llreturn . get ( ) ; if let Some ( llreturn ) = llreturn { llvm :: LLVMMoveBasicBlockAfter ( llreturn , bcx . llbb ) ; } } let ret_debug_loc = DebugLoc :: At ( fn_cleanup_debug_loc . id , fn_cleanup_debug_loc . span ) ; // Insert the mandatory first few basic blocks before lltop. finish_fn ( & fcx , bcx , output_type , ret_debug_loc ) ; }
Builds an LLVM function out of a source function.
Builds an LLVM function out of a source function .
ccx
&CrateContext<'a, 'tcx>
decl
&ast::FnDecl
body
&ast::Block
llfndecl
ValueRef
param_substs
&'tcx Substs<'tcx>
fn_ast_id
ast::NodeId
_attributes
&[ast::Attribute]
output_type
ty::FnOutput<'tcx>
abi
Abi
closure_env
closure::ClosureEnv<'b>