trans: Don't treat closure types like function types in declare.
This commit is contained in:
parent
da66431d06
commit
3342da4113
5 changed files with 64 additions and 99 deletions
|
|
@ -13,13 +13,11 @@ use libc::{c_uint, c_ulonglong};
|
|||
use llvm::{self, ValueRef, AttrHelper};
|
||||
use middle::ty;
|
||||
use middle::infer;
|
||||
use middle::traits::ProjectionMode;
|
||||
use session::config::NoDebugInfo;
|
||||
pub use syntax::attr::InlineAttr;
|
||||
use syntax::ast;
|
||||
use rustc_front::hir;
|
||||
use trans::abi::Abi;
|
||||
use trans::base;
|
||||
use trans::common;
|
||||
use trans::context::CrateContext;
|
||||
use trans::machine;
|
||||
|
|
@ -130,21 +128,12 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
|
|||
-> llvm::AttrBuilder {
|
||||
use middle::ty::{BrAnon, ReLateBound};
|
||||
|
||||
let function_type;
|
||||
let (fn_sig, abi, env_ty) = match fn_type.sty {
|
||||
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => (&f.sig, f.abi, None),
|
||||
ty::TyClosure(closure_did, ref substs) => {
|
||||
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
|
||||
&ccx.tcx().tables,
|
||||
ProjectionMode::Any);
|
||||
function_type = infcx.closure_type(closure_did, substs);
|
||||
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
|
||||
(&function_type.sig, Abi::RustCall, Some(self_type))
|
||||
}
|
||||
_ => ccx.sess().bug("expected closure or function.")
|
||||
let f = match fn_type.sty {
|
||||
ty::TyFnDef(_, _, f) | ty::TyFnPtr(f) => f,
|
||||
_ => unreachable!("expected fn type, found {:?}", fn_type)
|
||||
};
|
||||
|
||||
let fn_sig = ccx.tcx().erase_late_bound_regions(fn_sig);
|
||||
let fn_sig = ccx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let fn_sig = infer::normalize_associated_type(ccx.tcx(), &fn_sig);
|
||||
|
||||
let mut attrs = llvm::AttrBuilder::new();
|
||||
|
|
@ -153,30 +142,17 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
|
|||
// These have an odd calling convention, so we need to manually
|
||||
// unpack the input ty's
|
||||
let input_tys = match fn_type.sty {
|
||||
ty::TyClosure(..) => {
|
||||
assert!(abi == Abi::RustCall);
|
||||
|
||||
match fn_sig.inputs[0].sty {
|
||||
ty::TyTuple(ref inputs) => {
|
||||
let mut full_inputs = vec![env_ty.expect("Missing closure environment")];
|
||||
full_inputs.extend_from_slice(inputs);
|
||||
full_inputs
|
||||
}
|
||||
_ => ccx.sess().bug("expected tuple'd inputs")
|
||||
}
|
||||
},
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) if abi == Abi::RustCall => {
|
||||
let mut inputs = vec![fn_sig.inputs[0]];
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) if f.abi == Abi::RustCall => {
|
||||
let first = Some(fn_sig.inputs[0]).into_iter();
|
||||
|
||||
match fn_sig.inputs[1].sty {
|
||||
ty::TyTuple(ref t_in) => {
|
||||
inputs.extend_from_slice(&t_in[..]);
|
||||
inputs
|
||||
first.chain(t_in.iter().cloned())
|
||||
}
|
||||
_ => ccx.sess().bug("expected tuple'd inputs")
|
||||
}
|
||||
}
|
||||
_ => fn_sig.inputs.clone()
|
||||
_ => None.into_iter().chain(fn_sig.inputs.iter().cloned())
|
||||
};
|
||||
|
||||
// Index 0 is the return value of the llvm func, so we start at 1
|
||||
|
|
@ -228,7 +204,7 @@ pub fn from_fn_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn_type: ty::Ty<'tcx
|
|||
}
|
||||
}
|
||||
|
||||
for &t in input_tys.iter() {
|
||||
for t in input_tys {
|
||||
match t.sty {
|
||||
_ if type_of::arg_is_indirect(ccx, t) => {
|
||||
let llarg_sz = machine::llsize_of_real(ccx, type_of::type_of(ccx, t));
|
||||
|
|
|
|||
|
|
@ -192,22 +192,6 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn self_type_for_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
closure_id: DefId,
|
||||
fn_ty: Ty<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
let closure_kind = ccx.tcx().closure_kind(closure_id);
|
||||
match closure_kind {
|
||||
ty::ClosureKind::Fn => {
|
||||
ccx.tcx().mk_imm_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty)
|
||||
}
|
||||
ty::ClosureKind::FnMut => {
|
||||
ccx.tcx().mk_mut_ref(ccx.tcx().mk_region(ty::ReStatic), fn_ty)
|
||||
}
|
||||
ty::ClosureKind::FnOnce => fn_ty,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind_for_closure(ccx: &CrateContext, closure_id: DefId) -> ty::ClosureKind {
|
||||
*ccx.tcx().tables.borrow().closure_kinds.get(&closure_id).unwrap()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use llvm::{ValueRef, get_params};
|
|||
use middle::def_id::DefId;
|
||||
use middle::infer;
|
||||
use middle::traits::ProjectionMode;
|
||||
use trans::abi::Abi::RustCall;
|
||||
use trans::abi::Abi;
|
||||
use trans::adt;
|
||||
use trans::attributes;
|
||||
use trans::base::*;
|
||||
|
|
@ -30,7 +30,7 @@ use trans::monomorphize::{Instance};
|
|||
use trans::type_of::*;
|
||||
use trans::value::Value;
|
||||
use trans::Disr;
|
||||
use middle::ty;
|
||||
use middle::ty::{self, Ty, TyCtxt};
|
||||
use session::config::FullDebugInfo;
|
||||
|
||||
use syntax::ast;
|
||||
|
|
@ -49,7 +49,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
// Special case for small by-value selfs.
|
||||
let closure_ty = node_id_type(bcx, bcx.fcx.id);
|
||||
let self_type = self_type_for_closure(bcx.ccx(), closure_def_id, closure_ty);
|
||||
let self_type = get_self_type(bcx.tcx(), closure_def_id, closure_ty);
|
||||
let kind = kind_for_closure(bcx.ccx(), closure_def_id);
|
||||
let llenv = if kind == ty::ClosureKind::FnOnce &&
|
||||
!arg_is_indirect(bcx.ccx(), self_type) {
|
||||
|
|
@ -131,6 +131,21 @@ impl<'a> ClosureEnv<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_self_type<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
closure_id: DefId,
|
||||
fn_ty: Ty<'tcx>)
|
||||
-> Ty<'tcx> {
|
||||
match tcx.closure_kind(closure_id) {
|
||||
ty::ClosureKind::Fn => {
|
||||
tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), fn_ty)
|
||||
}
|
||||
ty::ClosureKind::FnMut => {
|
||||
tcx.mk_mut_ref(tcx.mk_region(ty::ReStatic), fn_ty)
|
||||
}
|
||||
ty::ClosureKind::FnOnce => fn_ty,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the LLVM function declaration for a closure, creating it if
|
||||
/// necessary. If the ID does not correspond to a closure ID, returns None.
|
||||
pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
|
|
@ -139,22 +154,38 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
-> ValueRef {
|
||||
// Normalize type so differences in regions and typedefs don't cause
|
||||
// duplicate declarations
|
||||
let substs = ccx.tcx().erase_regions(substs);
|
||||
let mono_id = Instance {
|
||||
let tcx = ccx.tcx();
|
||||
let substs = tcx.erase_regions(substs);
|
||||
let instance = Instance {
|
||||
def: closure_id,
|
||||
params: &substs.func_substs.types
|
||||
};
|
||||
|
||||
if let Some(&llfn) = ccx.closure_vals().borrow().get(&mono_id) {
|
||||
if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
|
||||
debug!("get_or_create_closure_declaration(): found closure {:?}: {:?}",
|
||||
mono_id, Value(llfn));
|
||||
instance, Value(llfn));
|
||||
return llfn;
|
||||
}
|
||||
|
||||
let path = ccx.tcx().def_path(closure_id);
|
||||
let path = tcx.def_path(closure_id);
|
||||
let symbol = mangle_internal_name_by_path_and_seq(path, "closure");
|
||||
|
||||
let function_type = ccx.tcx().mk_closure_from_closure_substs(closure_id, Box::new(substs));
|
||||
// Compute the rust-call form of the closure call method.
|
||||
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
|
||||
let sig = &infcx.closure_type(closure_id, &substs).sig;
|
||||
let sig = tcx.erase_late_bound_regions(sig);
|
||||
let sig = infer::normalize_associated_type(tcx, &sig);
|
||||
let closure_type = tcx.mk_closure_from_closure_substs(closure_id, Box::new(substs));
|
||||
let function_type = tcx.mk_fn_ptr(ty::BareFnTy {
|
||||
unsafety: hir::Unsafety::Normal,
|
||||
abi: Abi::RustCall,
|
||||
sig: ty::Binder(ty::FnSig {
|
||||
inputs: Some(get_self_type(tcx, closure_id, closure_type))
|
||||
.into_iter().chain(sig.inputs).collect(),
|
||||
output: sig.output,
|
||||
variadic: false
|
||||
})
|
||||
});
|
||||
let llfn = declare::define_internal_fn(ccx, &symbol, function_type);
|
||||
|
||||
// set an inline hint for all closures
|
||||
|
|
@ -162,8 +193,8 @@ pub fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
debug!("get_or_create_declaration_if_closure(): inserting new \
|
||||
closure {:?}: {:?}",
|
||||
mono_id, Value(llfn));
|
||||
ccx.closure_vals().borrow_mut().insert(mono_id, llfn);
|
||||
instance, Value(llfn));
|
||||
ccx.instances().borrow_mut().insert(instance, llfn);
|
||||
|
||||
llfn
|
||||
}
|
||||
|
|
@ -347,7 +378,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||
|
||||
// Make a version of the closure type with the same arguments, but
|
||||
// with argument #0 being by value.
|
||||
assert_eq!(abi, RustCall);
|
||||
assert_eq!(abi, Abi::RustCall);
|
||||
sig.0.inputs[0] = closure_ty;
|
||||
let llonce_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
|
||||
unsafety: unsafety,
|
||||
|
|
|
|||
|
|
@ -22,10 +22,8 @@
|
|||
use llvm::{self, ValueRef};
|
||||
use middle::ty;
|
||||
use middle::infer;
|
||||
use middle::traits::ProjectionMode;
|
||||
use trans::abi::{Abi, FnType};
|
||||
use trans::attributes;
|
||||
use trans::base;
|
||||
use trans::context::CrateContext;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
|
|
@ -94,37 +92,21 @@ pub fn declare_cfn(ccx: &CrateContext, name: &str, fn_type: Type) -> ValueRef {
|
|||
/// update the declaration and return existing ValueRef instead.
|
||||
pub fn declare_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);
|
||||
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
|
||||
|
||||
let function_type; // placeholder so that the memory ownership works out ok
|
||||
let (sig, abi, env) = match fn_type.sty {
|
||||
ty::TyFnDef(_, _, f) |
|
||||
ty::TyFnPtr(f) => {
|
||||
(&f.sig, f.abi, None)
|
||||
}
|
||||
ty::TyClosure(closure_did, ref substs) => {
|
||||
let infcx = infer::normalizing_infer_ctxt(ccx.tcx(),
|
||||
&ccx.tcx().tables,
|
||||
ProjectionMode::Any);
|
||||
function_type = infcx.closure_type(closure_did, substs);
|
||||
let self_type = base::self_type_for_closure(ccx, closure_did, fn_type);
|
||||
debug!("declare_rust_fn function_type={:?} self_type={:?}",
|
||||
function_type, self_type);
|
||||
(&function_type.sig, Abi::RustCall, Some(self_type))
|
||||
}
|
||||
_ => ccx.sess().bug("expected closure or fn")
|
||||
let f = match fn_type.sty {
|
||||
ty::TyFnDef(_, _, f) | ty::TyFnPtr(f) => f,
|
||||
_ => unreachable!("expected fn type for {:?}, found {:?}", name, fn_type)
|
||||
};
|
||||
|
||||
|
||||
let sig = ccx.tcx().erase_late_bound_regions(sig);
|
||||
let sig = ccx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
|
||||
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
|
||||
|
||||
let (cconv, llfty) = if abi == Abi::Rust || abi == Abi::RustCall {
|
||||
(llvm::CCallConv, type_of::type_of_rust_fn(ccx, env, &sig, abi))
|
||||
let (cconv, llfty) = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
(llvm::CCallConv, type_of::type_of_rust_fn(ccx, &sig, f.abi))
|
||||
} else {
|
||||
let fty = FnType::new(ccx, abi, &sig, &[]);
|
||||
let fty = FnType::new(ccx, f.abi, &sig, &[]);
|
||||
(fty.cconv, fty.to_llvm(ccx))
|
||||
};
|
||||
|
||||
|
|
@ -137,10 +119,10 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
|
|||
llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn);
|
||||
}
|
||||
|
||||
if abi == Abi::Rust || abi == Abi::RustCall {
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
|
||||
} else {
|
||||
FnType::new(ccx, abi, &sig, &[]).add_attributes(llfn);
|
||||
FnType::new(ccx, f.abi, &sig, &[]).add_attributes(llfn);
|
||||
}
|
||||
|
||||
llfn
|
||||
|
|
|
|||
|
|
@ -88,14 +88,11 @@ pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
}
|
||||
|
||||
pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
maybe_env: Option<Ty<'tcx>>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
abi: Abi)
|
||||
-> Type
|
||||
{
|
||||
debug!("type_of_rust_fn(sig={:?},abi={:?})",
|
||||
sig,
|
||||
abi);
|
||||
debug!("type_of_rust_fn(sig={:?}, abi={:?})", sig, abi);
|
||||
|
||||
assert!(!sig.variadic); // rust fns are never variadic
|
||||
|
||||
|
|
@ -129,11 +126,6 @@ pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
ty::FnDiverging => Type::void(cx)
|
||||
};
|
||||
|
||||
// Arg 1: Environment
|
||||
if let Some(env_ty) = maybe_env {
|
||||
atys.push(type_of_explicit_arg(cx, env_ty));
|
||||
}
|
||||
|
||||
// ... then explicit args.
|
||||
for input in inputs {
|
||||
let arg_ty = type_of_explicit_arg(cx, input);
|
||||
|
|
@ -384,7 +376,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
|||
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
type_of_rust_fn(cx, None, &sig, f.abi).ptr_to()
|
||||
type_of_rust_fn(cx, &sig, f.abi).ptr_to()
|
||||
} else {
|
||||
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue