trans: Reify functions & methods to fn ptrs only where necessary.

This commit is contained in:
Eduard Burtescu 2016-03-06 17:32:47 +02:00
parent c284099f56
commit 8f07f8a4fa
28 changed files with 683 additions and 1318 deletions

View file

@ -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))

View file

@ -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>
}

View file

@ -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);
}
}

View file

@ -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 }
}

View file

@ -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),
}
}

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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
}
}),

View file

@ -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 }
}
}

View file

@ -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,

View file

@ -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[..]);

View file

@ -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

View file

@ -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);

View file

@ -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;
}

View file

@ -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,

View file

@ -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")

View file

@ -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.

View file

@ -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)
}

View file

@ -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,

View file

@ -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;

View file

@ -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 shouldnt 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 shouldnt 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,

View file

@ -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)
}
}

View file

@ -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
}
}

View file

@ -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;

View file

@ -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 => {

View file

@ -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);