提交 3342da41 编写于 作者: E Eduard Burtescu

trans: Don't treat closure types like function types in declare.

上级 da66431d
......@@ -13,13 +13,11 @@
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 @@ fn drop(&mut self) {
}
}
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 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::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 @@ pub fn load<'blk,'tcx>(self, bcx: Block<'blk, 'tcx>, arg_scope: ScopeId)
}
}
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);
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")
};
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
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()
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册