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))
#[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>
}
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);
}
}
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 }
}
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),
}
}
#[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>
{
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
}
}
}
}
-#[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 {
//! kind of thing.
use build::Builder;
-use hair::*;
use rustc::middle::ty::Ty;
use rustc::mir::repr::*;
use std::u32;
});
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)
- }
}
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())
}
}
ty: tcx.lookup_item_type(free_func).ty.subst(tcx, substs),
literal: Literal::Item {
def_id: free_func,
- kind: ItemKind::Function,
substs: substs
}
}),
kind: ExprKind::Literal {
literal: Literal::Item {
def_id: callee.def_id,
- kind: ItemKind::Method,
substs: callee.substs,
},
},
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 {
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);
if let Some(v) = cx.try_const_eval_literal(expr) {
return ExprKind::Literal { literal: v };
} else {
- (def_id, ItemKind::Constant)
+ def_id
}
}
&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 }
}
}
//! 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;
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,
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());
expr_ty(bcx, &out.expr),
out_datum,
cleanup::CustomScope(temp_scope),
- callee::DontAutorefArg,
&mut ext_inputs);
ext_constraints.push(i.to_string());
}
expr_ty(bcx, &input),
in_datum,
cleanup::CustomScope(temp_scope),
- callee::DontAutorefArg,
&mut inputs);
}
inputs.extend_from_slice(&ext_inputs[..]);
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
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) {
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 {:?} -> {:?}",
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"),
}
}
}
-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)
}
}
.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 =
//! and methods are represented as just a fn ptr and not a full
//! closure.
-pub use self::AutorefArg::*;
pub use self::CalleeData::*;
pub use self::CallArgs::*;
use back::link;
use llvm::{self, ValueRef, get_params};
use middle::cstore::LOCAL_CRATE;
-use middle::def::Def;
use middle::def_id::DefId;
use middle::infer;
use middle::subst;
use trans::base;
use trans::base::*;
use trans::build::*;
-use trans::callee;
use trans::cleanup;
use trans::cleanup::CleanupMethods;
use trans::common::{self, Block, Result, NodeIdAndSpan, ExprId, CrateContext,
ExprOrMethodCall, FunctionContext, MethodCallKey};
use trans::consts;
use trans::datum::*;
-use trans::debuginfo::{DebugLoc, ToDebugLoc};
+use trans::debuginfo::DebugLoc;
use trans::declare;
use trans::expr;
use trans::glue;
use trans::type_of;
use trans::Disr;
use middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use middle::ty::MethodCall;
use rustc_front::hir;
use syntax::abi::Abi;
use syntax::ast;
+use syntax::codemap::DUMMY_SP;
use syntax::errors;
use syntax::ptr::P;
-#[derive(Copy, Clone)]
-pub struct MethodData {
- pub llfn: ValueRef,
- pub llself: ValueRef,
-}
-
pub enum CalleeData<'tcx> {
- // Constructor for enum variant/tuple-like-struct
- // i.e. Some, Ok
+ /// Constructor for enum variant/tuple-like-struct.
NamedTupleConstructor(Disr),
- // Represents a (possibly monomorphized) top-level fn item or method
- // item. Note that this is just the fn-ptr and is not a Rust closure
- // value (which is a pair).
- Fn(/* llfn */ ValueRef),
+ /// Function pointer.
+ Fn(ValueRef),
- Intrinsic(ast::NodeId, subst::Substs<'tcx>),
+ Intrinsic(ast::NodeId, &'tcx subst::Substs<'tcx>),
- TraitItem(MethodData)
+ /// Trait object found in the vtable at that index.
+ Virtual(usize)
}
-pub struct Callee<'blk, 'tcx: 'blk> {
- pub bcx: Block<'blk, 'tcx>,
+pub struct Callee<'tcx> {
pub data: CalleeData<'tcx>,
pub ty: Ty<'tcx>
}
-fn trans<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
- -> Callee<'blk, 'tcx> {
- let _icx = push_ctxt("trans_callee");
- debug!("callee::trans(expr={:?})", expr);
-
- // pick out special kinds of expressions that can be called:
- match expr.node {
- hir::ExprPath(..) => {
- return trans_def(bcx, bcx.def(expr.id), expr);
+impl<'tcx> Callee<'tcx> {
+ /// Function pointer.
+ pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> {
+ Callee {
+ data: Fn(datum.val),
+ ty: datum.ty
}
- _ => {}
}
- // any other expressions are closures:
- return datum_callee(bcx, expr);
-
- fn datum_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, expr: &hir::Expr)
- -> Callee<'blk, 'tcx> {
- let DatumBlock { bcx, datum, .. } = expr::trans(bcx, expr);
- match datum.ty.sty {
- ty::TyFnDef(..) | ty::TyFnPtr(_) => {
- Callee {
- bcx: bcx,
- ty: datum.ty,
- data: Fn(datum.to_llscalarish(bcx))
- }
- }
- _ => {
- bcx.tcx().sess.span_bug(
- expr.span,
- &format!("type of callee is neither bare-fn nor closure: {}",
- datum.ty));
- }
- }
+ /// Trait or impl method call.
+ pub fn method_call<'blk>(bcx: Block<'blk, 'tcx>,
+ method_call: ty::MethodCall)
+ -> Callee<'tcx> {
+ let method = bcx.tcx().tables.borrow().method_map[&method_call];
+ Callee::method(bcx, method)
}
- fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>)
- -> Callee<'blk, 'tcx> {
- Callee {
- bcx: bcx,
- data: Fn(datum.val),
- ty: datum.ty
- }
+ /// Trait or impl method.
+ pub fn method<'blk>(bcx: Block<'blk, 'tcx>,
+ method: ty::MethodCallee<'tcx>) -> Callee<'tcx> {
+ let substs = bcx.tcx().mk_substs(bcx.fcx.monomorphize(&method.substs));
+ let ty = bcx.fcx.monomorphize(&method.ty);
+ Callee::def(bcx.ccx(), method.def_id, substs, ty)
}
- fn trans_def<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- def: Def,
- ref_expr: &hir::Expr)
- -> Callee<'blk, 'tcx> {
- debug!("trans_def(def={:?}, ref_expr={:?})", def, ref_expr);
- let expr_ty = common::node_id_type(bcx, ref_expr.id);
- match def {
- Def::Fn(did) if {
- let maybe_def_id = inline::get_local_instance(bcx.ccx(), did);
- let maybe_ast_node = maybe_def_id.and_then(|def_id| {
- let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
- bcx.tcx().map.find(node_id)
- });
- match maybe_ast_node {
- Some(hir_map::NodeStructCtor(_)) => true,
- _ => false
- }
- } => {
- Callee {
- bcx: bcx,
+ /// Function or method definition.
+ pub fn def<'a>(ccx: &CrateContext<'a, 'tcx>,
+ def_id: DefId,
+ substs: &'tcx subst::Substs<'tcx>,
+ ty: Ty<'tcx>)
+ -> Callee<'tcx> {
+ let tcx = ccx.tcx();
+
+ if substs.self_ty().is_some() {
+ // Only trait methods can have a Self parameter.
+ let method_item = tcx.impl_or_trait_item(def_id);
+ let trait_id = method_item.container().id();
+ let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
+ let vtbl = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+ return meth::callee_for_trait_impl(ccx, def_id, substs,
+ trait_id, ty, vtbl);
+ }
+
+ let maybe_node_id = inline::get_local_instance(ccx, def_id)
+ .and_then(|def_id| tcx.map.as_local_node_id(def_id));
+ let maybe_ast_node = maybe_node_id.and_then(|node_id| {
+ tcx.map.find(node_id)
+ });
+ match maybe_ast_node {
+ Some(hir_map::NodeStructCtor(_)) => {
+ return Callee {
data: NamedTupleConstructor(Disr(0)),
- ty: expr_ty
- }
- }
- Def::Fn(did) if match expr_ty.sty {
- ty::TyFnDef(_, _, ref f) => f.abi == Abi::RustIntrinsic ||
- f.abi == Abi::PlatformIntrinsic,
- _ => false
- } => {
- let substs = common::node_id_substs(bcx.ccx(),
- ExprId(ref_expr.id),
- bcx.fcx.param_substs);
- let def_id = inline::maybe_instantiate_inline(bcx.ccx(), did);
- let node_id = bcx.tcx().map.as_local_node_id(def_id).unwrap();
- Callee { bcx: bcx, data: Intrinsic(node_id, substs), ty: expr_ty }
- }
- Def::Fn(did) => {
- fn_callee(bcx, trans_fn_ref(bcx.ccx(), did, ExprId(ref_expr.id),
- bcx.fcx.param_substs))
- }
- Def::Method(meth_did) => {
- let method_item = bcx.tcx().impl_or_trait_item(meth_did);
- let fn_datum = match method_item.container() {
- ty::ImplContainer(_) => {
- trans_fn_ref(bcx.ccx(), meth_did,
- ExprId(ref_expr.id),
- bcx.fcx.param_substs)
- }
- ty::TraitContainer(trait_did) => {
- meth::trans_static_method_callee(bcx.ccx(),
- meth_did,
- trait_did,
- ref_expr.id,
- bcx.fcx.param_substs)
- }
+ ty: ty
};
- fn_callee(bcx, fn_datum)
}
- Def::Variant(tid, vid) => {
- let vinfo = bcx.tcx().lookup_adt_def(tid).variant_with_id(vid);
+ Some(hir_map::NodeVariant(_)) => {
+ let vinfo = common::inlined_variant_def(ccx, maybe_node_id.unwrap());
assert_eq!(vinfo.kind(), ty::VariantKind::Tuple);
- Callee {
- bcx: bcx,
+ return Callee {
data: NamedTupleConstructor(Disr::from(vinfo.disr_val)),
- ty: expr_ty
- }
+ ty: ty
+ };
}
- Def::Struct(..) => {
- Callee {
- bcx: bcx,
- data: NamedTupleConstructor(Disr(0)),
- ty: expr_ty
+ Some(hir_map::NodeForeignItem(fi)) => {
+ let abi = tcx.map.get_foreign_abi(fi.id);
+ if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
+ return Callee {
+ data: Intrinsic(fi.id, substs),
+ ty: ty
+ };
}
}
- Def::Static(..) |
- Def::Const(..) |
- Def::AssociatedConst(..) |
- Def::Local(..) |
- Def::Upvar(..) => {
- datum_callee(bcx, ref_expr)
- }
- Def::Mod(..) | Def::ForeignMod(..) | Def::Trait(..) |
- Def::Enum(..) | Def::TyAlias(..) | Def::PrimTy(..) |
- Def::AssociatedTy(..) | Def::Label(..) | Def::TyParam(..) |
- Def::SelfTy(..) | Def::Err => {
- bcx.tcx().sess.span_bug(
- ref_expr.span,
- &format!("cannot translate def {:?} \
- to a callable thing!", def));
+ _ => {}
+ }
+ Callee::ptr(trans_fn_ref_with_substs(ccx, def_id, Some(ty), substs))
+ }
+
+ /// This behemoth of a function translates function calls. Unfortunately, in
+ /// order to generate more efficient LLVM output at -O0, it has quite a complex
+ /// signature (refactoring this into two functions seems like a good idea).
+ ///
+ /// In particular, for lang items, it is invoked with a dest of None, and in
+ /// that case the return value contains the result of the fn. The lang item must
+ /// not return a structural type or else all heck breaks loose.
+ ///
+ /// For non-lang items, `dest` is always Some, and hence the result is written
+ /// into memory somewhere. Nonetheless we return the actual return value of the
+ /// function.
+ pub fn call<'a, 'blk>(self, bcx: Block<'blk, 'tcx>,
+ debug_loc: DebugLoc,
+ args: CallArgs<'a, 'tcx>,
+ dest: Option<expr::Dest>)
+ -> Result<'blk, 'tcx> {
+ trans_call_inner(bcx, debug_loc, self, args, dest)
+ }
+
+ /// Turn the callee into a function pointer.
+ pub fn reify<'a>(self, ccx: &CrateContext<'a, 'tcx>)
+ -> Datum<'tcx, Rvalue> {
+ match self.data {
+ Fn(llfn) => {
+ let fn_ptr_ty = match self.ty.sty {
+ ty::TyFnDef(_, _, f) => ccx.tcx().mk_ty(ty::TyFnPtr(f)),
+ _ => self.ty
+ };
+ immediate_rvalue(llfn, fn_ptr_ty)
}
+ Virtual(idx) => meth::trans_object_shim(ccx, self.ty, idx),
+ NamedTupleConstructor(_) => match self.ty.sty {
+ ty::TyFnDef(def_id, substs, _) => {
+ return trans_fn_ref_with_substs(ccx, def_id, Some(self.ty), substs);
+ }
+ _ => unreachable!("expected fn item type, found {}", self.ty)
+ },
+ Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty)
}
}
}
def_id,
node,
substs);
- trans_fn_ref_with_substs(ccx, def_id, node, param_substs, substs)
+ let ref_ty = match node {
+ ExprId(0) => return trans_fn_ref_with_substs(ccx, def_id, None, substs),
+ ExprId(id) => ccx.tcx().node_id_to_type(id),
+ MethodCallKey(method_call) => {
+ ccx.tcx().tables.borrow().method_map[&method_call].ty
+ }
+ };
+ let ref_ty = monomorphize::apply_param_substs(ccx.tcx(),
+ param_substs,
+ &ref_ty);
+ trans_fn_ref_with_substs(ccx, def_id, Some(ref_ty), substs)
}
/// Translates an adapter that implements the `Fn` trait for a fn
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
// which is the fn pointer, and `args`, which is the arguments tuple.
- let (opt_def_id_and_substs, sig) =
- match bare_fn_ty.sty {
- ty::TyFnDef(def_id, substs,
- &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- ref sig }) => {
- (Some((def_id, substs)), sig)
- }
- ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- ref sig }) => {
- (None, sig)
- }
+ let sig = match bare_fn_ty.sty {
+ ty::TyFnDef(_, _,
+ &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+ abi: Abi::Rust,
+ ref sig }) |
+ ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
+ abi: Abi::Rust,
+ ref sig }) => sig,
- _ => {
- tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
- bare_fn_ty));
- }
- };
+ _ => {
+ tcx.sess.bug(&format!("trans_fn_pointer_shim invoked on invalid type: {}",
+ bare_fn_ty));
+ }
+ };
let sig = tcx.erase_late_bound_regions(sig);
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
- let bare_tuple_fn = ty::BareFnTy {
+ let tuple_fn_ty = tcx.mk_fn_ptr(ty::BareFnTy {
unsafety: hir::Unsafety::Normal,
abi: Abi::RustCall,
sig: ty::Binder(ty::FnSig {
output: sig.output,
variadic: false
})
- };
- let tuple_fn_ty = match opt_def_id_and_substs {
- Some((def_id, substs)) => tcx.mk_fn_def(def_id, substs, bare_tuple_fn),
- None => tcx.mk_fn_ptr(bare_tuple_fn),
- };
+ });
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
let llargs = get_params(fcx.llfn);
let self_idx = fcx.arg_offset();
- // the first argument (`self`) will be ptr to the fn pointer
- let llfnpointer = if is_by_ref {
- Load(bcx, llargs[self_idx])
- } else {
- llargs[self_idx]
+ let llfnpointer = match bare_fn_ty.sty {
+ ty::TyFnDef(def_id, substs, _) => {
+ // Function definitions have to be turned into a pointer.
+ Callee::def(ccx, def_id, substs, bare_fn_ty).reify(ccx).val
+ }
+
+ // the first argument (`self`) will be ptr to the fn pointer
+ _ => if is_by_ref {
+ Load(bcx, llargs[self_idx])
+ } else {
+ llargs[self_idx]
+ }
};
assert!(!fcx.needs_ret_allocas);
expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot"))
);
- bcx = trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
- Callee {
- bcx: bcx,
- data: Fn(llfnpointer),
- ty: bare_fn_ty
- }
- }, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
+ let callee = Callee {
+ data: Fn(llfnpointer),
+ ty: bare_fn_ty
+ };
+ bcx = callee.call(bcx, DebugLoc::None, ArgVals(&llargs[(self_idx + 1)..]), dest).bcx;
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
/// - `node`: node id of the reference to the fn/method, if applicable.
/// This parameter may be zero; but, if so, the resulting value may not
/// have the right type, so it must be cast before being used.
-/// - `param_substs`: if the `node` is in a polymorphic function, these
-/// are the substitutions required to monomorphize its type
+/// - `ref_ty`: monotype of the reference to the fn/method, if applicable.
+/// This parameter may be None; but, if so, the resulting value may not
+/// have the right type, so it must be cast before being used.
/// - `substs`: values for each of the fn/method's parameters
pub fn trans_fn_ref_with_substs<'a, 'tcx>(
ccx: &CrateContext<'a, 'tcx>,
def_id: DefId,
- node: ExprOrMethodCall,
- param_substs: &'tcx subst::Substs<'tcx>,
- substs: subst::Substs<'tcx>)
+ ref_ty: Option<Ty<'tcx>>,
+ substs: &'tcx subst::Substs<'tcx>)
-> Datum<'tcx, Rvalue>
{
let _icx = push_ctxt("trans_fn_ref_with_substs");
let tcx = ccx.tcx();
- debug!("trans_fn_ref_with_substs(def_id={:?}, node={:?}, \
- param_substs={:?}, substs={:?})",
- def_id,
- node,
- param_substs,
- substs);
+ debug!("trans_fn_ref_with_substs(def_id={:?}, ref_ty={:?}, substs={:?})",
+ def_id, ref_ty, substs);
assert!(!substs.types.needs_infer());
assert!(!substs.types.has_escaping_regions());
- let substs = substs.erase_regions();
// Check whether this fn has an inlined copy and, if so, redirect
// def_id to the local id of the inlined copy.
// Should be either intra-crate or inlined.
assert_eq!(def_id.krate, LOCAL_CRATE);
- let substs = tcx.mk_substs(substs);
- let (val, fn_ty, must_cast) =
+ let substs = tcx.mk_substs(substs.clone().erase_regions());
+ let (mut val, fn_ty, must_cast) =
monomorphize::monomorphic_fn(ccx, def_id, substs);
- if must_cast && node != ExprId(0) {
- // Monotype of the REFERENCE to the function (type params
- // are subst'd)
- let ref_ty = match node {
- ExprId(id) => tcx.node_id_to_type(id),
- MethodCallKey(method_call) => {
- tcx.tables.borrow().method_map[&method_call].ty
- }
- };
- let ref_ty = monomorphize::apply_param_substs(tcx,
- param_substs,
- &ref_ty);
- let llptrty = type_of::type_of(ccx, ref_ty);
+ let fn_ty = ref_ty.unwrap_or(fn_ty);
+ let fn_ptr_ty = match fn_ty.sty {
+ ty::TyFnDef(_, _, fty) => {
+ // Create a fn pointer with the substituted signature.
+ tcx.mk_ty(ty::TyFnPtr(fty))
+ }
+ _ => unreachable!("expected fn item type, found {}", fn_ty)
+ };
+ if must_cast && ref_ty.is_some() {
+ let llptrty = type_of::type_of(ccx, fn_ptr_ty);
if llptrty != common::val_ty(val) {
- let val = consts::ptrcast(val, llptrty);
- return Datum::new(val, ref_ty, Rvalue::new(ByValue));
+ val = consts::ptrcast(val, llptrty);
}
}
- return Datum::new(val, fn_ty, Rvalue::new(ByValue));
+ return immediate_rvalue(val, fn_ptr_ty);
}
- // Type scheme of the function item (may have type params)
- let fn_type_scheme = tcx.lookup_item_type(def_id);
- let fn_type = infer::normalize_associated_type(tcx, &fn_type_scheme.ty);
-
// Find the actual function pointer.
- let mut val = {
- if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
- // Internal reference.
- get_item_val(ccx, node_id)
- } else {
- // External reference.
- trans_external_path(ccx, def_id, fn_type)
- }
+ let local_node = ccx.tcx().map.as_local_node_id(def_id);
+ let mut datum = if let Some(node_id) = local_node {
+ // Type scheme of the function item (may have type params)
+ let fn_type_scheme = tcx.lookup_item_type(def_id);
+ let fn_type = match fn_type_scheme.ty.sty {
+ ty::TyFnDef(_, _, fty) => {
+ // Create a fn pointer with the normalized signature.
+ tcx.mk_fn_ptr(infer::normalize_associated_type(tcx, fty))
+ }
+ _ => unreachable!("expected fn item type, found {}",
+ fn_type_scheme.ty)
+ };
+
+ // Internal reference.
+ immediate_rvalue(get_item_val(ccx, node_id), fn_type)
+ } else {
+ // External reference.
+ get_extern_fn(ccx, def_id)
};
// This is subtle and surprising, but sometimes we have to bitcast
// This can occur on either a crate-local or crate-external
// reference. It also occurs when testing libcore and in some
// other weird situations. Annoying.
- let llptrty = type_of::type_of(ccx, fn_type);
- if common::val_ty(val) != llptrty {
+ let llptrty = type_of::type_of(ccx, datum.ty);
+ if common::val_ty(datum.val) != llptrty {
debug!("trans_fn_ref_with_substs(): casting pointer!");
- val = consts::ptrcast(val, llptrty);
+ datum.val = consts::ptrcast(datum.val, llptrty);
} else {
debug!("trans_fn_ref_with_substs(): not casting pointer!");
}
- Datum::new(val, fn_type, Rvalue::new(ByValue))
+ datum
}
// ______________________________________________________________________
// Translating calls
-pub fn trans_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- call_expr: &hir::Expr,
- f: &hir::Expr,
- args: CallArgs<'a, 'tcx>,
- dest: expr::Dest)
- -> Block<'blk, 'tcx> {
- let _icx = push_ctxt("trans_call");
- trans_call_inner(bcx,
- call_expr.debug_loc(),
- |bcx, _| trans(bcx, f),
- args,
- Some(dest)).bcx
-}
-
-pub fn trans_method_call<'a, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
- call_expr: &hir::Expr,
- rcvr: &hir::Expr,
- args: CallArgs<'a, 'tcx>,
- dest: expr::Dest)
- -> Block<'blk, 'tcx> {
- let _icx = push_ctxt("trans_method_call");
- debug!("trans_method_call(call_expr={:?})", call_expr);
- let method_call = MethodCall::expr(call_expr.id);
- trans_call_inner(
- bcx,
- call_expr.debug_loc(),
- |cx, arg_cleanup_scope| {
- meth::trans_method_callee(cx, method_call, Some(rcvr), arg_cleanup_scope)
- },
- args,
- Some(dest)).bcx
-}
-
pub fn trans_lang_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
did: DefId,
args: &[ValueRef],
dest: Option<expr::Dest>,
debug_loc: DebugLoc)
-> Result<'blk, 'tcx> {
- callee::trans_call_inner(bcx, debug_loc, |bcx, _| {
- let datum = trans_fn_ref_with_substs(bcx.ccx(),
- did,
- ExprId(0),
- bcx.fcx.param_substs,
- subst::Substs::trans_empty());
- Callee {
- bcx: bcx,
- data: Fn(datum.val),
- ty: datum.ty
- }
- }, ArgVals(args), dest)
+ let datum = trans_fn_ref(bcx.ccx(), did, ExprId(0), bcx.fcx.param_substs);
+ Callee::ptr(datum).call(bcx, debug_loc, ArgVals(args), dest)
}
-/// This behemoth of a function translates function calls. Unfortunately, in
-/// order to generate more efficient LLVM output at -O0, it has quite a complex
-/// signature (refactoring this into two functions seems like a good idea).
-///
-/// In particular, for lang items, it is invoked with a dest of None, and in
-/// that case the return value contains the result of the fn. The lang item must
-/// not return a structural type or else all heck breaks loose.
-///
-/// For non-lang items, `dest` is always Some, and hence the result is written
-/// into memory somewhere. Nonetheless we return the actual return value of the
-/// function.
-pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
- debug_loc: DebugLoc,
- get_callee: F,
- args: CallArgs<'a, 'tcx>,
- dest: Option<expr::Dest>)
- -> Result<'blk, 'tcx> where
- F: FnOnce(Block<'blk, 'tcx>, cleanup::ScopeId) -> Callee<'blk, 'tcx>,
-{
+fn trans_call_inner<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
+ debug_loc: DebugLoc,
+ callee: Callee<'tcx>,
+ args: CallArgs<'a, 'tcx>,
+ dest: Option<expr::Dest>)
+ -> Result<'blk, 'tcx> {
// Introduce a temporary cleanup scope that will contain cleanups
// for the arguments while they are being evaluated. The purpose
// this cleanup is to ensure that, should a panic occur while
// scope will ever execute.
let fcx = bcx.fcx;
let ccx = fcx.ccx;
- let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
-
- let callee = get_callee(bcx, cleanup::CustomScope(arg_cleanup_scope));
- let mut bcx = callee.bcx;
let (abi, ret_ty) = match callee.ty.sty {
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
(f.abi, sig.output)
}
- _ => panic!("expected bare rust fn or closure in trans_call_inner")
+ _ => panic!("expected fn item or ptr in Callee::call")
};
- let (llfn, llself) = match callee.data {
- Fn(llfn) => {
- (llfn, None)
- }
- TraitItem(d) => {
- (d.llfn, Some(d.llself))
- }
+ match callee.data {
Intrinsic(node, substs) => {
assert!(abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic);
assert!(dest.is_some());
}
};
+ let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
return intrinsic::trans_intrinsic_call(bcx, node, callee.ty,
arg_cleanup_scope, args,
- dest.unwrap(), substs,
+ dest.unwrap(),
+ substs,
call_info);
}
NamedTupleConstructor(disr) => {
assert!(dest.is_some());
- fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
return base::trans_named_tuple_constructor(bcx,
callee.ty,
dest.unwrap(),
debug_loc);
}
- };
+ _ => {}
+ }
// Intrinsics should not become actual functions.
// We trans them in place in `trans_intrinsic_call`
llvm::LLVMGetUndef(Type::nil(ccx).ptr_to().to_ref())
};
+ let arg_cleanup_scope = fcx.push_custom_cleanup_scope();
+
// The code below invokes the function, using either the Rust
// conventions (if it is a rust fn) or the native conventions
// (otherwise). The important part is that, when all is said
}
}
- // Push a trait object's self.
- if let Some(llself) = llself {
- llargs.push(llself);
- }
+ let arg_start = llargs.len();
// Push the arguments.
bcx = trans_args(bcx,
callee.ty,
&mut llargs,
cleanup::CustomScope(arg_cleanup_scope),
- llself.is_some(),
abi);
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
+ let datum = match callee.data {
+ Fn(f) => immediate_rvalue(f, callee.ty),
+ Virtual(idx) => {
+ // The data and vtable pointers were split by trans_arg_datum.
+ let vtable = llargs.remove(arg_start + 1);
+ meth::get_virtual_method(bcx, vtable, idx, callee.ty)
+ }
+ _ => unreachable!()
+ };
+
// Invoke the actual rust fn and update bcx/llresult.
let (llret, b) = base::invoke(bcx,
- llfn,
+ datum.val,
&llargs[..],
- callee.ty,
+ datum.ty,
debug_loc);
bcx = b;
llresult = llret;
assert!(dest.is_some());
let mut llargs = Vec::new();
- let arg_tys = match args {
- ArgExprs(a) => a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect(),
- _ => panic!("expected arg exprs.")
+ let (llfn, arg_tys) = match (callee.data, &args) {
+ (Fn(f), &ArgExprs(a)) => {
+ (f, a.iter().map(|x| common::expr_ty_adjusted(bcx, &x)).collect())
+ }
+ _ => panic!("expected fn ptr and arg exprs.")
};
bcx = trans_args(bcx,
args,
callee.ty,
&mut llargs,
cleanup::CustomScope(arg_cleanup_scope),
- false,
abi);
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
}
pub enum CallArgs<'a, 'tcx> {
- // Supply value of arguments as a list of expressions that must be
- // translated. This is used in the common case of `foo(bar, qux)`.
+ /// Supply value of arguments as a list of expressions that must be
+ /// translated. This is used in the common case of `foo(bar, qux)`.
ArgExprs(&'a [P<hir::Expr>]),
- // Supply value of arguments as a list of LLVM value refs; frequently
- // used with lang items and so forth, when the argument is an internal
- // value.
+ /// Supply value of arguments as a list of LLVM value refs; frequently
+ /// used with lang items and so forth, when the argument is an internal
+ /// value.
ArgVals(&'a [ValueRef]),
- // For overloaded operators: `(lhs, Option(rhs, rhs_id), autoref)`. `lhs`
- // is the left-hand-side and `rhs/rhs_id` is the datum/expr-id of
- // the right-hand-side argument (if any). `autoref` indicates whether the `rhs`
- // arguments should be auto-referenced
- ArgOverloadedOp(Datum<'tcx, Expr>, Option<(Datum<'tcx, Expr>, ast::NodeId)>, bool),
+ /// For overloaded operators: `(lhs, Option(rhs))`.
+ /// `lhs` is the left-hand-side and `rhs` is the datum
+ /// of the right-hand-side argument (if any).
+ ArgOverloadedOp(Datum<'tcx, Expr>, Option<Datum<'tcx, Expr>>),
- // Supply value of arguments as a list of expressions that must be
- // translated, for overloaded call operators.
+ /// Supply value of arguments as a list of expressions that must be
+ /// translated, for overloaded call operators.
ArgOverloadedCall(Vec<&'a hir::Expr>),
}
arg_exprs: &[P<hir::Expr>],
fn_ty: Ty<'tcx>,
llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId,
- ignore_self: bool)
+ arg_cleanup_scope: cleanup::ScopeId)
-> Block<'blk, 'tcx>
{
let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
let args = sig.inputs;
// Translate the `self` argument first.
- if !ignore_self {
- let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
- bcx = trans_arg_datum(bcx,
- args[0],
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg,
- llargs);
- }
+ let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_exprs[0]));
+ bcx = trans_arg_datum(bcx,
+ args[0],
+ arg_datum,
+ arg_cleanup_scope,
+ llargs);
// Now untuple the rest of the arguments.
let tuple_expr = &arg_exprs[1];
field_type,
arg_datum,
arg_cleanup_scope,
- DontAutorefArg,
llargs);
}
}
arg_exprs: Vec<&hir::Expr>,
fn_ty: Ty<'tcx>,
llargs: &mut Vec<ValueRef>,
- arg_cleanup_scope: cleanup::ScopeId,
- ignore_self: bool)
+ arg_cleanup_scope: cleanup::ScopeId)
-> Block<'blk, 'tcx> {
// Translate the `self` argument first.
let sig = bcx.tcx().erase_late_bound_regions(&fn_ty.fn_sig());
let sig = infer::normalize_associated_type(bcx.tcx(), &sig);
let arg_tys = sig.inputs;
- if !ignore_self {
- let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
- bcx = trans_arg_datum(bcx,
- arg_tys[0],
- arg_datum,
- arg_cleanup_scope,
- DontAutorefArg,
- llargs);
- }
+ let arg_datum = unpack_datum!(bcx, expr::trans(bcx, arg_exprs[0]));
+ bcx = trans_arg_datum(bcx,
+ arg_tys[0],
+ arg_datum,
+ arg_cleanup_scope,
+ llargs);
// Now untuple the rest of the arguments.
let tuple_type = arg_tys[1];
field_type,
arg_datum,
arg_cleanup_scope,
- DontAutorefArg,
llargs);
}
}
fn_ty: Ty<'tcx>,
llargs: &mut Vec<ValueRef>,
arg_cleanup_scope: cleanup::ScopeId,
- ignore_self: bool,
abi: Abi)
-> Block<'blk, 'tcx> {
debug!("trans_args(abi={})", abi);
arg_exprs,
fn_ty,
llargs,
- arg_cleanup_scope,
- ignore_self)
+ arg_cleanup_scope)
}
let num_formal_args = arg_tys.len();
for (i, arg_expr) in arg_exprs.iter().enumerate() {
- if i == 0 && ignore_self {
- continue;
- }
let arg_ty = if i >= num_formal_args {
assert!(variadic);
common::expr_ty_adjusted(cx, &arg_expr)
let arg_datum = unpack_datum!(bcx, expr::trans(bcx, &arg_expr));
bcx = trans_arg_datum(bcx, arg_ty, arg_datum,
arg_cleanup_scope,
- DontAutorefArg,
llargs);
}
}
arg_exprs,
fn_ty,
llargs,
- arg_cleanup_scope,
- ignore_self)
+ arg_cleanup_scope)
}
- ArgOverloadedOp(lhs, rhs, autoref) => {
+ ArgOverloadedOp(lhs, rhs) => {
assert!(!variadic);
bcx = trans_arg_datum(bcx, arg_tys[0], lhs,
arg_cleanup_scope,
- DontAutorefArg,
llargs);
- if let Some((rhs, rhs_id)) = rhs {
+ if let Some(rhs) = rhs {
assert_eq!(arg_tys.len(), 2);
bcx = trans_arg_datum(bcx, arg_tys[1], rhs,
arg_cleanup_scope,
- if autoref { DoAutorefArg(rhs_id) } else { DontAutorefArg },
llargs);
} else {
assert_eq!(arg_tys.len(), 1);
bcx
}
-#[derive(Copy, Clone)]
-pub enum AutorefArg {
- DontAutorefArg,
- DoAutorefArg(ast::NodeId)
-}
-
pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
formal_arg_ty: Ty<'tcx>,
arg_datum: Datum<'tcx, Expr>,
arg_cleanup_scope: cleanup::ScopeId,
- autoref_arg: AutorefArg,
llargs: &mut Vec<ValueRef>)
-> Block<'blk, 'tcx> {
let _icx = push_ctxt("trans_arg_datum");
debug!(" arg datum: {}", arg_datum.to_string(bcx.ccx()));
- let mut val;
- // FIXME(#3548) use the adjustments table
- match autoref_arg {
- DoAutorefArg(arg_id) => {
- // We will pass argument by reference
- // We want an lvalue, so that we can pass by reference and
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_lvalue_datum(bcx, "arg", arg_id));
- val = arg_datum.val;
- }
- DontAutorefArg if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
- !bcx.fcx.type_needs_drop(arg_datum_ty) => {
- val = arg_datum.val
- }
- DontAutorefArg => {
- // Make this an rvalue, since we are going to be
- // passing ownership.
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
-
- // Now that arg_datum is owned, get it into the appropriate
- // mode (ref vs value).
- let arg_datum = unpack_datum!(
- bcx, arg_datum.to_appropriate_datum(bcx));
-
- // Technically, ownership of val passes to the callee.
- // However, we must cleanup should we panic before the
- // callee is actually invoked.
- val = arg_datum.add_clean(bcx.fcx, arg_cleanup_scope);
- }
- }
+ let mut val = if common::type_is_fat_ptr(bcx.tcx(), arg_datum_ty) &&
+ !bcx.fcx.type_needs_drop(arg_datum_ty) {
+ arg_datum.val
+ } else {
+ // Make this an rvalue, since we are going to be
+ // passing ownership.
+ let arg_datum = unpack_datum!(
+ bcx, arg_datum.to_rvalue_datum(bcx, "arg"));
+
+ // Now that arg_datum is owned, get it into the appropriate
+ // mode (ref vs value).
+ let arg_datum = unpack_datum!(
+ bcx, arg_datum.to_appropriate_datum(bcx));
+
+ // Technically, ownership of val passes to the callee.
+ // However, we must cleanup should we panic before the
+ // callee is actually invoked.
+ arg_datum.add_clean(bcx.fcx, arg_cleanup_scope)
+ };
if type_of::arg_is_indirect(ccx, formal_arg_ty) && formal_arg_ty != arg_datum_ty {
// this could happen due to e.g. subtyping
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};
// 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();
&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();
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);
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
};
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 {
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);
}
{
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
// 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
// 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;
}
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 {
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,
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};
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)
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
.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()
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)
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")
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::*;
use trans::declare;
use trans::glue;
use trans::machine;
-use trans::meth;
use trans::tvec;
use trans::type_of;
use trans::Disr;
use syntax::{ast, codemap};
use syntax::parse::token::InternedString;
-use syntax::ptr::P;
use std::mem;
// Destinations
}
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
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
(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.
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));
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) {
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))
}
}
}
}
}
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)
}
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)
&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.
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);
}
}
-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)
}
}
-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>,
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 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
+ 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);
+
+ // 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`.
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 => {
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.
&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)
}
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;
callee_ty,
&mut llargs,
cleanup::CustomScope(cleanup_scope),
- false,
Abi::RustIntrinsic);
fcx.scopes.borrow_mut().last_mut().unwrap().drop_non_lifetime_clean();
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],
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,
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;
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;
}
}
-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);
-
- Callee { bcx: bcx, data: Fn(datum.val), ty: datum.ty }
+ 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);
+
+ // 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)
}
}
///
/// 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");
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);
/// 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();
Some(mth) => {
trans_fn_ref_with_substs(ccx,
mth.method.def_id,
- ExprId(0),
- param_substs,
+ None,
mth.substs).val
}
None => nullptr
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();
// 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);
// 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;
// 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);
}
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);
// 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 {
(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) {
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(),
(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(),
});
},
(false, _, &None) => {
- bcx.call(callee.immediate(),
+ bcx.call(datum.val,
&llargs[..],
cleanup_bundle.as_ref(),
Some(attrs));
bcx.unreachable();
}
(false, _, &Some((_, target))) => {
- let llret = bcx.call(callee.immediate(),
+ let llret = bcx.call(datum.val,
&llargs[..],
cleanup_bundle.as_ref(),
Some(attrs));
.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,
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};
-> 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) {
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();
expr::trans(bcx, expr).datum.val
})
},
- ConstVal::Function(did) =>
- self.trans_fn_ref(bcx, ty, param_substs, did).immediate()
+ ConstVal::Function(_) => C_nil(ccx)
}
}
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)
}
}
+++ /dev/null
-// 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
- }
-}
mod analyze;
mod block;
mod constant;
-mod did;
mod drop;
mod lvalue;
mod operand;
use trans::asm;
use trans::base;
+use trans::callee::Callee;
use trans::common::{self, BlockAndBuilder, Result};
use trans::debuginfo::DebugLoc;
use trans::declare;
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 => {
}
}
- 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);
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);