diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index b8b2395dde1..67e1735d9a3 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -19,8 +19,7 @@ pub use self::CalleeData::*; pub use self::CallArgs::*; use arena::TypedArena; -use back::abi; -use back::link; +use back::{abi,link}; use session; use llvm::{ValueRef, get_param}; use llvm; @@ -357,153 +356,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>( llfn } -/// Translates the adapter that deconstructs a `Box` object into -/// `Trait` so that a by-value self method can be called. -pub fn trans_unboxing_shim<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - llshimmedfn: ValueRef, - fty: &ty::BareFnTy<'tcx>, - method_id: ast::DefId, - substs: &subst::Substs<'tcx>) - -> ValueRef { - let _icx = push_ctxt("trans_unboxing_shim"); - let ccx = bcx.ccx(); - let tcx = bcx.tcx(); - - let fty = fty.subst(tcx, substs); - - // Transform the self type to `Box`. - let self_type = fty.sig.inputs[0]; - let boxed_self_type = ty::mk_uniq(tcx, self_type); - let boxed_function_type = ty::FnSig { - inputs: fty.sig.inputs.iter().enumerate().map(|(i, typ)| { - if i == 0 { - boxed_self_type - } else { - *typ - } - }).collect(), - output: fty.sig.output, - variadic: false, - }; - let boxed_function_type = ty::BareFnTy { - fn_style: fty.fn_style, - abi: fty.abi, - sig: boxed_function_type, - }; - let boxed_function_type = ty::mk_bare_fn(tcx, boxed_function_type); - let function_type = match fty.abi { - synabi::RustCall => { - // We're passing through to a RustCall ABI function, but - // because the shim will already perform untupling, we - // need to pretend the shimmed function does not use - // RustCall so the untupled arguments can be passed - // through verbatim. This is kind of ugly. - let fake_ty = ty::FnSig { - inputs: type_of::untuple_arguments_if_necessary(ccx, - fty.sig.inputs.as_slice(), - fty.abi), - output: fty.sig.output, - variadic: false, - }; - let fake_ty = ty::BareFnTy { - fn_style: fty.fn_style, - abi: synabi::Rust, - sig: fake_ty, - }; - ty::mk_bare_fn(tcx, fake_ty) - } - _ => { - ty::mk_bare_fn(tcx, fty) - } - }; - - let function_name = ty::with_path(tcx, method_id, |path| { - link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim") - }); - let llfn = decl_internal_rust_fn(ccx, - boxed_function_type, - function_name.as_slice()); - - let block_arena = TypedArena::new(); - let empty_param_substs = Substs::trans_empty(); - let return_type = ty::ty_fn_ret(boxed_function_type); - let fcx = new_fn_ctxt(ccx, - llfn, - ast::DUMMY_NODE_ID, - false, - return_type, - &empty_param_substs, - None, - &block_arena); - let mut bcx = init_function(&fcx, false, return_type); - - // Create the substituted versions of the self type. - let arg_scope = fcx.push_custom_cleanup_scope(); - let arg_scope_id = cleanup::CustomScope(arg_scope); - let boxed_self_type = ty::ty_fn_args(boxed_function_type)[0]; - let arg_types = ty::ty_fn_args(function_type); - let self_type = arg_types[0]; - let boxed_self_kind = arg_kind(&fcx, boxed_self_type); - - // Create a datum for self. - let llboxedself = get_param(fcx.llfn, fcx.arg_pos(0) as u32); - let llboxedself = Datum::new(llboxedself, - boxed_self_type, - boxed_self_kind); - let boxed_self = - unpack_datum!(bcx, - llboxedself.to_lvalue_datum_in_scope(bcx, - "boxedself", - arg_scope_id)); - - // This `Load` is needed because lvalue data are always by-ref. - let llboxedself = Load(bcx, boxed_self.val); - - let llself = if type_is_immediate(ccx, self_type) { - let llboxedself = Load(bcx, llboxedself); - immediate_rvalue(llboxedself, self_type) - } else { - let llself = rvalue_scratch_datum(bcx, self_type, "self"); - memcpy_ty(bcx, llself.val, llboxedself, self_type); - llself - }; - - // Make sure we don't free the box twice! - boxed_self.kind.post_store(bcx, boxed_self.val, boxed_self_type); - - // Schedule a cleanup to free the box. - fcx.schedule_free_value(arg_scope_id, - llboxedself, - cleanup::HeapExchange, - self_type); - - // Now call the function. - let mut llshimmedargs = vec!(llself.val); - for i in range(1, arg_types.len()) { - llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32)); - } - assert!(!fcx.needs_ret_allocas); - let dest = fcx.llretslotptr.get().map(|_| - expr::SaveIn(fcx.get_ret_slot(bcx, return_type, "ret_slot")) - ); - bcx = trans_call_inner(bcx, - None, - function_type, - |bcx, _| { - Callee { - bcx: bcx, - data: Fn(llshimmedfn), - } - }, - ArgVals(llshimmedargs.as_slice()), - dest).bcx; - - bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope); - finish_fn(&fcx, bcx, return_type); - - llfn -} - /// Translates a reference to a fn/method item, monomorphizing and /// inlining as it goes. /// diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index 94ff526debd..9a2bc38acdf 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -550,68 +550,12 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, emit_vtable_methods(bcx, id, substs).into_iter() } traits::VtableUnboxedClosure(closure_def_id, substs) => { - // Look up closure type - let self_ty = ty::node_id_to_type(bcx.tcx(), closure_def_id.node); - // Apply substitutions from closure param environment. - // The substitutions should have no type parameters - // remaining after passing through fulfill_obligation - let self_ty = self_ty.subst(bcx.tcx(), &substs); - - let mut llfn = trans_fn_ref_with_substs( + let llfn = trans_fn_ref_with_substs( bcx, closure_def_id, ExprId(0), substs.clone()); - { - let unboxed_closures = bcx.tcx() - .unboxed_closures - .borrow(); - let closure_info = - unboxed_closures.get(&closure_def_id) - .expect("get_vtable(): didn't find \ - unboxed closure"); - if closure_info.kind == ty::FnOnceUnboxedClosureKind { - // Untuple the arguments and create an unboxing shim. - let (new_inputs, new_output) = match self_ty.sty { - ty::ty_unboxed_closure(_, _, ref substs) => { - let mut new_inputs = vec![self_ty.clone()]; - match closure_info.closure_type.sig.inputs[0].sty { - ty::ty_tup(ref elements) => { - for element in elements.iter() { - new_inputs.push(element.subst(bcx.tcx(), substs)); - } - } - _ => { - bcx.tcx().sess.bug("get_vtable(): closure \ - type wasn't a tuple") - } - } - (new_inputs, - closure_info.closure_type.sig.output.subst(bcx.tcx(), substs)) - }, - _ => bcx.tcx().sess.bug("get_vtable(): def wasn't an unboxed closure") - }; - - let closure_type = ty::BareFnTy { - fn_style: closure_info.closure_type.fn_style, - abi: Rust, - sig: ty::FnSig { - inputs: new_inputs, - output: new_output, - variadic: false, - }, - }; - debug!("get_vtable(): closure type is {}", - closure_type.repr(bcx.tcx())); - llfn = trans_unboxing_shim(bcx, - llfn, - &closure_type, - closure_def_id, - &substs); - } - } - (vec!(llfn)).into_iter() } traits::VtableFnPointer(bare_fn_ty) => { @@ -701,18 +645,15 @@ fn emit_vtable_methods<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, token::get_name(name)); Some(C_null(Type::nil(ccx).ptr_to())).into_iter() } else { - let mut fn_ref = trans_fn_ref_with_substs( + let fn_ref = trans_fn_ref_with_substs( bcx, m_id, ExprId(0), substs.clone()); - if m.explicit_self == ty::ByValueExplicitSelfCategory { - fn_ref = trans_unboxing_shim(bcx, - fn_ref, - &m.fty, - m_id, - &substs); - } + + // currently, at least, by-value self is not object safe + assert!(m.explicit_self != ty::ByValueExplicitSelfCategory); + Some(fn_ref).into_iter() } } diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index adcfc491dcc..d3879e49034 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -315,23 +315,6 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { get_method_index(tcx, &*new_trait_ref, trait_ref.clone(), method_num); - // FIXME Hacky. By-value `self` methods in objects ought to be - // just a special case of passing ownership of a DST value - // as a parameter. *But* we currently hack them in and tie them to - // the particulars of the `Box` type. So basically for a `fn foo(self,...)` - // method invoked on an object, we don't want the receiver type to be - // `TheTrait`, but rather `Box`. Yuck. - let mut m = m; - match m.explicit_self { - ty::ByValueExplicitSelfCategory => { - let mut n = (*m).clone(); - let self_ty = n.fty.sig.inputs[0]; - n.fty.sig.inputs[0] = ty::mk_uniq(tcx, self_ty); - m = Rc::new(n); - } - _ => { } - } - let xform_self_ty = this.xform_self_ty(&m, &new_trait_ref.substs); diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs index 7c5ceb6f510..415a3d53fb2 100644 --- a/src/librustc_typeck/check/vtable.rs +++ b/src/librustc_typeck/check/vtable.rs @@ -149,14 +149,6 @@ pub fn check_object_safety<'tcx>(tcx: &ty::ctxt<'tcx>, fn check_object_safety_inner<'tcx>(tcx: &ty::ctxt<'tcx>, object_trait: &ty::TraitRef<'tcx>, span: Span) { - // Skip the fn_once lang item trait since only the compiler should call - // `call_once` which is the method which takes self by value. What could go - // wrong? - match tcx.lang_items.fn_once_trait() { - Some(def_id) if def_id == object_trait.def_id => return, - _ => {} - } - let trait_items = ty::trait_items(tcx, object_trait.def_id); let mut errors = Vec::new(); diff --git a/src/test/run-pass/issue-16739.rs b/src/test/run-pass/issue-16739.rs index 6dcdc1d1086..552ce565f6b 100644 --- a/src/test/run-pass/issue-16739.rs +++ b/src/test/run-pass/issue-16739.rs @@ -11,29 +11,29 @@ #![feature(unboxed_closures)] // Test that unboxing shim for calling rust-call ABI methods through a -// trait box works and does not cause an ICE +// trait box works and does not cause an ICE. struct Foo { foo: uint } -impl FnOnce<(), uint> for Foo { - extern "rust-call" fn call_once(self, _: ()) -> uint { self.foo } +impl FnMut<(), uint> for Foo { + extern "rust-call" fn call_mut(&mut self, _: ()) -> uint { self.foo } } -impl FnOnce<(uint,), uint> for Foo { - extern "rust-call" fn call_once(self, (x,): (uint,)) -> uint { self.foo + x } +impl FnMut<(uint,), uint> for Foo { + extern "rust-call" fn call_mut(&mut self, (x,): (uint,)) -> uint { self.foo + x } } -impl FnOnce<(uint, uint), uint> for Foo { - extern "rust-call" fn call_once(self, (x, y): (uint, uint)) -> uint { self.foo + x + y } +impl FnMut<(uint, uint), uint> for Foo { + extern "rust-call" fn call_mut(&mut self, (x, y): (uint, uint)) -> uint { self.foo + x + y } } fn main() { - let f = box Foo { foo: 42 } as Box>; - assert_eq!(f.call_once(()), 42); + let mut f = box Foo { foo: 42 } as Box>; + assert_eq!(f.call_mut(()), 42); - let f = box Foo { foo: 40 } as Box>; - assert_eq!(f.call_once((2,)), 42); + let mut f = box Foo { foo: 40 } as Box>; + assert_eq!(f.call_mut((2,)), 42); - let f = box Foo { foo: 40 } as Box>; - assert_eq!(f.call_once((1, 1)), 42); + let mut f = box Foo { foo: 40 } as Box>; + assert_eq!(f.call_mut((1, 1)), 42); } diff --git a/src/test/run-pass/issue-18883.rs b/src/test/run-pass/issue-18883.rs deleted file mode 100644 index c54844f570b..00000000000 --- a/src/test/run-pass/issue-18883.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 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. - -// Test that we don't ICE due to encountering unsubstituted type -// parameters when untupling FnOnce parameters during translation of -// an unboxing shim. - -#![feature(unboxed_closures)] - -fn main() { - let _: Box> = box move |&mut:| {}; -} diff --git a/src/test/run-pass/unboxed-closures-monomorphization.rs b/src/test/run-pass/unboxed-closures-monomorphization.rs index cd97fd96fa3..dfc234e87cd 100644 --- a/src/test/run-pass/unboxed-closures-monomorphization.rs +++ b/src/test/run-pass/unboxed-closures-monomorphization.rs @@ -14,26 +14,26 @@ #![feature(unboxed_closures)] fn main(){ - fn bar<'a, T:'a> (t: T) -> Box + 'a> { - box move |:| t + fn bar<'a, T:Clone+'a> (t: T) -> Box + 'a> { + box move |&mut:| t.clone() } - let f = bar(42u); - assert_eq!(f.call_once(()), 42); + let mut f = bar(42u); + assert_eq!(f.call_mut(()), 42); - let f = bar("forty-two"); - assert_eq!(f.call_once(()), "forty-two"); + let mut f = bar("forty-two"); + assert_eq!(f.call_mut(()), "forty-two"); let x = 42u; - let f = bar(&x); - assert_eq!(f.call_once(()), &x); + let mut f = bar(&x); + assert_eq!(f.call_mut(()), &x); - #[deriving(Show, PartialEq)] + #[deriving(Clone, Show, PartialEq)] struct Foo(uint, &'static str); impl Copy for Foo {} let x = Foo(42, "forty-two"); - let f = bar(x); - assert_eq!(f.call_once(()), x); + let mut f = bar(x); + assert_eq!(f.call_mut(()), x); } diff --git a/src/test/run-pass/unboxed-closures-prelude.rs b/src/test/run-pass/unboxed-closures-prelude.rs index 6f672f2f282..e31ef169e16 100644 --- a/src/test/run-pass/unboxed-closures-prelude.rs +++ b/src/test/run-pass/unboxed-closures-prelude.rs @@ -13,7 +13,16 @@ #![feature(unboxed_closures)] fn main() { - let task: Box int> = box |: x| x; - task.call_once((0i, )); + let task: Box int> = box |&: x| x; + task.call((0i, )); + + let mut task: Box int> = box |&mut: x| x; + task.call_mut((0i, )); + + call(|:x| x, 22); +} + +fn call int>(f: F, x: int) -> int { + f.call_once((x,)) } diff --git a/src/test/run-pass/unboxed-closures-unboxing-shim.rs b/src/test/run-pass/unboxed-closures-unboxing-shim.rs deleted file mode 100644 index c41aeaa673f..00000000000 --- a/src/test/run-pass/unboxed-closures-unboxing-shim.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2014 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. - -#![feature(unboxed_closures)] - -use std::ops::FnOnce; - -fn main() { - let task: Box int> = box |: x| x; - assert!(task.call_once((1234i,)) == 1234i); -} -