diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 9cc94402b165..02dfeb80b928 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -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)) diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index f0ff0380aaa3..8a2f0c0c0930 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -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 } diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index b19771420bd3..e36307feddbf 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -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); } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index fbaf5a1306b8..2ecfa119007b 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -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 } } diff --git a/src/librustc/middle/traits/structural_impls.rs b/src/librustc/middle/traits/structural_impls.rs index 453420e2a54d..903b7c80bafa 100644 --- a/src/librustc/middle/traits/structural_impls.rs +++ b/src/librustc/middle/traits/structural_impls.rs @@ -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>(&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), } } diff --git a/src/librustc/middle/ty/util.rs b/src/librustc/middle/ty/util.rs index b9dd0a6af06a..2b83aaccdc46 100644 --- a/src/librustc/middle/ty/util.rs +++ b/src/librustc/middle/ty/util.rs @@ -602,14 +602,14 @@ impl<'tcx> TyCtxt<'tcx> { #[derive(Debug)] pub struct ImplMethod<'tcx> { pub method: Rc>, - 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 } } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index ce7b1ceb3554..4556611df594 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -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 { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 5d040bcb40ad..8c435b45daef 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -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) - } } diff --git a/src/librustc_mir/build/scope.rs b/src/librustc_mir/build/scope.rs index 6b1b3a33d3d7..3d14ad2374bb 100644 --- a/src/librustc_mir/build/scope.rs +++ b/src/librustc_mir/build/scope.rs @@ -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 } }), diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index ac732828f0ec..cbd6bed81a68 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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 } } } diff --git a/src/librustc_mir/hair/mod.rs b/src/librustc_mir/hair/mod.rs index 707dd972003f..6a22dce7af9d 100644 --- a/src/librustc_mir/hair/mod.rs +++ b/src/librustc_mir/hair/mod.rs @@ -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, diff --git a/src/librustc_trans/trans/asm.rs b/src/librustc_trans/trans/asm.rs index 33370abc3fcc..98e9a1c98ad8 100644 --- a/src/librustc_trans/trans/asm.rs +++ b/src/librustc_trans/trans/asm.rs @@ -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[..]); diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 02f6ff8bab91..5088dabfbe78 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -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, - param_substs: &'tcx Substs<'tcx>) + old_info: Option) -> 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 = diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 7afd09634850..05e5ac808d03 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -14,7 +14,6 @@ //! 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::*; @@ -22,7 +21,6 @@ use arena::TypedArena; 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; @@ -32,14 +30,13 @@ use trans::adt; 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; @@ -52,177 +49,148 @@ use trans::type_::Type; 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); - } - _ => {} - } - - // 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)); - } - } - } - - fn fn_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, datum: Datum<'tcx, Rvalue>) - -> Callee<'blk, 'tcx> { +impl<'tcx> Callee<'tcx> { + /// Function pointer. + pub fn ptr(datum: Datum<'tcx, Rvalue>) -> Callee<'tcx> { Callee { - bcx: bcx, data: Fn(datum.val), ty: datum.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, + /// 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) + } + + /// 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) + } + + /// 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 + }; + } + 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::Struct(..) => { - Callee { - bcx: bcx, - data: NamedTupleConstructor(Disr(0)), - ty: expr_ty + _ => {} + } + 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) + -> 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); } - } - 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)); - } + _ => unreachable!("expected fn item type, found {}", self.ty) + }, + Intrinsic(..) => unreachable!("intrinsic {} getting reified", self.ty) } } } @@ -241,7 +209,17 @@ pub fn trans_fn_ref<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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 @@ -290,29 +268,24 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( // 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 { @@ -321,11 +294,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( 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); // @@ -350,11 +319,18 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( 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); @@ -363,13 +339,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( 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); @@ -388,30 +362,25 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( /// - `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>, + 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. @@ -446,43 +415,45 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // 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 @@ -508,92 +479,36 @@ pub fn trans_fn_ref_with_substs<'a, 'tcx>( // 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, 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) - -> 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) + -> 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 @@ -603,10 +518,6 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, // 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) => { @@ -614,16 +525,10 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, 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()); @@ -635,14 +540,15 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } }; + 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, @@ -651,7 +557,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, dest.unwrap(), debug_loc); } - }; + _ => {} + } // Intrinsics should not become actual functions. // We trans them in place in `trans_intrinsic_call` @@ -691,6 +598,8 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, 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 @@ -714,10 +623,7 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } } - // 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, @@ -725,16 +631,25 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, 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; @@ -757,16 +672,17 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, 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(); @@ -803,23 +719,22 @@ pub fn trans_call_inner<'a, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } 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]), - // 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>), - // 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>), } @@ -828,8 +743,7 @@ fn trans_args_under_call_abi<'blk, 'tcx>( arg_exprs: &[P], fn_ty: Ty<'tcx>, llargs: &mut Vec, - 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()); @@ -837,15 +751,12 @@ fn trans_args_under_call_abi<'blk, 'tcx>( 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]; @@ -873,7 +784,6 @@ fn trans_args_under_call_abi<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -891,23 +801,19 @@ fn trans_overloaded_call_args<'blk, 'tcx>( arg_exprs: Vec<&hir::Expr>, fn_ty: Ty<'tcx>, llargs: &mut Vec, - 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]; @@ -920,7 +826,6 @@ fn trans_overloaded_call_args<'blk, 'tcx>( field_type, arg_datum, arg_cleanup_scope, - DontAutorefArg, llargs); } } @@ -938,7 +843,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, fn_ty: Ty<'tcx>, llargs: &mut Vec, arg_cleanup_scope: cleanup::ScopeId, - ignore_self: bool, abi: Abi) -> Block<'blk, 'tcx> { debug!("trans_args(abi={})", abi); @@ -963,15 +867,11 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, 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) @@ -982,7 +882,6 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, 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); } } @@ -991,22 +890,19 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, 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); @@ -1020,17 +916,10 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, 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) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_arg_datum"); @@ -1044,37 +933,25 @@ pub fn trans_arg_datum<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, 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")); + 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)); + // 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); - } - } + // 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 diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs index 023ab02bc38d..95ca250e8444 100644 --- a/src/librustc_trans/trans/closure.rs +++ b/src/librustc_trans/trans/closure.rs @@ -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); diff --git a/src/librustc_trans/trans/collector.rs b/src/librustc_trans/trans/collector.rs index 4bd150605c9e..abfd127f3886 100644 --- a/src/librustc_trans/trans/collector.rs +++ b/src/librustc_trans/trans/collector.rs @@ -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; } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index f489f1f62ac6..34ef4f4acec5 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -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, diff --git a/src/librustc_trans/trans/consts.rs b/src/librustc_trans/trans/consts.rs index bec73c7cedc0..6c47cab64eff 100644 --- a/src/librustc_trans/trans/consts.rs +++ b/src/librustc_trans/trans/consts.rs @@ -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") diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 00ce0f810949..ae03f58bce0c 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -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, - 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], - dest: Option) - -> 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` 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. diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index 0b2ab58a835a..d5f8cff49560 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -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) } diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs index 70c8681dbc1c..dff6652e5419 100644 --- a/src/librustc_trans/trans/intrinsic.rs +++ b/src/librustc_trans/trans/intrinsic.rs @@ -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]>, 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, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 4b18ff05b188..78b86dafa18a 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -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 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) 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) 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` from a value of type `Foo`, 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>> { 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; diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index db93b77c47d9..50283c0959c3 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,73 +9,27 @@ // except according to those terms. use llvm::{BasicBlockRef, ValueRef, OperandBundleDef}; -use rustc::middle::ty::{self, Ty}; +use rustc::middle::ty; use rustc::mir::repr as mir; use syntax::abi::Abi; use trans::adt; use trans::attributes; use trans::base; use trans::build; +use trans::callee::{Callee, Fn, Virtual}; use trans::common::{self, Block, BlockAndBuilder}; use trans::debuginfo::DebugLoc; use trans::Disr; use trans::foreign; +use trans::meth; use trans::type_of; use trans::glue; use trans::type_::Type; use super::{MirContext, drop}; use super::operand::OperandValue::{FatPtr, Immediate, Ref}; -use super::operand::OperandRef; - -#[derive(PartialEq, Eq)] -enum AbiStyle { - Foreign, - RustCall, - Rust -} impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { - fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle { - match fn_ty.sty { - ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => { - // We do not translate intrinsics here (they shouldn’t be functions) - assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic); - - match f.abi { - Abi::Rust => AbiStyle::Rust, - Abi::RustCall => AbiStyle::RustCall, - _ => AbiStyle::Foreign - } - } - _ => unreachable!() - } - } - - fn arg_operands(&mut self, - bcx: &BlockAndBuilder<'bcx, 'tcx>, - abi_style: AbiStyle, - args: &[mir::Operand<'tcx>]) - -> Vec> - { - match abi_style { - AbiStyle::Foreign | AbiStyle::Rust => { - args.iter().map(|arg| self.trans_operand(bcx, arg)).collect() - } - AbiStyle::RustCall => match args.split_last() { - None => vec![], - Some((tup, self_ty)) => { - // we can reorder safely because of MIR - let untupled_args = self.trans_operand_untupled(bcx, tup); - self_ty - .iter().map(|arg| self.trans_operand(bcx, arg)) - .chain(untupled_args.into_iter()) - .collect() - } - } - } - } - pub fn trans_block(&mut self, bb: mir::BasicBlock) { debug!("trans_block({:?})", bb); @@ -198,9 +152,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } mir::Terminator::Call { ref func, ref args, ref destination, ref cleanup } => { - // Create the callee. This will always be a fn ptr and hence a kind of scalar. + // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.trans_operand(&bcx, func); - let attrs = attributes::from_fn_type(bcx.ccx(), callee.ty); let debugloc = DebugLoc::None; // The arguments we'll be passing. Plus one to account for outptr, if used. let mut llargs = Vec::with_capacity(args.len() + 1); @@ -208,9 +161,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // filled when `is_foreign` is `true` and foreign calls are minority of the cases. let mut arg_tys = Vec::new(); + let (callee, fty) = match callee.ty.sty { + ty::TyFnDef(def_id, substs, f) => { + (Callee::def(bcx.ccx(), def_id, substs, callee.ty), f) + } + ty::TyFnPtr(f) => { + (Callee { + data: Fn(callee.immediate()), + ty: callee.ty + }, f) + } + _ => unreachable!("{} is not callable", callee.ty) + }; + + // We do not translate intrinsics here (they shouldn’t be functions) + assert!(fty.abi != Abi::RustIntrinsic && fty.abi != Abi::PlatformIntrinsic); // Foreign-ABI functions are translated differently - let abi_style = self.abi_style(callee.ty); - let is_foreign = abi_style == AbiStyle::Foreign; + let is_foreign = fty.abi != Abi::Rust && fty.abi != Abi::RustCall; // Prepare the return value destination let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination { @@ -226,19 +193,58 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (None, false) }; - // Process the rest of the args. - for operand in self.arg_operands(&bcx, abi_style, args) { - match operand.val { - Ref(llval) | Immediate(llval) => llargs.push(llval), - FatPtr(b, e) => { - llargs.push(b); - llargs.push(e); + // Split the rust-call tupled arguments off. + let (args, rest) = if fty.abi == Abi::RustCall && !args.is_empty() { + let (tup, args) = args.split_last().unwrap(); + // we can reorder safely because of MIR + (args, self.trans_operand_untupled(&bcx, tup)) + } else { + (&args[..], vec![]) + }; + + let datum = { + let mut arg_ops = args.iter().map(|arg| { + self.trans_operand(&bcx, arg) + }).chain(rest.into_iter()); + + // Get the actual pointer we can call. + // This can involve vtable accesses or reification. + let datum = if let Virtual(idx) = callee.data { + assert!(!is_foreign); + + // Grab the first argument which is a trait object. + let vtable = match arg_ops.next().unwrap().val { + FatPtr(data, vtable) => { + llargs.push(data); + vtable + } + _ => unreachable!("expected FatPtr for Virtual call") + }; + + bcx.with_block(|bcx| { + meth::get_virtual_method(bcx, vtable, idx, callee.ty) + }) + } else { + callee.reify(bcx.ccx()) + }; + + // Process the rest of the args. + for operand in arg_ops { + match operand.val { + Ref(llval) | Immediate(llval) => llargs.push(llval), + FatPtr(b, e) => { + llargs.push(b); + llargs.push(e); + } + } + if is_foreign { + arg_tys.push(operand.ty); } } - if is_foreign { - arg_tys.push(operand.ty); - } - } + + datum + }; + let attrs = attributes::from_fn_type(bcx.ccx(), datum.ty); // Many different ways to call a function handled here match (is_foreign, cleanup, destination) { @@ -247,7 +253,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); let unreachable_blk = self.unreachable_block(); - bcx.invoke(callee.immediate(), + bcx.invoke(datum.val, &llargs[..], unreachable_blk.llbb, landingpad.llbb(), @@ -260,7 +266,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { (false, &Some(cleanup), &Some((_, success))) => { let cleanup = self.bcx(cleanup); let landingpad = self.make_landing_pad(cleanup); - let invokeret = bcx.invoke(callee.immediate(), + let invokeret = bcx.invoke(datum.val, &llargs[..], self.llblock(success), landingpad.llbb(), @@ -283,7 +289,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { }); }, (false, _, &None) => { - bcx.call(callee.immediate(), + bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -291,7 +297,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { bcx.unreachable(); } (false, _, &Some((_, target))) => { - let llret = bcx.call(callee.immediate(), + let llret = bcx.call(datum.val, &llargs[..], cleanup_bundle.as_ref(), Some(attrs)); @@ -313,8 +319,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { .expect("return destination is not set"); bcx = bcx.map_block(|bcx| { foreign::trans_native_call(bcx, - callee.ty, - callee.immediate(), + datum.ty, + datum.val, dest.llval, &llargs[..], arg_tys, diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs index 7f03069385fe..a0615a6cf5b1 100644 --- a/src/librustc_trans/trans/mir/constant.rs +++ b/src/librustc_trans/trans/mir/constant.rs @@ -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) } } diff --git a/src/librustc_trans/trans/mir/did.rs b/src/librustc_trans/trans/mir/did.rs deleted file mode 100644 index 5b6af4757197..000000000000 --- a/src/librustc_trans/trans/mir/did.rs +++ /dev/null @@ -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 or the MIT license -// , 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 - } -} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 40dc22e31aa6..4ad2e035945f 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -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; diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 541df43b49b9..ce10ed425f63 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -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 => { diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs index 8b4ed9b87980..b78bf9bfc3fb 100644 --- a/src/librustc_trans/trans/type_of.rs +++ b/src/librustc_trans/trans/type_of.rs @@ -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);