trans: Reify functions & methods to fn ptrs only where necessary.
This commit is contained in:
parent
c284099f56
commit
8f07f8a4fa
28 changed files with 683 additions and 1318 deletions
|
|
@ -148,11 +148,11 @@ impl<'tcx> Substs<'tcx> {
|
|||
Substs { types: types, regions: regions }
|
||||
}
|
||||
|
||||
pub fn with_method_from(self,
|
||||
pub fn with_method_from(&self,
|
||||
meth_substs: &Substs<'tcx>)
|
||||
-> Substs<'tcx>
|
||||
{
|
||||
let Substs { types, regions } = self;
|
||||
let Substs { types, regions } = self.clone();
|
||||
let types = types.with_slice(FnSpace, meth_substs.types.get_slice(FnSpace));
|
||||
let regions = regions.map(|r| {
|
||||
r.with_slice(FnSpace, meth_substs.regions().get_slice(FnSpace))
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ pub enum Vtable<'tcx, N> {
|
|||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct VtableImplData<'tcx, N> {
|
||||
pub impl_def_id: DefId,
|
||||
pub substs: subst::Substs<'tcx>,
|
||||
pub substs: &'tcx subst::Substs<'tcx>,
|
||||
pub nested: Vec<N>
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -948,7 +948,7 @@ fn confirm_impl_candidate<'cx,'tcx>(
|
|||
for impl_item in &selcx.tcx().impl_items.borrow()[&impl_vtable.impl_def_id] {
|
||||
if let ty::TypeTraitItem(ref assoc_ty) = impl_or_trait_items_map[&impl_item.def_id()] {
|
||||
if assoc_ty.name == obligation.predicate.item_name {
|
||||
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), &impl_vtable.substs),
|
||||
return (assoc_ty.ty.unwrap().subst(selcx.tcx(), impl_vtable.substs),
|
||||
impl_vtable.nested);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2305,7 +2305,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
impl_obligations.append(&mut substs.obligations);
|
||||
|
||||
VtableImplData { impl_def_id: impl_def_id,
|
||||
substs: substs.value,
|
||||
substs: self.tcx().mk_substs(substs.value),
|
||||
nested: impl_obligations }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,9 +147,10 @@ impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx
|
|||
|
||||
impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::VtableImplData<'tcx, N> {
|
||||
fn super_fold_with<F:TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
|
||||
let substs = self.substs.fold_with(folder);
|
||||
traits::VtableImplData {
|
||||
impl_def_id: self.impl_def_id,
|
||||
substs: self.substs.fold_with(folder),
|
||||
substs: folder.tcx().mk_substs(substs),
|
||||
nested: self.nested.fold_with(folder),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -602,14 +602,14 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
#[derive(Debug)]
|
||||
pub struct ImplMethod<'tcx> {
|
||||
pub method: Rc<ty::Method<'tcx>>,
|
||||
pub substs: Substs<'tcx>,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
pub is_provided: bool
|
||||
}
|
||||
|
||||
impl<'tcx> TyCtxt<'tcx> {
|
||||
pub fn get_impl_method(&self,
|
||||
impl_def_id: DefId,
|
||||
substs: Substs<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
name: Name)
|
||||
-> ImplMethod<'tcx>
|
||||
{
|
||||
|
|
@ -636,9 +636,10 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
if meth.name == name {
|
||||
let impl_to_trait_substs = self
|
||||
.make_substs_for_receiver_types(&trait_ref, meth);
|
||||
let substs = impl_to_trait_substs.subst(self, substs);
|
||||
return ImplMethod {
|
||||
method: meth.clone(),
|
||||
substs: impl_to_trait_substs.subst(self, &substs),
|
||||
substs: self.mk_substs(substs),
|
||||
is_provided: true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -861,20 +861,10 @@ impl<'tcx> Debug for TypedConstVal<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum ItemKind {
|
||||
Constant,
|
||||
/// This is any sort of callable (usually those that have a type of `fn(…) -> …`). This
|
||||
/// includes functions, constructors, but not methods which have their own ItemKind.
|
||||
Function,
|
||||
Method,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Literal<'tcx> {
|
||||
Item {
|
||||
def_id: DefId,
|
||||
kind: ItemKind,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
},
|
||||
Value {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
//! kind of thing.
|
||||
|
||||
use build::Builder;
|
||||
use hair::*;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc::mir::repr::*;
|
||||
use std::u32;
|
||||
|
|
@ -59,16 +58,4 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
});
|
||||
temp
|
||||
}
|
||||
|
||||
pub fn item_ref_operand(&mut self,
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>)
|
||||
-> Operand<'tcx> {
|
||||
let literal = Literal::Item {
|
||||
def_id: item_ref.def_id,
|
||||
kind: item_ref.kind,
|
||||
substs: item_ref.substs,
|
||||
};
|
||||
self.literal_operand(span, item_ref.ty, literal)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -503,7 +503,6 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
ty: self.hir.tcx().lookup_item_type(funcdid).ty,
|
||||
literal: Literal::Item {
|
||||
def_id: funcdid,
|
||||
kind: ItemKind::Function,
|
||||
substs: self.hir.tcx().mk_substs(Substs::empty())
|
||||
}
|
||||
}
|
||||
|
|
@ -641,7 +640,6 @@ fn build_free<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||
ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs),
|
||||
literal: Literal::Item {
|
||||
def_id: free_func,
|
||||
kind: ItemKind::Function,
|
||||
substs: substs
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -581,7 +581,6 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
|
|||
kind: ExprKind::Literal {
|
||||
literal: Literal::Item {
|
||||
def_id: callee.def_id,
|
||||
kind: ItemKind::Method,
|
||||
substs: callee.substs,
|
||||
},
|
||||
},
|
||||
|
|
@ -618,14 +617,13 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
|
|||
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
|
||||
// Otherwise there may be def_map borrow conflicts
|
||||
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
|
||||
let (def_id, kind) = match def {
|
||||
let def_id = match def {
|
||||
// A regular function.
|
||||
Def::Fn(def_id) => (def_id, ItemKind::Function),
|
||||
Def::Method(def_id) => (def_id, ItemKind::Method),
|
||||
Def::Fn(def_id) | Def::Method(def_id) => def_id,
|
||||
Def::Struct(def_id) => match cx.tcx.node_id_to_type(expr.id).sty {
|
||||
// A tuple-struct constructor. Should only be reached if not called in the same
|
||||
// expression.
|
||||
ty::TyFnDef(..) => (def_id, ItemKind::Function),
|
||||
ty::TyFnDef(..) => def_id,
|
||||
// A unit struct which is used as a value. We return a completely different ExprKind
|
||||
// here to account for this special case.
|
||||
ty::TyStruct(adt_def, substs) => return ExprKind::Adt {
|
||||
|
|
@ -640,7 +638,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
|
|||
Def::Variant(enum_id, variant_id) => match cx.tcx.node_id_to_type(expr.id).sty {
|
||||
// A variant constructor. Should only be reached if not called in the same
|
||||
// expression.
|
||||
ty::TyFnDef(..) => (variant_id, ItemKind::Function),
|
||||
ty::TyFnDef(..) => variant_id,
|
||||
// A unit variant, similar special case to the struct case above.
|
||||
ty::TyEnum(adt_def, substs) => {
|
||||
debug_assert!(adt_def.did == enum_id);
|
||||
|
|
@ -660,7 +658,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
|
|||
if let Some(v) = cx.try_const_eval_literal(expr) {
|
||||
return ExprKind::Literal { literal: v };
|
||||
} else {
|
||||
(def_id, ItemKind::Constant)
|
||||
def_id
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -677,7 +675,7 @@ fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr)
|
|||
&format!("def `{:?}` not yet implemented", def)),
|
||||
};
|
||||
ExprKind::Literal {
|
||||
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
|
||||
literal: Literal::Item { def_id: def_id, substs: substs }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
//! unit-tested and separated from the Rust source and compiler data
|
||||
//! structures.
|
||||
|
||||
use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind,
|
||||
use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp,
|
||||
TypedConstVal};
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
|
|
@ -28,14 +28,6 @@ use self::cx::Cx;
|
|||
|
||||
pub mod cx;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ItemRef<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub kind: ItemKind,
|
||||
pub def_id: DefId,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block<'tcx> {
|
||||
pub extent: CodeExtent,
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
|||
expr_ty(bcx, &out.expr),
|
||||
out_datum,
|
||||
cleanup::CustomScope(temp_scope),
|
||||
callee::DontAutorefArg,
|
||||
&mut inputs);
|
||||
if out.is_rw {
|
||||
ext_inputs.push(*inputs.last().unwrap());
|
||||
|
|
@ -64,7 +63,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
|||
expr_ty(bcx, &out.expr),
|
||||
out_datum,
|
||||
cleanup::CustomScope(temp_scope),
|
||||
callee::DontAutorefArg,
|
||||
&mut ext_inputs);
|
||||
ext_constraints.push(i.to_string());
|
||||
}
|
||||
|
|
@ -80,7 +78,6 @@ pub fn trans_inline_asm<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ia: &ast::InlineAsm)
|
|||
expr_ty(bcx, &input),
|
||||
in_datum,
|
||||
cleanup::CustomScope(temp_scope),
|
||||
callee::DontAutorefArg,
|
||||
&mut inputs);
|
||||
}
|
||||
inputs.extend_from_slice(&ext_inputs[..]);
|
||||
|
|
|
|||
|
|
@ -195,16 +195,14 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
|
|||
fn get_extern_rust_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
fn_ty: Ty<'tcx>,
|
||||
name: &str,
|
||||
did: DefId)
|
||||
attrs: &[ast::Attribute])
|
||||
-> ValueRef {
|
||||
if let Some(n) = ccx.externs().borrow().get(name) {
|
||||
return *n;
|
||||
}
|
||||
|
||||
let f = declare::declare_rust_fn(ccx, name, fn_ty);
|
||||
|
||||
let attrs = ccx.sess().cstore.item_attrs(did);
|
||||
attributes::from_fn_attrs(ccx, &attrs[..], f);
|
||||
attributes::from_fn_attrs(ccx, &attrs, f);
|
||||
|
||||
ccx.externs().borrow_mut().insert(name.to_string(), f);
|
||||
f
|
||||
|
|
@ -621,8 +619,7 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>,
|
|||
pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
|
||||
source: Ty<'tcx>,
|
||||
target: Ty<'tcx>,
|
||||
old_info: Option<ValueRef>,
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
old_info: Option<ValueRef>)
|
||||
-> ValueRef {
|
||||
let (source, target) = ccx.tcx().struct_lockstep_tails(source, target);
|
||||
match (&source.sty, &target.sty) {
|
||||
|
|
@ -641,7 +638,7 @@ pub fn unsized_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
|
|||
def_id: principal.def_id(),
|
||||
substs: substs,
|
||||
});
|
||||
consts::ptrcast(meth::get_vtable(ccx, trait_ref, param_substs),
|
||||
consts::ptrcast(meth::get_vtable(ccx, trait_ref),
|
||||
Type::vtable_ptr(ccx))
|
||||
}
|
||||
_ => ccx.sess().bug(&format!("unsized_info: invalid unsizing {:?} -> {:?}",
|
||||
|
|
@ -668,7 +665,7 @@ pub fn unsize_thin_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
assert!(common::type_is_sized(bcx.tcx(), a));
|
||||
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), b).ptr_to();
|
||||
(PointerCast(bcx, src, ptr_ty),
|
||||
unsized_info(bcx.ccx(), a, b, None, bcx.fcx.param_substs))
|
||||
unsized_info(bcx.ccx(), a, b, None))
|
||||
}
|
||||
_ => bcx.sess().bug("unsize_thin_ptr: called on bad types"),
|
||||
}
|
||||
|
|
@ -900,29 +897,31 @@ pub fn fail_if_zero_or_overflows<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trans_external_path<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
did: DefId,
|
||||
t: Ty<'tcx>)
|
||||
-> ValueRef {
|
||||
let name = ccx.sess().cstore.item_symbol(did);
|
||||
match t.sty {
|
||||
ty::TyFnDef(_, _, ref fn_ty) => {
|
||||
match ccx.sess().target.target.adjust_abi(fn_ty.abi) {
|
||||
Abi::Rust | Abi::RustCall => {
|
||||
get_extern_rust_fn(ccx, t, &name[..], did)
|
||||
}
|
||||
pub fn get_extern_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> datum::Datum<'tcx, datum::Rvalue> {
|
||||
let name = ccx.sess().cstore.item_symbol(def_id);
|
||||
let attrs = ccx.sess().cstore.item_attrs(def_id);
|
||||
let ty = ccx.tcx().lookup_item_type(def_id).ty;
|
||||
match ty.sty {
|
||||
ty::TyFnDef(_, _, fty) => {
|
||||
let abi = fty.abi;
|
||||
let fty = infer::normalize_associated_type(ccx.tcx(), fty);
|
||||
let ty = ccx.tcx().mk_fn_ptr(fty);
|
||||
let llfn = match ccx.sess().target.target.adjust_abi(abi) {
|
||||
Abi::RustIntrinsic | Abi::PlatformIntrinsic => {
|
||||
ccx.sess().bug("unexpected intrinsic in trans_external_path")
|
||||
ccx.sess().bug("unexpected intrinsic in get_extern_fn")
|
||||
}
|
||||
Abi::Rust | Abi::RustCall => {
|
||||
get_extern_rust_fn(ccx, ty, &name, &attrs)
|
||||
}
|
||||
_ => {
|
||||
let attrs = ccx.sess().cstore.item_attrs(did);
|
||||
foreign::register_foreign_item_fn(ccx, fn_ty.abi, t, &name, &attrs)
|
||||
foreign::register_foreign_item_fn(ccx, abi, ty, &name, &attrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
get_extern_const(ccx, did, t)
|
||||
};
|
||||
datum::immediate_rvalue(llfn, ty)
|
||||
}
|
||||
_ => unreachable!("get_extern_fn: expected fn item type, found {}", ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2685,8 +2684,7 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
|
|||
.as_local_node_id(start_def_id) {
|
||||
get_item_val(ccx, start_node_id)
|
||||
} else {
|
||||
let start_fn_type = ccx.tcx().lookup_item_type(start_def_id).ty;
|
||||
trans_external_path(ccx, start_def_id, start_fn_type)
|
||||
get_extern_fn(ccx, start_def_id).val
|
||||
};
|
||||
let args = {
|
||||
let opaque_rust_main =
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -17,7 +17,7 @@ use trans::adt;
|
|||
use trans::attributes;
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
|
||||
use trans::callee::{self, ArgVals, Callee};
|
||||
use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
|
||||
use trans::common::*;
|
||||
use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue};
|
||||
|
|
@ -271,24 +271,8 @@ pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
|||
|
||||
// If the closure is a Fn closure, but a FnOnce is needed (etc),
|
||||
// then adapt the self type
|
||||
let closure_kind = ccx.tcx().closure_kind(closure_def_id);
|
||||
trans_closure_adapter_shim(ccx,
|
||||
closure_def_id,
|
||||
substs,
|
||||
closure_kind,
|
||||
trait_closure_kind,
|
||||
llfn)
|
||||
}
|
||||
let llfn_closure_kind = ccx.tcx().closure_kind(closure_def_id);
|
||||
|
||||
fn trans_closure_adapter_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
closure_def_id: DefId,
|
||||
substs: ty::ClosureSubsts<'tcx>,
|
||||
llfn_closure_kind: ty::ClosureKind,
|
||||
trait_closure_kind: ty::ClosureKind,
|
||||
llfn: ValueRef)
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("trans_closure_adapter_shim");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
|
|
@ -393,7 +377,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||
&block_arena);
|
||||
let mut bcx = init_function(&fcx, false, ret_ty);
|
||||
|
||||
let llargs = get_params(fcx.llfn);
|
||||
let mut llargs = get_params(fcx.llfn);
|
||||
|
||||
// the first argument (`self`) will be the (by value) closure env.
|
||||
let self_scope = fcx.push_custom_cleanup_scope();
|
||||
|
|
@ -408,21 +392,17 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
|||
|
||||
debug!("trans_fn_once_adapter_shim: env_datum={}",
|
||||
bcx.val_to_string(env_datum.val));
|
||||
llargs[self_idx] = env_datum.val;
|
||||
|
||||
let dest =
|
||||
fcx.llretslotptr.get().map(
|
||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, ret_ty, "ret_slot")));
|
||||
|
||||
let callee_data = TraitItem(MethodData { llfn: llreffn,
|
||||
llself: env_datum.val });
|
||||
|
||||
bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: callee_data,
|
||||
ty: llref_fn_ty
|
||||
}
|
||||
}, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
|
||||
let callee = Callee {
|
||||
data: callee::Fn(llreffn),
|
||||
ty: llref_fn_ty
|
||||
};
|
||||
bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
|
||||
|
||||
fcx.pop_and_trans_custom_cleanup_scope(bcx, self_scope);
|
||||
|
||||
|
|
|
|||
|
|
@ -542,14 +542,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
debug!("visiting operand {:?}", *operand);
|
||||
|
||||
let callee = match *operand {
|
||||
mir::Operand::Constant(mir::Constant {
|
||||
literal: mir::Literal::Item {
|
||||
def_id,
|
||||
kind,
|
||||
substs
|
||||
},
|
||||
..
|
||||
}) if is_function_or_method(kind) => Some((def_id, substs)),
|
||||
mir::Operand::Constant(mir::Constant { ty: &ty::TyS {
|
||||
sty: ty::TyFnDef(def_id, substs, _), ..
|
||||
}, .. }) => Some((def_id, substs)),
|
||||
_ => None
|
||||
};
|
||||
|
||||
|
|
@ -588,14 +583,6 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
|
|||
|
||||
self.super_operand(operand);
|
||||
|
||||
fn is_function_or_method(item_kind: mir::ItemKind) -> bool {
|
||||
match item_kind {
|
||||
mir::ItemKind::Constant => false,
|
||||
mir::ItemKind::Function |
|
||||
mir::ItemKind::Method => true
|
||||
}
|
||||
}
|
||||
|
||||
fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
def_id: DefId)
|
||||
-> bool {
|
||||
|
|
@ -690,7 +677,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
if can_have_local_instance(ccx, destructor_did) {
|
||||
let trans_item = create_fn_trans_item(ccx,
|
||||
destructor_did,
|
||||
ccx.tcx().mk_substs(substs),
|
||||
substs,
|
||||
&Substs::trans_empty());
|
||||
output.push(trans_item);
|
||||
}
|
||||
|
|
@ -833,9 +820,9 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
{
|
||||
let callee_substs = impl_substs.with_method_from(&rcvr_substs);
|
||||
let impl_method = tcx.get_impl_method(impl_did,
|
||||
callee_substs,
|
||||
tcx.mk_substs(callee_substs),
|
||||
trait_method.name);
|
||||
Some((impl_method.method.def_id, tcx.mk_substs(impl_method.substs)))
|
||||
Some((impl_method.method.def_id, impl_method.substs))
|
||||
}
|
||||
// If we have a closure or a function pointer, we will also encounter
|
||||
// the concrete closure/function somewhere else (during closure or fn
|
||||
|
|
@ -993,10 +980,9 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// create translation items
|
||||
.filter_map(|impl_method| {
|
||||
if can_have_local_instance(ccx, impl_method.method.def_id) {
|
||||
let substs = ccx.tcx().mk_substs(impl_method.substs);
|
||||
Some(create_fn_trans_item(ccx,
|
||||
impl_method.method.def_id,
|
||||
substs,
|
||||
impl_method.substs,
|
||||
&Substs::trans_empty()))
|
||||
} else {
|
||||
None
|
||||
|
|
@ -1175,12 +1161,12 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// The substitutions we have are on the impl, so we grab
|
||||
// the method type from the impl to substitute into.
|
||||
let mth = tcx.get_impl_method(impl_def_id,
|
||||
callee_substs.clone(),
|
||||
callee_substs,
|
||||
default_impl.name);
|
||||
|
||||
assert!(mth.is_provided);
|
||||
|
||||
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
|
||||
let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
|
||||
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1228,7 +1228,7 @@ pub enum ExprOrMethodCall {
|
|||
pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
node: ExprOrMethodCall,
|
||||
param_substs: &subst::Substs<'tcx>)
|
||||
-> subst::Substs<'tcx> {
|
||||
-> &'tcx subst::Substs<'tcx> {
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
let substs = match node {
|
||||
|
|
@ -1245,9 +1245,9 @@ pub fn node_id_substs<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
node, substs));
|
||||
}
|
||||
|
||||
monomorphize::apply_param_substs(tcx,
|
||||
param_substs,
|
||||
&substs.erase_regions())
|
||||
ccx.tcx().mk_substs(monomorphize::apply_param_substs(tcx,
|
||||
param_substs,
|
||||
&substs.erase_regions()))
|
||||
}
|
||||
|
||||
pub fn langcall(bcx: Block,
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ use middle::def::Def;
|
|||
use middle::def_id::DefId;
|
||||
use trans::{adt, closure, debuginfo, expr, inline, machine};
|
||||
use trans::base::{self, push_ctxt};
|
||||
use trans::callee::Callee;
|
||||
use trans::collector::{self, TransItem};
|
||||
use trans::common::{self, type_is_sized, ExprOrMethodCall, node_id_substs, C_nil, const_get_elt};
|
||||
use trans::common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty};
|
||||
|
|
@ -211,7 +212,7 @@ fn const_fn_call<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
let arg_ids = args.iter().map(|arg| arg.pat.id);
|
||||
let fn_args = arg_ids.zip(arg_vals.iter().cloned()).collect();
|
||||
|
||||
let substs = ccx.tcx().mk_substs(node_id_substs(ccx, node, param_substs));
|
||||
let substs = node_id_substs(ccx, node, param_substs);
|
||||
match fn_like.body().expr {
|
||||
Some(ref expr) => {
|
||||
const_expr(ccx, &expr, substs, Some(&fn_args), trueconst).map(|(res, _)| res)
|
||||
|
|
@ -355,8 +356,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let opt_adj = cx.tcx().tables.borrow().adjustments.get(&e.id).cloned();
|
||||
match opt_adj {
|
||||
Some(AdjustReifyFnPointer) => {
|
||||
// FIXME(#19925) once fn item types are
|
||||
// zero-sized, we'll need to do something here
|
||||
match ety.sty {
|
||||
ty::TyFnDef(def_id, substs, _) => {
|
||||
let datum = Callee::def(cx, def_id, substs, ety).reify(cx);
|
||||
llconst = datum.val;
|
||||
ety_adjusted = datum.ty;
|
||||
}
|
||||
_ => {
|
||||
unreachable!("{} cannot be reified to a fn ptr", ety)
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(AdjustUnsafeFnPointer) | Some(AdjustMutToConstPointer) => {
|
||||
// purely a type-level thing
|
||||
|
|
@ -413,8 +422,7 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
.expect("consts: unsizing got non-pointer target type").ty;
|
||||
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
|
||||
let base = ptrcast(base, ptr_ty);
|
||||
let info = base::unsized_info(cx, pointee_ty, unsized_ty,
|
||||
old_info, param_substs);
|
||||
let info = base::unsized_info(cx, pointee_ty, unsized_ty, old_info);
|
||||
|
||||
if old_info.is_none() {
|
||||
let prev_const = cx.const_unsized().borrow_mut()
|
||||
|
|
@ -894,9 +902,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
cx.sess().span_bug(e.span, "const fn argument not found")
|
||||
}
|
||||
}
|
||||
Def::Fn(..) | Def::Method(..) => {
|
||||
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
|
||||
}
|
||||
Def::Fn(..) | Def::Method(..) => C_nil(cx),
|
||||
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
|
||||
load_const(cx, try!(get_const_val(cx, def_id, e, param_substs)),
|
||||
ety)
|
||||
|
|
@ -908,23 +914,14 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||
let repr = adt::represent_type(cx, ety);
|
||||
adt::trans_const(cx, &repr, Disr::from(vinfo.disr_val), &[])
|
||||
}
|
||||
ty::VariantKind::Tuple => {
|
||||
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
|
||||
}
|
||||
ty::VariantKind::Tuple => C_nil(cx),
|
||||
ty::VariantKind::Struct => {
|
||||
cx.sess().span_bug(e.span, "path-expr refers to a dict variant!")
|
||||
}
|
||||
}
|
||||
}
|
||||
Def::Struct(..) => {
|
||||
if let ty::TyFnDef(..) = ety.sty {
|
||||
// Tuple struct.
|
||||
expr::trans_def_fn_unadjusted(cx, e, def, param_substs).val
|
||||
} else {
|
||||
// Unit struct.
|
||||
C_null(type_of::type_of(cx, ety))
|
||||
}
|
||||
}
|
||||
// Unit struct or ctor.
|
||||
Def::Struct(..) => C_null(type_of::type_of(cx, ety)),
|
||||
_ => {
|
||||
cx.sess().span_bug(e.span, "expected a const, fn, struct, \
|
||||
or variant def")
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ use llvm::{self, ValueRef, TypeKind};
|
|||
use middle::const_qualif::ConstQualif;
|
||||
use middle::def::Def;
|
||||
use middle::subst::Substs;
|
||||
use trans::{_match, adt, asm, base, callee, closure, consts, controlflow};
|
||||
use trans::{_match, adt, asm, base, closure, consts, controlflow};
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::callee::{Callee, ArgExprs, ArgOverloadedCall, ArgOverloadedOp};
|
||||
use trans::cleanup::{self, CleanupMethods, DropHintMethods};
|
||||
use trans::common::*;
|
||||
use trans::datum::*;
|
||||
|
|
@ -66,7 +67,6 @@ use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
|
|||
use trans::declare;
|
||||
use trans::glue;
|
||||
use trans::machine;
|
||||
use trans::meth;
|
||||
use trans::tvec;
|
||||
use trans::type_of;
|
||||
use trans::Disr;
|
||||
|
|
@ -85,7 +85,6 @@ use rustc_front::hir;
|
|||
|
||||
use syntax::{ast, codemap};
|
||||
use syntax::parse::token::InternedString;
|
||||
use syntax::ptr::P;
|
||||
use std::mem;
|
||||
|
||||
// Destinations
|
||||
|
|
@ -349,11 +348,7 @@ fn adjustment_required<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
|
||||
match adjustment {
|
||||
AdjustReifyFnPointer => {
|
||||
// FIXME(#19925) once fn item types are
|
||||
// zero-sized, we'll need to return true here
|
||||
false
|
||||
}
|
||||
AdjustReifyFnPointer => true,
|
||||
AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
|
||||
// purely a type-level thing
|
||||
false
|
||||
|
|
@ -388,8 +383,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
adjustment);
|
||||
match adjustment {
|
||||
AdjustReifyFnPointer => {
|
||||
// FIXME(#19925) once fn item types are
|
||||
// zero-sized, we'll need to do something here
|
||||
match datum.ty.sty {
|
||||
ty::TyFnDef(def_id, substs, _) => {
|
||||
datum = Callee::def(bcx.ccx(), def_id, substs, datum.ty)
|
||||
.reify(bcx.ccx()).to_expr_datum();
|
||||
}
|
||||
_ => {
|
||||
unreachable!("{} cannot be reified to a fn ptr", datum.ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
AdjustUnsafeFnPointer | AdjustMutToConstPointer => {
|
||||
// purely a type-level thing
|
||||
|
|
@ -492,8 +494,7 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
(val, None)
|
||||
};
|
||||
|
||||
let info = unsized_info(bcx.ccx(), inner_source, inner_target,
|
||||
old_info, bcx.fcx.param_substs);
|
||||
let info = unsized_info(bcx.ccx(), inner_source, inner_target, old_info);
|
||||
|
||||
// Compute the base pointer. This doesn't change the pointer value,
|
||||
// but merely its type.
|
||||
|
|
@ -785,15 +786,10 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let index_expr_debug_loc = index_expr.debug_loc();
|
||||
|
||||
// Check for overloaded index.
|
||||
let method_ty = ccx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call)
|
||||
.map(|method| method.ty);
|
||||
let elt_datum = match method_ty {
|
||||
Some(method_ty) => {
|
||||
let method_ty = monomorphize_type(bcx, method_ty);
|
||||
let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
|
||||
let elt_datum = match method {
|
||||
Some(method) => {
|
||||
let method_ty = monomorphize_type(bcx, method.ty);
|
||||
|
||||
let base_datum = unpack_datum!(bcx, trans(bcx, base));
|
||||
|
||||
|
|
@ -811,19 +807,16 @@ fn trans_index<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
Some(elt_tm) => elt_tm.ty,
|
||||
};
|
||||
|
||||
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
||||
// invoke the user's index() method, which basically yields
|
||||
// a `&T` pointer. We can then proceed down the normal
|
||||
// path (below) to dereference that `&T`.
|
||||
// Overloaded. Invoke the index() method, which basically
|
||||
// yields a `&T` pointer. We can then proceed down the
|
||||
// normal path (below) to dereference that `&T`.
|
||||
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_index_elt");
|
||||
unpack_result!(bcx,
|
||||
trans_overloaded_op(bcx,
|
||||
index_expr,
|
||||
method_call,
|
||||
base_datum,
|
||||
Some((ix_datum, idx.id)),
|
||||
Some(SaveIn(scratch.val)),
|
||||
false));
|
||||
|
||||
bcx = Callee::method(bcx, method)
|
||||
.call(bcx, index_expr_debug_loc,
|
||||
ArgOverloadedOp(base_datum, Some(ix_datum)),
|
||||
Some(SaveIn(scratch.val))).bcx;
|
||||
|
||||
let datum = scratch.to_expr_datum();
|
||||
let lval = Lvalue::new("expr::trans_index overload");
|
||||
if type_is_sized(bcx.tcx(), elt_ty) {
|
||||
|
|
@ -899,24 +892,18 @@ fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
let _icx = push_ctxt("trans_def_lvalue");
|
||||
match def {
|
||||
Def::Fn(..) | Def::Method(..) |
|
||||
Def::Struct(..) | Def::Variant(..) => {
|
||||
let datum = trans_def_fn_unadjusted(bcx.ccx(), ref_expr, def,
|
||||
bcx.fcx.param_substs);
|
||||
DatumBlock::new(bcx, datum.to_expr_datum())
|
||||
}
|
||||
Def::Static(did, _) => {
|
||||
let const_ty = expr_ty(bcx, ref_expr);
|
||||
let val = get_static_val(bcx.ccx(), did, const_ty);
|
||||
let lval = Lvalue::new("expr::trans_def");
|
||||
DatumBlock::new(bcx, Datum::new(val, const_ty, LvalueExpr(lval)))
|
||||
}
|
||||
Def::Const(_) | Def::AssociatedConst(_) => {
|
||||
bcx.sess().span_bug(ref_expr.span,
|
||||
"constant expression should not reach expr::trans_def")
|
||||
Def::Local(..) | Def::Upvar(..) => {
|
||||
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
|
||||
}
|
||||
_ => {
|
||||
DatumBlock::new(bcx, trans_local_var(bcx, def).to_expr_datum())
|
||||
bcx.sess().span_bug(ref_expr.span,
|
||||
&format!("{:?} should not reach expr::trans_def", def))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1024,17 +1011,18 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
hir::ExprAssignOp(op, ref dst, ref src) => {
|
||||
let has_method_map = bcx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.contains_key(&MethodCall::expr(expr.id));
|
||||
let method = bcx.tcx().tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&MethodCall::expr(expr.id)).cloned();
|
||||
|
||||
if has_method_map {
|
||||
if let Some(method) = method {
|
||||
let dst = unpack_datum!(bcx, trans(bcx, &dst));
|
||||
let src_datum = unpack_datum!(bcx, trans(bcx, &src));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), dst,
|
||||
Some((src_datum, src.id)), None, false).bcx
|
||||
|
||||
Callee::method(bcx, method)
|
||||
.call(bcx, expr.debug_loc(),
|
||||
ArgOverloadedOp(dst, Some(src_datum)), None).bcx
|
||||
} else {
|
||||
trans_assign_op(bcx, expr, op, &dst, &src)
|
||||
}
|
||||
|
|
@ -1061,6 +1049,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
|
||||
debuginfo::set_source_location(bcx.fcx, expr.id, expr.span);
|
||||
|
||||
// Entry into the method table if this is an overloaded call/op.
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
|
||||
match expr.node {
|
||||
hir::ExprType(ref e, _) => {
|
||||
trans_into(bcx, &e, dest)
|
||||
|
|
@ -1144,47 +1135,54 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
&expr.attrs).unwrap_or(bcx)
|
||||
}
|
||||
hir::ExprCall(ref f, ref args) => {
|
||||
if bcx.tcx().is_method_call(expr.id) {
|
||||
trans_overloaded_call(bcx,
|
||||
expr,
|
||||
&f,
|
||||
&args[..],
|
||||
Some(dest))
|
||||
let method = bcx.tcx().tables.borrow().method_map.get(&method_call).cloned();
|
||||
let (callee, args) = if let Some(method) = method {
|
||||
let mut all_args = vec![&**f];
|
||||
all_args.extend(args.iter().map(|e| &**e));
|
||||
|
||||
(Callee::method(bcx, method), ArgOverloadedCall(all_args))
|
||||
} else {
|
||||
callee::trans_call(bcx,
|
||||
expr,
|
||||
&f,
|
||||
callee::ArgExprs(&args[..]),
|
||||
dest)
|
||||
}
|
||||
let f = unpack_datum!(bcx, trans(bcx, f));
|
||||
(match f.ty.sty {
|
||||
ty::TyFnDef(def_id, substs, _) => {
|
||||
Callee::def(bcx.ccx(), def_id, substs, f.ty)
|
||||
}
|
||||
ty::TyFnPtr(_) => {
|
||||
let f = unpack_datum!(bcx,
|
||||
f.to_rvalue_datum(bcx, "callee"));
|
||||
Callee::ptr(f)
|
||||
}
|
||||
_ => {
|
||||
bcx.tcx().sess.span_bug(expr.span,
|
||||
&format!("type of callee is not a fn: {}", f.ty));
|
||||
}
|
||||
}, ArgExprs(&args))
|
||||
};
|
||||
callee.call(bcx, expr.debug_loc(), args, Some(dest)).bcx
|
||||
}
|
||||
hir::ExprMethodCall(_, _, ref args) => {
|
||||
callee::trans_method_call(bcx,
|
||||
expr,
|
||||
&args[0],
|
||||
callee::ArgExprs(&args[..]),
|
||||
dest)
|
||||
Callee::method_call(bcx, method_call)
|
||||
.call(bcx, expr.debug_loc(), ArgExprs(&args), Some(dest)).bcx
|
||||
}
|
||||
hir::ExprBinary(op, ref lhs, ref rhs) => {
|
||||
hir::ExprBinary(op, ref lhs, ref rhs_expr) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
let lhs = unpack_datum!(bcx, trans(bcx, &lhs));
|
||||
let rhs_datum = unpack_datum!(bcx, trans(bcx, &rhs));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), lhs,
|
||||
Some((rhs_datum, rhs.id)), Some(dest),
|
||||
!rustc_front::util::is_by_value_binop(op.node)).bcx
|
||||
let mut rhs = unpack_datum!(bcx, trans(bcx, &rhs_expr));
|
||||
if !rustc_front::util::is_by_value_binop(op.node) {
|
||||
rhs = unpack_datum!(bcx, auto_ref(bcx, rhs, rhs_expr));
|
||||
}
|
||||
|
||||
Callee::method_call(bcx, method_call)
|
||||
.call(bcx, expr.debug_loc(),
|
||||
ArgOverloadedOp(lhs, Some(rhs)), Some(dest)).bcx
|
||||
}
|
||||
hir::ExprUnary(op, ref subexpr) => {
|
||||
hir::ExprUnary(_, ref subexpr) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
let arg = unpack_datum!(bcx, trans(bcx, &subexpr));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id),
|
||||
arg, None, Some(dest), !rustc_front::util::is_by_value_unop(op)).bcx
|
||||
}
|
||||
hir::ExprIndex(ref base, ref idx) => {
|
||||
// if not overloaded, would be RvalueDatumExpr
|
||||
let base = unpack_datum!(bcx, trans(bcx, &base));
|
||||
let idx_datum = unpack_datum!(bcx, trans(bcx, &idx));
|
||||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
|
||||
Some((idx_datum, idx.id)), Some(dest), true).bcx
|
||||
|
||||
Callee::method_call(bcx, method_call)
|
||||
.call(bcx, expr.debug_loc(),
|
||||
ArgOverloadedOp(arg, None), Some(dest)).bcx
|
||||
}
|
||||
hir::ExprCast(..) => {
|
||||
// Trait casts used to come this way, now they should be coercions.
|
||||
|
|
@ -1218,26 +1216,22 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
Ignore => { return bcx; }
|
||||
};
|
||||
|
||||
let ty = expr_ty(bcx, ref_expr);
|
||||
if let ty::TyFnDef(..) = ty.sty {
|
||||
// Zero-sized function or ctor.
|
||||
return bcx;
|
||||
}
|
||||
|
||||
match def {
|
||||
Def::Variant(tid, vid) => {
|
||||
let variant = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
|
||||
if let ty::VariantKind::Tuple = variant.kind() {
|
||||
// N-ary variant.
|
||||
let llfn = callee::trans_fn_ref(bcx.ccx(), vid,
|
||||
ExprId(ref_expr.id),
|
||||
bcx.fcx.param_substs).val;
|
||||
Store(bcx, llfn, lldest);
|
||||
return bcx;
|
||||
} else {
|
||||
// Nullary variant.
|
||||
let ty = expr_ty(bcx, ref_expr);
|
||||
let repr = adt::represent_type(bcx.ccx(), ty);
|
||||
adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
|
||||
return bcx;
|
||||
}
|
||||
// Nullary variant.
|
||||
let ty = expr_ty(bcx, ref_expr);
|
||||
let repr = adt::represent_type(bcx.ccx(), ty);
|
||||
adt::trans_set_discr(bcx, &repr, lldest, Disr::from(variant.disr_val));
|
||||
bcx
|
||||
}
|
||||
Def::Struct(..) => {
|
||||
let ty = expr_ty(bcx, ref_expr);
|
||||
match ty.sty {
|
||||
ty::TyStruct(def, _) if def.has_dtor() => {
|
||||
let repr = adt::represent_type(bcx.ccx(), ty);
|
||||
|
|
@ -1255,41 +1249,6 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trans_def_fn_unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
ref_expr: &hir::Expr,
|
||||
def: Def,
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue> {
|
||||
let _icx = push_ctxt("trans_def_datum_unadjusted");
|
||||
|
||||
match def {
|
||||
Def::Fn(did) |
|
||||
Def::Struct(did) | Def::Variant(_, did) => {
|
||||
callee::trans_fn_ref(ccx, did, ExprId(ref_expr.id), param_substs)
|
||||
}
|
||||
Def::Method(method_did) => {
|
||||
match ccx.tcx().impl_or_trait_item(method_did).container() {
|
||||
ty::ImplContainer(_) => {
|
||||
callee::trans_fn_ref(ccx, method_did,
|
||||
ExprId(ref_expr.id),
|
||||
param_substs)
|
||||
}
|
||||
ty::TraitContainer(trait_did) => {
|
||||
meth::trans_static_method_callee(ccx, method_did,
|
||||
trait_did, ref_expr.id,
|
||||
param_substs)
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
ccx.tcx().sess.span_bug(ref_expr.span, &format!(
|
||||
"trans_def_fn_unadjusted invoked on: {:?} for {:?}",
|
||||
def,
|
||||
ref_expr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates a reference to a local variable or argument. This always results in an lvalue datum.
|
||||
pub fn trans_local_var<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
def: Def)
|
||||
|
|
@ -1898,51 +1857,6 @@ fn trans_binary<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn trans_overloaded_op<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
method_call: MethodCall,
|
||||
lhs: Datum<'tcx, Expr>,
|
||||
rhs: Option<(Datum<'tcx, Expr>, ast::NodeId)>,
|
||||
dest: Option<Dest>,
|
||||
autoref: bool)
|
||||
-> Result<'blk, 'tcx> {
|
||||
callee::trans_call_inner(bcx,
|
||||
expr.debug_loc(),
|
||||
|bcx, arg_cleanup_scope| {
|
||||
meth::trans_method_callee(bcx,
|
||||
method_call,
|
||||
None,
|
||||
arg_cleanup_scope)
|
||||
},
|
||||
callee::ArgOverloadedOp(lhs, rhs, autoref),
|
||||
dest)
|
||||
}
|
||||
|
||||
fn trans_overloaded_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
expr: &hir::Expr,
|
||||
callee: &'a hir::Expr,
|
||||
args: &'a [P<hir::Expr>],
|
||||
dest: Option<Dest>)
|
||||
-> Block<'blk, 'tcx> {
|
||||
debug!("trans_overloaded_call {}", expr.id);
|
||||
let method_call = MethodCall::expr(expr.id);
|
||||
let mut all_args = vec!(callee);
|
||||
all_args.extend(args.iter().map(|e| &**e));
|
||||
unpack_result!(bcx,
|
||||
callee::trans_call_inner(bcx,
|
||||
expr.debug_loc(),
|
||||
|bcx, arg_cleanup_scope| {
|
||||
meth::trans_method_callee(
|
||||
bcx,
|
||||
method_call,
|
||||
None,
|
||||
arg_cleanup_scope)
|
||||
},
|
||||
callee::ArgOverloadedCall(all_args),
|
||||
dest));
|
||||
bcx
|
||||
}
|
||||
|
||||
pub fn cast_is_noop<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||
expr: &hir::Expr,
|
||||
t_in: Ty<'tcx>,
|
||||
|
|
@ -2179,18 +2093,12 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let mut bcx = bcx;
|
||||
|
||||
// Check for overloaded deref.
|
||||
let method_ty = ccx.tcx()
|
||||
.tables
|
||||
.borrow()
|
||||
.method_map
|
||||
.get(&method_call).map(|method| method.ty);
|
||||
let method = ccx.tcx().tables.borrow().method_map.get(&method_call).cloned();
|
||||
let datum = match method {
|
||||
Some(method) => {
|
||||
let method_ty = monomorphize_type(bcx, method.ty);
|
||||
|
||||
let datum = match method_ty {
|
||||
Some(method_ty) => {
|
||||
let method_ty = monomorphize_type(bcx, method_ty);
|
||||
|
||||
// Overloaded. Evaluate `trans_overloaded_op`, which will
|
||||
// invoke the user's deref() method, which basically
|
||||
// Overloaded. Invoke the deref() method, which basically
|
||||
// converts from the `Smaht<T>` pointer that we have into
|
||||
// a `&T` pointer. We can then proceed down the normal
|
||||
// path (below) to dereference that `&T`.
|
||||
|
|
@ -2205,9 +2113,10 @@ fn deref_once<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
ccx.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
|
||||
let scratch = rvalue_scratch_datum(bcx, ref_ty, "overloaded_deref");
|
||||
|
||||
unpack_result!(bcx, trans_overloaded_op(bcx, expr, method_call,
|
||||
datum, None, Some(SaveIn(scratch.val)),
|
||||
false));
|
||||
bcx = Callee::method(bcx, method)
|
||||
.call(bcx, expr.debug_loc(),
|
||||
ArgOverloadedOp(datum, None),
|
||||
Some(SaveIn(scratch.val))).bcx;
|
||||
scratch.to_expr_datum()
|
||||
}
|
||||
None => {
|
||||
|
|
@ -2524,18 +2433,13 @@ fn expr_kind(tcx: &TyCtxt, expr: &hir::Expr) -> ExprKind {
|
|||
match expr.node {
|
||||
hir::ExprPath(..) => {
|
||||
match tcx.resolve_expr(expr) {
|
||||
Def::Struct(..) | Def::Variant(..) => {
|
||||
if let ty::TyFnDef(..) = tcx.node_id_to_type(expr.id).sty {
|
||||
// ctor function
|
||||
ExprKind::RvalueDatum
|
||||
} else {
|
||||
ExprKind::RvalueDps
|
||||
}
|
||||
// Put functions and ctors with the ADTs, as they
|
||||
// are zero-sized, so DPS is the cheapest option.
|
||||
Def::Struct(..) | Def::Variant(..) |
|
||||
Def::Fn(..) | Def::Method(..) => {
|
||||
ExprKind::RvalueDps
|
||||
}
|
||||
|
||||
// Fn pointers are just scalar values.
|
||||
Def::Fn(..) | Def::Method(..) => ExprKind::RvalueDatum,
|
||||
|
||||
// Note: there is actually a good case to be made that
|
||||
// DefArg's, particularly those of immediate type, ought to
|
||||
// considered rvalues.
|
||||
|
|
|
|||
|
|
@ -356,27 +356,18 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
&unsized_args
|
||||
};
|
||||
|
||||
bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
|
||||
let trait_ref = ty::Binder(ty::TraitRef {
|
||||
def_id: tcx.lang_items.drop_trait().unwrap(),
|
||||
substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
|
||||
});
|
||||
let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
|
||||
traits::VtableImpl(data) => data,
|
||||
_ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
|
||||
};
|
||||
let dtor_did = def.destructor().unwrap();
|
||||
let datum = callee::trans_fn_ref_with_substs(bcx.ccx(),
|
||||
dtor_did,
|
||||
ExprId(0),
|
||||
bcx.fcx.param_substs,
|
||||
vtbl.substs);
|
||||
callee::Callee {
|
||||
bcx: bcx,
|
||||
data: callee::Fn(datum.val),
|
||||
ty: datum.ty
|
||||
}
|
||||
}, callee::ArgVals(args), Some(expr::Ignore)).bcx;
|
||||
let trait_ref = ty::Binder(ty::TraitRef {
|
||||
def_id: tcx.lang_items.drop_trait().unwrap(),
|
||||
substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
|
||||
});
|
||||
let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
|
||||
traits::VtableImpl(data) => data,
|
||||
_ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
|
||||
};
|
||||
let dtor_did = def.destructor().unwrap();
|
||||
bcx = callee::Callee::ptr(callee::trans_fn_ref_with_substs(
|
||||
bcx.ccx(), dtor_did, None, vtbl.substs))
|
||||
.call(bcx, DebugLoc::None, callee::ArgVals(args), Some(expr::Ignore)).bcx;
|
||||
|
||||
bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
cleanup_scope: cleanup::CustomScopeIndex,
|
||||
args: callee::CallArgs<'a, 'tcx>,
|
||||
dest: expr::Dest,
|
||||
substs: subst::Substs<'tcx>,
|
||||
substs: &'tcx subst::Substs<'tcx>,
|
||||
call_info: NodeIdAndSpan)
|
||||
-> Result<'blk, 'tcx> {
|
||||
let fcx = bcx.fcx;
|
||||
|
|
@ -364,7 +364,6 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
|||
callee_ty,
|
||||
&mut llargs,
|
||||
cleanup::CustomScope(cleanup_scope),
|
||||
false,
|
||||
Abi::RustIntrinsic);
|
||||
|
||||
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
|
||||
|
|
@ -1397,7 +1396,7 @@ fn span_invalid_monomorphization_error(a: &Session, b: Span, c: &str) {
|
|||
fn generic_simd_intrinsic<'blk, 'tcx, 'a>
|
||||
(bcx: Block<'blk, 'tcx>,
|
||||
name: &str,
|
||||
substs: subst::Substs<'tcx>,
|
||||
substs: &'tcx subst::Substs<'tcx>,
|
||||
callee_ty: Ty<'tcx>,
|
||||
args: Option<&[P<hir::Expr>]>,
|
||||
llargs: &[ValueRef],
|
||||
|
|
@ -1505,11 +1504,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
|
|||
None => bcx.sess().span_bug(call_info.span,
|
||||
"intrinsic call with unexpected argument shape"),
|
||||
};
|
||||
let vector = match consts::const_expr(
|
||||
bcx.ccx(),
|
||||
vector,
|
||||
tcx.mk_substs(substs),
|
||||
None,
|
||||
let vector = match consts::const_expr(bcx.ccx(), vector, substs, None,
|
||||
consts::TrueConst::Yes, // this should probably help simd error reporting
|
||||
) {
|
||||
Ok((vector, _)) => vector,
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ use middle::subst;
|
|||
use middle::traits;
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::callee::*;
|
||||
use trans::callee;
|
||||
use trans::cleanup;
|
||||
use trans::callee::{Callee, Virtual, ArgVals,
|
||||
trans_fn_pointer_shim, trans_fn_ref_with_substs};
|
||||
use trans::closure;
|
||||
use trans::common::*;
|
||||
use trans::consts;
|
||||
|
|
@ -30,11 +29,9 @@ use trans::declare;
|
|||
use trans::expr;
|
||||
use trans::glue;
|
||||
use trans::machine;
|
||||
use trans::monomorphize;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of::*;
|
||||
use middle::ty::{self, Ty, TyCtxt};
|
||||
use middle::ty::MethodCall;
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::attr;
|
||||
|
|
@ -92,263 +89,99 @@ pub fn trans_impl(ccx: &CrateContext,
|
|||
}
|
||||
}
|
||||
|
||||
pub fn trans_method_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
method_call: MethodCall,
|
||||
self_expr: Option<&hir::Expr>,
|
||||
arg_cleanup_scope: cleanup::ScopeId)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_method_callee");
|
||||
|
||||
let method = bcx.tcx().tables.borrow().method_map[&method_call];
|
||||
|
||||
match bcx.tcx().impl_or_trait_item(method.def_id).container() {
|
||||
ty::ImplContainer(_) => {
|
||||
debug!("trans_method_callee: static, {:?}", method.def_id);
|
||||
let datum = callee::trans_fn_ref(bcx.ccx(),
|
||||
method.def_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(datum.val),
|
||||
ty: datum.ty
|
||||
}
|
||||
}
|
||||
|
||||
ty::TraitContainer(trait_def_id) => {
|
||||
let trait_ref = method.substs.to_trait_ref(bcx.tcx(), trait_def_id);
|
||||
let trait_ref = ty::Binder(bcx.monomorphize(&trait_ref));
|
||||
let span = bcx.tcx().map.span(method_call.expr_id);
|
||||
debug!("method_call={:?} trait_ref={:?} trait_ref id={:?} substs={:?}",
|
||||
method_call,
|
||||
trait_ref,
|
||||
trait_ref.0.def_id,
|
||||
trait_ref.0.substs);
|
||||
let origin = fulfill_obligation(bcx.ccx(), span, trait_ref);
|
||||
debug!("origin = {:?}", origin);
|
||||
trans_monomorphized_callee(bcx,
|
||||
method_call,
|
||||
self_expr,
|
||||
trait_def_id,
|
||||
method.def_id,
|
||||
method.ty,
|
||||
origin,
|
||||
arg_cleanup_scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_static_method_callee<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
method_id: DefId,
|
||||
trait_id: DefId,
|
||||
expr_id: ast::NodeId,
|
||||
param_substs: &'tcx subst::Substs<'tcx>)
|
||||
-> Datum<'tcx, Rvalue>
|
||||
{
|
||||
let _icx = push_ctxt("meth::trans_static_method_callee");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
debug!("trans_static_method_callee(method_id={:?}, trait_id={}, \
|
||||
expr_id={})",
|
||||
method_id,
|
||||
tcx.item_path_str(trait_id),
|
||||
expr_id);
|
||||
|
||||
let mname = tcx.item_name(method_id);
|
||||
|
||||
debug!("trans_static_method_callee: method_id={:?}, expr_id={}, \
|
||||
name={}", method_id, expr_id, mname);
|
||||
|
||||
// Find the substitutions for the fn itself. This includes
|
||||
// type parameters that belong to the trait but also some that
|
||||
// belong to the method:
|
||||
let rcvr_substs = node_id_substs(ccx, ExprId(expr_id), param_substs);
|
||||
debug!("rcvr_substs={:?}", rcvr_substs);
|
||||
let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
|
||||
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
|
||||
|
||||
// Now that we know which impl is being used, we can dispatch to
|
||||
// the actual function:
|
||||
match vtbl {
|
||||
traits::VtableImpl(traits::VtableImplData {
|
||||
impl_def_id: impl_did,
|
||||
substs: impl_substs,
|
||||
nested: _ }) =>
|
||||
{
|
||||
let callee_substs = impl_substs.with_method_from(&rcvr_substs);
|
||||
let mth = tcx.get_impl_method(impl_did, callee_substs, mname);
|
||||
trans_fn_ref_with_substs(ccx, mth.method.def_id, ExprId(expr_id),
|
||||
param_substs,
|
||||
mth.substs)
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
|
||||
trans_object_shim(ccx,
|
||||
data.upcast_trait_ref.clone(),
|
||||
method_id,
|
||||
idx)
|
||||
}
|
||||
_ => {
|
||||
// FIXME(#20847): handle at least VtableFnPointer
|
||||
tcx.sess.bug(&format!("static call to invalid vtable: {:?}",
|
||||
vtbl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
method_call: MethodCall,
|
||||
self_expr: Option<&hir::Expr>,
|
||||
trait_id: DefId,
|
||||
method_id: DefId,
|
||||
method_ty: Ty<'tcx>,
|
||||
vtable: traits::Vtable<'tcx, ()>,
|
||||
arg_cleanup_scope: cleanup::ScopeId)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_monomorphized_callee");
|
||||
/// Compute the appropriate callee, give na method's ID, trait ID,
|
||||
/// substitutions and a Vtable for that trait.
|
||||
pub fn callee_for_trait_impl<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
method_id: DefId,
|
||||
substs: &'tcx subst::Substs<'tcx>,
|
||||
trait_id: DefId,
|
||||
method_ty: Ty<'tcx>,
|
||||
vtable: traits::Vtable<'tcx, ()>)
|
||||
-> Callee<'tcx> {
|
||||
let _icx = push_ctxt("meth::callee_for_trait_impl");
|
||||
match vtable {
|
||||
traits::VtableImpl(vtable_impl) => {
|
||||
let ccx = bcx.ccx();
|
||||
let impl_did = vtable_impl.impl_def_id;
|
||||
let mname = match ccx.tcx().impl_or_trait_item(method_id) {
|
||||
ty::MethodTraitItem(method) => method.name,
|
||||
_ => {
|
||||
bcx.tcx().sess.bug("can't monomorphize a non-method trait \
|
||||
item")
|
||||
}
|
||||
};
|
||||
let mname = ccx.tcx().item_name(method_id);
|
||||
// create a concatenated set of substitutions which includes
|
||||
// those from the impl and those from the method:
|
||||
let meth_substs = node_id_substs(ccx,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs);
|
||||
let impl_substs = vtable_impl.substs.with_method_from(&meth_substs);
|
||||
let mth = bcx.tcx().get_impl_method(impl_did, impl_substs, mname);
|
||||
// translate the function
|
||||
let datum = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
mth.method.def_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs,
|
||||
mth.substs);
|
||||
let impl_substs = vtable_impl.substs.with_method_from(&substs);
|
||||
let substs = ccx.tcx().mk_substs(impl_substs);
|
||||
let mth = ccx.tcx().get_impl_method(impl_did, substs, mname);
|
||||
|
||||
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
|
||||
// Translate the function, bypassing Callee::def.
|
||||
// That is because default methods have the same ID as the
|
||||
// trait method used to look up the impl method that ended
|
||||
// up here, so calling Callee::def would infinitely recurse.
|
||||
Callee::ptr(trans_fn_ref_with_substs(ccx, mth.method.def_id,
|
||||
Some(method_ty), mth.substs))
|
||||
}
|
||||
traits::VtableClosure(vtable_closure) => {
|
||||
// The substitutions should have no type parameters remaining
|
||||
// after passing through fulfill_obligation
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = closure::trans_closure_method(bcx.ccx(),
|
||||
let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = closure::trans_closure_method(ccx,
|
||||
vtable_closure.closure_def_id,
|
||||
vtable_closure.substs,
|
||||
trait_closure_kind);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
ty: monomorphize_type(bcx, method_ty)
|
||||
}
|
||||
let fn_ptr_ty = match method_ty.sty {
|
||||
ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
|
||||
_ => unreachable!("expected fn item type, found {}",
|
||||
method_ty)
|
||||
};
|
||||
Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
|
||||
}
|
||||
traits::VtableFnPointer(fn_ty) => {
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
ty: monomorphize_type(bcx, method_ty)
|
||||
}
|
||||
let trait_closure_kind = ccx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = trans_fn_pointer_shim(ccx, trait_closure_kind, fn_ty);
|
||||
let fn_ptr_ty = match method_ty.sty {
|
||||
ty::TyFnDef(_, _, fty) => ccx.tcx().mk_ty(ty::TyFnPtr(fty)),
|
||||
_ => unreachable!("expected fn item type, found {}",
|
||||
method_ty)
|
||||
};
|
||||
Callee::ptr(immediate_rvalue(llfn, fn_ptr_ty))
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
let idx = traits::get_vtable_index_of_object_method(bcx.tcx(), data, method_id);
|
||||
if let Some(self_expr) = self_expr {
|
||||
if let ty::TyFnDef(_, _, ref fty) = monomorphize_type(bcx, method_ty).sty {
|
||||
let ty = opaque_method_ty(bcx.tcx(), fty);
|
||||
return trans_trait_callee(bcx, ty, idx, self_expr, arg_cleanup_scope);
|
||||
}
|
||||
Callee {
|
||||
data: Virtual(traits::get_vtable_index_of_object_method(
|
||||
ccx.tcx(), data, method_id)),
|
||||
ty: method_ty
|
||||
}
|
||||
let datum = trans_object_shim(bcx.ccx(),
|
||||
data.upcast_trait_ref.clone(),
|
||||
method_id,
|
||||
idx);
|
||||
Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
|
||||
}
|
||||
traits::VtableBuiltin(..) |
|
||||
traits::VtableDefaultImpl(..) |
|
||||
traits::VtableParam(..) => {
|
||||
bcx.sess().bug(
|
||||
ccx.sess().bug(
|
||||
&format!("resolved vtable bad vtable {:?} in trans",
|
||||
vtable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a method callee where the method is coming from a trait object (e.g., Box<Trait> type).
|
||||
/// In this case, we must pull the fn pointer out of the vtable that is packaged up with the
|
||||
/// object. Objects are represented as a pair, so we first evaluate the self expression and then
|
||||
/// extract the self data and vtable out of the pair.
|
||||
fn trans_trait_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
opaque_fn_ty: Ty<'tcx>,
|
||||
vtable_index: usize,
|
||||
self_expr: &hir::Expr,
|
||||
arg_cleanup_scope: cleanup::ScopeId)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_trait_callee");
|
||||
let mut bcx = bcx;
|
||||
|
||||
// Translate self_datum and take ownership of the value by
|
||||
// converting to an rvalue.
|
||||
let self_datum = unpack_datum!(
|
||||
bcx, expr::trans(bcx, self_expr));
|
||||
|
||||
let llval = if bcx.fcx.type_needs_drop(self_datum.ty) {
|
||||
let self_datum = unpack_datum!(
|
||||
bcx, self_datum.to_rvalue_datum(bcx, "trait_callee"));
|
||||
|
||||
// Convert to by-ref since `trans_trait_callee_from_llval` wants it
|
||||
// that way.
|
||||
let self_datum = unpack_datum!(
|
||||
bcx, self_datum.to_ref_datum(bcx));
|
||||
|
||||
// Arrange cleanup in case something should go wrong before the
|
||||
// actual call occurs.
|
||||
self_datum.add_clean(bcx.fcx, arg_cleanup_scope)
|
||||
} else {
|
||||
// We don't have to do anything about cleanups for &Trait and &mut Trait.
|
||||
assert!(self_datum.kind.is_by_ref());
|
||||
self_datum.val
|
||||
};
|
||||
|
||||
let llself = Load(bcx, expr::get_dataptr(bcx, llval));
|
||||
let llvtable = Load(bcx, expr::get_meta(bcx, llval));
|
||||
trans_trait_callee_from_llval(bcx, opaque_fn_ty, vtable_index, llself, llvtable)
|
||||
}
|
||||
|
||||
/// Same as `trans_trait_callee()` above, except that it is given a by-ref pointer to the object
|
||||
/// pair.
|
||||
fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
opaque_fn_ty: Ty<'tcx>,
|
||||
vtable_index: usize,
|
||||
llself: ValueRef,
|
||||
llvtable: ValueRef)
|
||||
-> Callee<'blk, 'tcx> {
|
||||
let _icx = push_ctxt("meth::trans_trait_callee");
|
||||
/// Extracts a method from a trait object's vtable, at the
|
||||
/// specified index, and casts it to the given type.
|
||||
pub fn get_virtual_method<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
llvtable: ValueRef,
|
||||
vtable_index: usize,
|
||||
method_ty: Ty<'tcx>)
|
||||
-> Datum<'tcx, Rvalue> {
|
||||
let _icx = push_ctxt("meth::get_virtual_method");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Load the data pointer from the object.
|
||||
debug!("trans_trait_callee_from_llval(callee_ty={}, vtable_index={}, llself={}, llvtable={})",
|
||||
opaque_fn_ty,
|
||||
debug!("get_virtual_method(callee_ty={}, vtable_index={}, llvtable={})",
|
||||
method_ty,
|
||||
vtable_index,
|
||||
bcx.val_to_string(llself),
|
||||
bcx.val_to_string(llvtable));
|
||||
|
||||
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
let mptr = Load(bcx, GEPi(bcx, llvtable, &[vtable_index + VTABLE_OFFSET]));
|
||||
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: TraitItem(MethodData {
|
||||
llfn: PointerCast(bcx, mptr, type_of(ccx, opaque_fn_ty)),
|
||||
llself: PointerCast(bcx, llself, Type::i8p(ccx)),
|
||||
}),
|
||||
ty: opaque_fn_ty
|
||||
// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
if let ty::TyFnDef(_, _, fty) = method_ty.sty {
|
||||
let opaque_ty = opaque_method_ty(ccx.tcx(), fty);
|
||||
immediate_rvalue(PointerCast(bcx, mptr, type_of(ccx, opaque_ty)), opaque_ty)
|
||||
} else {
|
||||
immediate_rvalue(mptr, method_ty)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,41 +206,24 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
///
|
||||
/// In fact, all virtual calls can be thought of as normal trait calls
|
||||
/// that go through this shim function.
|
||||
pub fn trans_object_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
method_id: DefId,
|
||||
vtable_index: usize)
|
||||
-> Datum<'tcx, Rvalue>
|
||||
{
|
||||
pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
method_ty: Ty<'tcx>,
|
||||
vtable_index: usize)
|
||||
-> Datum<'tcx, Rvalue> {
|
||||
let _icx = push_ctxt("trans_object_shim");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
debug!("trans_object_shim(upcast_trait_ref={:?}, method_id={:?})",
|
||||
upcast_trait_ref,
|
||||
method_id);
|
||||
debug!("trans_object_shim(vtable_index={}, method_ty={:?})",
|
||||
vtable_index,
|
||||
method_ty);
|
||||
|
||||
// Upcast to the trait in question and extract out the substitutions.
|
||||
let upcast_trait_ref = tcx.erase_late_bound_regions(&upcast_trait_ref);
|
||||
let object_substs = upcast_trait_ref.substs.clone().erase_regions();
|
||||
debug!("trans_object_shim: object_substs={:?}", object_substs);
|
||||
let ret_ty = tcx.erase_late_bound_regions(&method_ty.fn_ret());
|
||||
let ret_ty = infer::normalize_associated_type(tcx, &ret_ty);
|
||||
|
||||
// Lookup the type of this method as declared in the trait and apply substitutions.
|
||||
let method_ty = match tcx.impl_or_trait_item(method_id) {
|
||||
ty::MethodTraitItem(method) => method,
|
||||
_ => {
|
||||
tcx.sess.bug("can't create a method shim for a non-method item")
|
||||
}
|
||||
let shim_fn_ty = match method_ty.sty {
|
||||
ty::TyFnDef(_, _, fty) => tcx.mk_ty(ty::TyFnPtr(fty)),
|
||||
_ => unreachable!("expected fn item type, found {}", method_ty)
|
||||
};
|
||||
let fty = monomorphize::apply_param_substs(tcx, &object_substs, &method_ty.fty);
|
||||
|
||||
let ret_ty = ccx.tcx().erase_late_bound_regions(&fty.sig.output());
|
||||
let ret_ty = infer::normalize_associated_type(ccx.tcx(), &ret_ty);
|
||||
|
||||
let method_fn_ty = opaque_method_ty(tcx, &fty);
|
||||
let shim_fn_ty = tcx.mk_fn_ptr(fty);
|
||||
debug!("trans_object_shim: shim_fn_ty={:?} method_fn_ty={:?}",
|
||||
shim_fn_ty, method_fn_ty);
|
||||
|
||||
//
|
||||
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, shim_fn_ty, "object_shim");
|
||||
|
|
@ -444,14 +260,11 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
debug!("trans_object_shim: method_offset_in_vtable={}",
|
||||
vtable_index);
|
||||
|
||||
bcx = trans_call_inner(bcx,
|
||||
DebugLoc::None,
|
||||
|bcx, _| trans_trait_callee_from_llval(bcx,
|
||||
method_fn_ty,
|
||||
vtable_index,
|
||||
llself, llvtable),
|
||||
ArgVals(&llargs[(self_idx + 2)..]),
|
||||
dest).bcx;
|
||||
let callee = Callee {
|
||||
data: Virtual(vtable_index),
|
||||
ty: method_ty
|
||||
};
|
||||
bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[self_idx..]), dest).bcx;
|
||||
|
||||
finish_fn(&fcx, bcx, ret_ty, DebugLoc::None);
|
||||
|
||||
|
|
@ -465,8 +278,7 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
/// making an object `Foo<Trait>` from a value of type `Foo<T>`, then
|
||||
/// `trait_ref` would map `T:Trait`.
|
||||
pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
param_substs: &'tcx subst::Substs<'tcx>)
|
||||
trait_ref: ty::PolyTraitRef<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
let tcx = ccx.tcx();
|
||||
|
|
@ -502,8 +314,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
Some(mth) => {
|
||||
trans_fn_ref_with_substs(ccx,
|
||||
mth.method.def_id,
|
||||
ExprId(0),
|
||||
param_substs,
|
||||
None,
|
||||
mth.substs).val
|
||||
}
|
||||
None => nullptr
|
||||
|
|
@ -566,7 +377,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
impl_id: DefId,
|
||||
substs: subst::Substs<'tcx>)
|
||||
substs: &'tcx subst::Substs<'tcx>)
|
||||
-> Vec<Option<ty::util::ImplMethod<'tcx>>>
|
||||
{
|
||||
let tcx = ccx.tcx();
|
||||
|
|
@ -617,7 +428,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
|
||||
// The substitutions we have are on the impl, so we grab
|
||||
// the method type from the impl to substitute into.
|
||||
let mth = tcx.get_impl_method(impl_id, substs.clone(), name);
|
||||
let mth = tcx.get_impl_method(impl_id, substs, name);
|
||||
|
||||
debug!("get_vtable_methods: mth={:?}", mth);
|
||||
|
||||
|
|
@ -627,7 +438,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
// method could then never be called, so we do not want to
|
||||
// try and trans it, in that case. Issue #23435.
|
||||
if mth.is_provided {
|
||||
let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
|
||||
let predicates = mth.method.predicates.predicates.subst(tcx, mth.substs);
|
||||
if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
|
||||
debug!("get_vtable_methods: predicates do not hold");
|
||||
return None;
|
||||
|
|
|
|||
|
|
@ -9,73 +9,27 @@
|
|||
// except according to those terms.
|
||||
|
||||
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc::middle::ty;
|
||||
use rustc::mir::repr as mir;
|
||||
use syntax::abi::Abi;
|
||||
use trans::adt;
|
||||
use trans::attributes;
|
||||
use trans::base;
|
||||
use trans::build;
|
||||
use trans::callee::{Callee, Fn, Virtual};
|
||||
use trans::common::{self, Block, BlockAndBuilder};
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::Disr;
|
||||
use trans::foreign;
|
||||
use trans::meth;
|
||||
use trans::type_of;
|
||||
use trans::glue;
|
||||
use trans::type_::Type;
|
||||
|
||||
use super::{MirContext, drop};
|
||||
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
|
||||
use super::operand::OperandRef;
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum AbiStyle {
|
||||
Foreign,
|
||||
RustCall,
|
||||
Rust
|
||||
}
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle {
|
||||
match fn_ty.sty {
|
||||
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
|
||||
// We do not translate intrinsics here (they shouldn’t be functions)
|
||||
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
|
||||
|
||||
match f.abi {
|
||||
Abi::Rust => AbiStyle::Rust,
|
||||
Abi::RustCall => AbiStyle::RustCall,
|
||||
_ => AbiStyle::Foreign
|
||||
}
|
||||
}
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_operands(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
abi_style: AbiStyle,
|
||||
args: &[mir::Operand<'tcx>])
|
||||
-> Vec<OperandRef<'tcx>>
|
||||
{
|
||||
match abi_style {
|
||||
AbiStyle::Foreign | AbiStyle::Rust => {
|
||||
args.iter().map(|arg| self.trans_operand(bcx, arg)).collect()
|
||||
}
|
||||
AbiStyle::RustCall => match args.split_last() {
|
||||
None => vec![],
|
||||
Some((tup, self_ty)) => {
|
||||
// we can reorder safely because of MIR
|
||||
let untupled_args = self.trans_operand_untupled(bcx, tup);
|
||||
self_ty
|
||||
.iter().map(|arg| self.trans_operand(bcx, arg))
|
||||
.chain(untupled_args.into_iter())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
|
||||
debug!("trans_block({:?})", bb);
|
||||
|
||||
|
|
@ -198,9 +152,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
}
|
||||
|
||||
mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => {
|
||||
// Create the callee. This will always be a fn ptr and hence a kind of scalar.
|
||||
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
|
||||
let callee = self.trans_operand(&bcx, func);
|
||||
let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty);
|
||||
let debugloc = DebugLoc::None;
|
||||
// The arguments we'll be passing. Plus one to account for outptr, if used.
|
||||
let mut llargs = Vec::with_capacity(args.len() + 1);
|
||||
|
|
@ -208,9 +161,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
// filled when `is_foreign` is `true` and foreign calls are minority of the cases.
|
||||
let mut arg_tys = Vec::new();
|
||||
|
||||
let (callee, fty) = match callee.ty.sty {
|
||||
ty::TyFnDef(def_id, substs, f) => {
|
||||
(Callee::def(bcx.ccx(), def_id, substs, callee.ty), f)
|
||||
}
|
||||
ty::TyFnPtr(f) => {
|
||||
(Callee {
|
||||
data: Fn(callee.immediate()),
|
||||
ty: callee.ty
|
||||
}, f)
|
||||
}
|
||||
_ => unreachable!("{} is not callable", callee.ty)
|
||||
};
|
||||
|
||||
// We do not translate intrinsics here (they shouldn’t be functions)
|
||||
assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic);
|
||||
// Foreign-ABI functions are translated differently
|
||||
let abi_style = self.abi_style(callee.ty);
|
||||
let is_foreign = abi_style == AbiStyle::Foreign;
|
||||
let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall;
|
||||
|
||||
// Prepare the return value destination
|
||||
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
|
||||
|
|
@ -226,19 +193,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
(None, false)
|
||||
};
|
||||
|
||||
// Process the rest of the args.
|
||||
for operand in self.arg_operands(&bcx, abi_style, args) {
|
||||
match operand.val {
|
||||
Ref(llval) | Immediate(llval) => llargs.push(llval),
|
||||
FatPtr(b, e) => {
|
||||
llargs.push(b);
|
||||
llargs.push(e);
|
||||
// Split the rust-call tupled arguments off.
|
||||
let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() {
|
||||
let (tup, args) = args.split_last().unwrap();
|
||||
// we can reorder safely because of MIR
|
||||
(args, self.trans_operand_untupled(&bcx, tup))
|
||||
} else {
|
||||
(&args[..], vec![])
|
||||
};
|
||||
|
||||
let datum = {
|
||||
let mut arg_ops = args.iter().map(|arg| {
|
||||
self.trans_operand(&bcx, arg)
|
||||
}).chain(rest.into_iter());
|
||||
|
||||
// Get the actual pointer we can call.
|
||||
// This can involve vtable accesses or reification.
|
||||
let datum = if let Virtual(idx) = callee.data {
|
||||
assert!(!is_foreign);
|
||||
|
||||
// Grab the first argument which is a trait object.
|
||||
let vtable = match arg_ops.next().unwrap().val {
|
||||
FatPtr(data, vtable) => {
|
||||
llargs.push(data);
|
||||
vtable
|
||||
}
|
||||
_ => unreachable!("expected FatPtr for Virtual call")
|
||||
};
|
||||
|
||||
bcx.with_block(|bcx| {
|
||||
meth::get_virtual_method(bcx, vtable, idx, callee.ty)
|
||||
})
|
||||
} else {
|
||||
callee.reify(bcx.ccx())
|
||||
};
|
||||
|
||||
// Process the rest of the args.
|
||||
for operand in arg_ops {
|
||||
match operand.val {
|
||||
Ref(llval) | Immediate(llval) => llargs.push(llval),
|
||||
FatPtr(b, e) => {
|
||||
llargs.push(b);
|
||||
llargs.push(e);
|
||||
}
|
||||
}
|
||||
if is_foreign {
|
||||
arg_tys.push(operand.ty);
|
||||
}
|
||||
}
|
||||
if is_foreign {
|
||||
arg_tys.push(operand.ty);
|
||||
}
|
||||
}
|
||||
|
||||
datum
|
||||
};
|
||||
let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty);
|
||||
|
||||
// Many different ways to call a function handled here
|
||||
match (is_foreign, cleanup, destination) {
|
||||
|
|
@ -247,7 +253,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let cleanup = self.bcx(cleanup);
|
||||
let landingpad = self.make_landing_pad(cleanup);
|
||||
let unreachable_blk = self.unreachable_block();
|
||||
bcx.invoke(callee.immediate(),
|
||||
bcx.invoke(datum.val,
|
||||
&llargs[..],
|
||||
unreachable_blk.llbb,
|
||||
landingpad.llbb(),
|
||||
|
|
@ -260,7 +266,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
(false, &Some(cleanup), &Some((_, success))) => {
|
||||
let cleanup = self.bcx(cleanup);
|
||||
let landingpad = self.make_landing_pad(cleanup);
|
||||
let invokeret = bcx.invoke(callee.immediate(),
|
||||
let invokeret = bcx.invoke(datum.val,
|
||||
&llargs[..],
|
||||
self.llblock(success),
|
||||
landingpad.llbb(),
|
||||
|
|
@ -283,7 +289,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
});
|
||||
},
|
||||
(false, _, &None) => {
|
||||
bcx.call(callee.immediate(),
|
||||
bcx.call(datum.val,
|
||||
&llargs[..],
|
||||
cleanup_bundle.as_ref(),
|
||||
Some(attrs));
|
||||
|
|
@ -291,7 +297,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
bcx.unreachable();
|
||||
}
|
||||
(false, _, &Some((_, target))) => {
|
||||
let llret = bcx.call(callee.immediate(),
|
||||
let llret = bcx.call(datum.val,
|
||||
&llargs[..],
|
||||
cleanup_bundle.as_ref(),
|
||||
Some(attrs));
|
||||
|
|
@ -313,8 +319,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
.expect("return destination is not set");
|
||||
bcx = bcx.map_block(|bcx| {
|
||||
foreign::trans_native_call(bcx,
|
||||
callee.ty,
|
||||
callee.immediate(),
|
||||
datum.ty,
|
||||
datum.val,
|
||||
dest.llval,
|
||||
&llargs[..],
|
||||
arg_tys,
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
|
||||
use back::abi;
|
||||
use llvm::ValueRef;
|
||||
use middle::subst::Substs;
|
||||
use middle::ty::{Ty, TypeFoldable};
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::const_eval::{self, ConstVal};
|
||||
use rustc::mir::repr as mir;
|
||||
use trans::common::{self, BlockAndBuilder, C_bool, C_bytes, C_floating_f64, C_integral,
|
||||
C_str_slice};
|
||||
C_str_slice, C_nil, C_undef};
|
||||
use trans::consts;
|
||||
use trans::expr;
|
||||
use trans::inline;
|
||||
use trans::type_of;
|
||||
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
|
|
@ -32,7 +32,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
-> OperandRef<'tcx>
|
||||
{
|
||||
let ccx = bcx.ccx();
|
||||
let val = self.trans_constval_inner(bcx, cv, ty, bcx.fcx().param_substs);
|
||||
let val = self.trans_constval_inner(bcx, cv, ty);
|
||||
let val = if common::type_is_immediate(ccx, ty) {
|
||||
OperandValue::Immediate(val)
|
||||
} else if common::type_is_fat_ptr(bcx.tcx(), ty) {
|
||||
|
|
@ -55,8 +55,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
fn trans_constval_inner(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
cv: &ConstVal,
|
||||
ty: Ty<'tcx>,
|
||||
param_substs: &'tcx Substs<'tcx>)
|
||||
ty: Ty<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
let ccx = bcx.ccx();
|
||||
|
|
@ -75,8 +74,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
expr::trans(bcx, expr).datum.val
|
||||
})
|
||||
},
|
||||
ConstVal::Function(did) =>
|
||||
self.trans_fn_ref(bcx, ty, param_substs, did).immediate()
|
||||
ConstVal::Function(_) => C_nil(ccx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -85,13 +83,31 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
constant: &mir::Constant<'tcx>)
|
||||
-> OperandRef<'tcx>
|
||||
{
|
||||
let ty = bcx.monomorphize(&constant.ty);
|
||||
match constant.literal {
|
||||
mir::Literal::Item { def_id, kind, substs } => {
|
||||
mir::Literal::Item { def_id, substs } => {
|
||||
// Shortcut for zero-sized types, including function item
|
||||
// types, which would not work with lookup_const_by_id.
|
||||
if common::type_is_zero_size(bcx.ccx(), ty) {
|
||||
let llty = type_of::type_of(bcx.ccx(), ty);
|
||||
return OperandRef {
|
||||
val: OperandValue::Immediate(C_undef(llty)),
|
||||
ty: ty
|
||||
};
|
||||
}
|
||||
|
||||
let substs = bcx.tcx().mk_substs(bcx.monomorphize(&substs));
|
||||
self.trans_item_ref(bcx, constant.ty, kind, substs, def_id)
|
||||
let def_id = inline::maybe_instantiate_inline(bcx.ccx(), def_id);
|
||||
let expr = const_eval::lookup_const_by_id(bcx.tcx(), def_id, None, Some(substs))
|
||||
.expect("def was const, but lookup_const_by_id failed");
|
||||
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
|
||||
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
|
||||
let d = bcx.with_block(|bcx| {
|
||||
expr::trans(bcx, expr)
|
||||
});
|
||||
OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
|
||||
}
|
||||
mir::Literal::Value { ref value } => {
|
||||
let ty = bcx.monomorphize(&constant.ty);
|
||||
self.trans_constval(bcx, value, ty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,171 +0,0 @@
|
|||
// Copyright 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.
|
||||
|
||||
//! Code for translating references to other items (DefIds).
|
||||
|
||||
use syntax::codemap::DUMMY_SP;
|
||||
use rustc::front::map;
|
||||
use rustc::middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::traits;
|
||||
use rustc::mir::repr::ItemKind;
|
||||
use trans::common::{BlockAndBuilder, fulfill_obligation};
|
||||
use trans::base;
|
||||
use trans::closure;
|
||||
use trans::expr;
|
||||
use trans::monomorphize;
|
||||
use trans::meth;
|
||||
use trans::inline;
|
||||
|
||||
use super::MirContext;
|
||||
use super::operand::{OperandRef, OperandValue};
|
||||
|
||||
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
/// Translate reference to item.
|
||||
pub fn trans_item_ref(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
kind: ItemKind,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
did: DefId)
|
||||
-> OperandRef<'tcx> {
|
||||
debug!("trans_item_ref(ty={:?}, kind={:?}, substs={:?}, did={})",
|
||||
ty, kind, substs, bcx.tcx().item_path_str(did));
|
||||
|
||||
match kind {
|
||||
ItemKind::Function => self.trans_fn_ref(bcx, ty, substs, did),
|
||||
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
|
||||
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
|
||||
ty::TraitContainer(tdid) => self.trans_trait_method(bcx, ty, did, tdid, substs)
|
||||
},
|
||||
ItemKind::Constant => {
|
||||
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
|
||||
let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None, Some(substs))
|
||||
.expect("def was const, but lookup_const_by_id failed");
|
||||
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
|
||||
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
|
||||
let d = bcx.with_block(|bcx| {
|
||||
expr::trans(bcx, expr)
|
||||
});
|
||||
OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates references to a function-like items.
|
||||
///
|
||||
/// That includes regular functions, non-static methods, struct and enum variant constructors,
|
||||
/// closures and possibly more.
|
||||
///
|
||||
/// This is an adaptation of callee::trans_fn_ref_with_substs.
|
||||
pub fn trans_fn_ref(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
did: DefId)
|
||||
-> OperandRef<'tcx> {
|
||||
debug!("trans_fn_ref(ty={:?}, substs={:?}, did={})",
|
||||
ty, substs, bcx.tcx().item_path_str(did));
|
||||
|
||||
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
|
||||
|
||||
if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
|
||||
let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs);
|
||||
// FIXME: cast fnptr to proper type if necessary
|
||||
OperandRef {
|
||||
ty: fn_ty,
|
||||
val: OperandValue::Immediate(val)
|
||||
}
|
||||
} else {
|
||||
let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
|
||||
base::get_item_val(bcx.ccx(), node_id)
|
||||
} else {
|
||||
base::trans_external_path(bcx.ccx(), did, ty)
|
||||
};
|
||||
// FIXME: cast fnptr to proper type if necessary
|
||||
OperandRef {
|
||||
ty: ty,
|
||||
val: OperandValue::Immediate(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Translates references to trait methods.
|
||||
///
|
||||
/// This is an adaptation of meth::trans_static_method_callee
|
||||
pub fn trans_trait_method(&mut self,
|
||||
bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
method_id: DefId,
|
||||
trait_id: DefId,
|
||||
substs: &'tcx Substs<'tcx>)
|
||||
-> OperandRef<'tcx> {
|
||||
debug!("trans_static_method(ty={:?}, method={}, trait={}, substs={:?})",
|
||||
ty,
|
||||
bcx.tcx().item_path_str(method_id),
|
||||
bcx.tcx().item_path_str(trait_id),
|
||||
substs);
|
||||
|
||||
let ccx = bcx.ccx();
|
||||
let tcx = bcx.tcx();
|
||||
let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
|
||||
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
|
||||
match vtbl {
|
||||
traits::VtableImpl(traits::VtableImplData {
|
||||
impl_def_id, substs: impl_substs, ..
|
||||
}) => {
|
||||
assert!(!impl_substs.types.needs_infer());
|
||||
|
||||
let mname = tcx.item_name(method_id);
|
||||
|
||||
let callee_substs = impl_substs.with_method_from(substs);
|
||||
let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
|
||||
let mth_substs = tcx.mk_substs(mth.substs);
|
||||
self.trans_fn_ref(bcx, ty, mth_substs, mth.method.def_id)
|
||||
},
|
||||
traits::VtableClosure(data) => {
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = closure::trans_closure_method(bcx.ccx(),
|
||||
data.closure_def_id,
|
||||
data.substs,
|
||||
trait_closure_kind);
|
||||
OperandRef {
|
||||
ty: ty,
|
||||
val: OperandValue::Immediate(llfn)
|
||||
}
|
||||
},
|
||||
traits::VtableObject(ref data) => {
|
||||
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
|
||||
OperandRef::from_rvalue_datum(
|
||||
meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
|
||||
)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_named_tuple_constructor(tcx: &TyCtxt, def_id: DefId) -> bool {
|
||||
let node_id = match tcx.map.as_local_node_id(def_id) {
|
||||
Some(n) => n,
|
||||
None => { return false; }
|
||||
};
|
||||
match tcx.map.find(node_id).expect("local item should be in ast map") {
|
||||
map::NodeVariant(v) => {
|
||||
v.node.data.is_tuple()
|
||||
}
|
||||
map::NodeStructCtor(_) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
|
@ -196,7 +196,6 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
|
|||
mod analyze;
|
||||
mod block;
|
||||
mod constant;
|
||||
mod did;
|
||||
mod drop;
|
||||
mod lvalue;
|
||||
mod operand;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use rustc::mir::repr as mir;
|
|||
|
||||
use trans::asm;
|
||||
use trans::base;
|
||||
use trans::callee::Callee;
|
||||
use trans::common::{self, BlockAndBuilder, Result};
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::declare;
|
||||
|
|
@ -193,9 +194,20 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
|||
let cast_ty = bcx.monomorphize(&cast_ty);
|
||||
|
||||
let val = match *kind {
|
||||
mir::CastKind::ReifyFnPointer |
|
||||
mir::CastKind::ReifyFnPointer => {
|
||||
match operand.ty.sty {
|
||||
ty::TyFnDef(def_id, substs, _) => {
|
||||
OperandValue::Immediate(
|
||||
Callee::def(bcx.ccx(), def_id, substs, operand.ty)
|
||||
.reify(bcx.ccx()).val)
|
||||
}
|
||||
_ => {
|
||||
unreachable!("{} cannot be reified to a fn ptr", operand.ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
mir::CastKind::UnsafeFnPointer => {
|
||||
// these are no-ops at the LLVM level
|
||||
// this is a no-op at the LLVM level
|
||||
operand.val
|
||||
}
|
||||
mir::CastKind::Unsize => {
|
||||
|
|
|
|||
|
|
@ -190,7 +190,8 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
|
|||
}
|
||||
}
|
||||
|
||||
ty::TyFnDef(..) | ty::TyFnPtr(_) => Type::i8p(cx),
|
||||
ty::TyFnDef(..) => Type::nil(cx),
|
||||
ty::TyFnPtr(_) => Type::i8p(cx),
|
||||
|
||||
ty::TyArray(ty, size) => {
|
||||
let llty = sizing_type_of(cx, ty);
|
||||
|
|
@ -395,9 +396,8 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
|||
ty::TySlice(ty) => in_memory_type_of(cx, ty),
|
||||
ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
|
||||
|
||||
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
|
||||
// FIXME(#19925) once fn item types are
|
||||
// zero-sized, we'll need to do something here
|
||||
ty::TyFnDef(..) => Type::nil(cx),
|
||||
ty::TyFnPtr(f) => {
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue