From 39221a013fdbfcc05d44fc7a62650f62c7b833e9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 1 Dec 2014 09:23:40 -0500 Subject: [PATCH] Implement the `Fn` trait for bare fn pointers in the compiler rather than doing it using hard-coded impls. This means that it works also for more complex fn types involving bound regions. Fixes #19126. --- src/libcore/ops.rs | 88 ++++++----- src/librustc/middle/traits/mod.rs | 18 ++- src/librustc/middle/traits/select.rs | 143 +++++++++++++++--- src/librustc/middle/traits/util.rs | 4 + src/librustc/middle/ty_fold.rs | 3 + src/librustc_trans/trans/base.rs | 8 +- src/librustc_trans/trans/callee.rs | 106 +++++++++++++ src/librustc_trans/trans/meth.rs | 16 +- src/test/compile-fail/issue-15965.rs | 4 +- src/test/compile-fail/issue-18532.rs | 2 - .../unboxed-closures-unsafe-extern-fn.rs | 28 ++++ .../unboxed-closures-wrong-abi.rs | 28 ++++ ...boxed-closures-wrong-arg-type-extern-fn.rs | 29 ++++ .../run-pass/unboxed-closures-extern-fn-hr.rs | 45 ++++++ .../run-pass/unboxed-closures-extern-fn.rs | 2 +- 15 files changed, 446 insertions(+), 78 deletions(-) create mode 100644 src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs create mode 100644 src/test/compile-fail/unboxed-closures-wrong-abi.rs create mode 100644 src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs create mode 100644 src/test/run-pass/unboxed-closures-extern-fn-hr.rs diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index d85481098e4..4f4ec486797 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -833,48 +833,52 @@ impl FnOnce for F } } +#[cfg(stage0)] +mod fn_impls { + use super::Fn; -impl Fn<(),Result> for extern "Rust" fn() -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, _args: ()) -> Result { - (*self)() - } -} - -impl Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, args: (A0,)) -> Result { - let (a0,) = args; - (*self)(a0) - } -} - -macro_rules! def_fn( - ($($args:ident)*) => ( - impl - Fn<($($args,)*),Result> - for extern "Rust" fn($($args: $args,)*) -> Result { - #[allow(non_snake_case)] - extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result { - let ($($args,)*) = args; - (*self)($($args,)*) - } + impl Fn<(),Result> for extern "Rust" fn() -> Result { + #[allow(non_snake_case)] + extern "rust-call" fn call(&self, _args: ()) -> Result { + (*self)() } - ) -) + } -def_fn!(A0 A1) -def_fn!(A0 A1 A2) -def_fn!(A0 A1 A2 A3) -def_fn!(A0 A1 A2 A3 A4) -def_fn!(A0 A1 A2 A3 A4 A5) -def_fn!(A0 A1 A2 A3 A4 A5 A6) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) -def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) + impl Fn<(A0,),Result> for extern "Rust" fn(A0) -> Result { + #[allow(non_snake_case)] + extern "rust-call" fn call(&self, args: (A0,)) -> Result { + let (a0,) = args; + (*self)(a0) + } + } + + macro_rules! def_fn( + ($($args:ident)*) => ( + impl + Fn<($($args,)*),Result> + for extern "Rust" fn($($args: $args,)*) -> Result { + #[allow(non_snake_case)] + extern "rust-call" fn call(&self, args: ($($args,)*)) -> Result { + let ($($args,)*) = args; + (*self)($($args,)*) + } + } + ) + ) + + def_fn!(A0 A1) + def_fn!(A0 A1 A2) + def_fn!(A0 A1 A2 A3) + def_fn!(A0 A1 A2 A3 A4) + def_fn!(A0 A1 A2 A3 A4 A5) + def_fn!(A0 A1 A2 A3 A4 A5 A6) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) + def_fn!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) +} diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index 34278c25cfa..b8d915c06e0 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -167,18 +167,21 @@ pub enum Vtable<'tcx, N> { /// Vtable identifying a particular impl. VtableImpl(VtableImplData<'tcx, N>), - /// Vtable automatically generated for an unboxed closure. The def - /// ID is the ID of the closure expression. This is a `VtableImpl` - /// in spirit, but the impl is generated by the compiler and does - /// not appear in the source. - VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>), - /// Successful resolution to an obligation provided by the caller /// for some type parameter. VtableParam(VtableParamData<'tcx>), /// Successful resolution for a builtin trait. VtableBuiltin(VtableBuiltinData), + + /// Vtable automatically generated for an unboxed closure. The def + /// ID is the ID of the closure expression. This is a `VtableImpl` + /// in spirit, but the impl is generated by the compiler and does + /// not appear in the source. + VtableUnboxedClosure(ast::DefId, subst::Substs<'tcx>), + + /// Same as above, but for a fn pointer type with the given signature. + VtableFnPointer(ty::Ty<'tcx>), } /// Identifies a particular impl in the source, along with a set of @@ -322,6 +325,7 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn iter_nested(&self) -> Items { match *self { VtableImpl(ref i) => i.iter_nested(), + VtableFnPointer(..) => (&[]).iter(), VtableUnboxedClosure(..) => (&[]).iter(), VtableParam(_) => (&[]).iter(), VtableBuiltin(ref i) => i.iter_nested(), @@ -331,6 +335,7 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn map_nested(&self, op: |&N| -> M) -> Vtable<'tcx, M> { match *self { VtableImpl(ref i) => VtableImpl(i.map_nested(op)), + VtableFnPointer(ref sig) => VtableFnPointer((*sig).clone()), VtableUnboxedClosure(d, ref s) => VtableUnboxedClosure(d, s.clone()), VtableParam(ref p) => VtableParam((*p).clone()), VtableBuiltin(ref i) => VtableBuiltin(i.map_nested(op)), @@ -340,6 +345,7 @@ impl<'tcx, N> Vtable<'tcx, N> { pub fn map_move_nested(self, op: |N| -> M) -> Vtable<'tcx, M> { match self { VtableImpl(i) => VtableImpl(i.map_move_nested(op)), + VtableFnPointer(sig) => VtableFnPointer(sig), VtableUnboxedClosure(d, s) => VtableUnboxedClosure(d, s), VtableParam(p) => VtableParam(p), VtableBuiltin(i) => VtableBuiltin(i.map_move_nested(op)), diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 71a183b475c..9dbcf455f4b 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -22,7 +22,7 @@ use super::{SelectionError, Unimplemented, Overflow, OutputTypeParameterMismatch}; use super::{Selection}; use super::{SelectionResult}; -use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure}; +use super::{VtableBuiltin, VtableImpl, VtableParam, VtableUnboxedClosure, VtableFnPointer}; use super::{VtableImplData, VtableParamData, VtableBuiltinData}; use super::{util}; @@ -36,7 +36,7 @@ use middle::ty_fold::TypeFoldable; use std::cell::RefCell; use std::collections::hash_map::HashMap; use std::rc::Rc; -use syntax::ast; +use syntax::{abi, ast}; use util::common::ErrorReported; use util::ppaux::Repr; @@ -131,7 +131,15 @@ enum Candidate<'tcx> { BuiltinCandidate(ty::BuiltinBound), ParamCandidate(VtableParamData<'tcx>), ImplCandidate(ast::DefId), + + /// Implementation of a `Fn`-family trait by one of the + /// anonymous types generated for a `||` expression. UnboxedClosureCandidate(/* closure */ ast::DefId, Substs<'tcx>), + + /// Implementation of a `Fn`-family trait by one of the anonymous + /// types generated for a fn pointer type (e.g., `fn(int)->int`) + FnPointerCandidate, + ErrorCandidate, } @@ -917,7 +925,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => { // For the time being, we ignore user-defined impls for builtin-bounds. // (And unboxed candidates only apply to the Fn/FnMut/etc traits.) - try!(self.assemble_unboxed_candidates(obligation, &mut candidates)); + try!(self.assemble_unboxed_closure_candidates(obligation, &mut candidates)); + try!(self.assemble_fn_pointer_candidates(obligation, &mut candidates)); try!(self.assemble_candidates_from_impls(obligation, &mut candidates)); } } @@ -968,20 +977,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Note: the type parameters on an unboxed closure candidate are modeled as *output* type /// parameters and hence do not affect whether this trait is a match or not. They will be /// unified during the confirmation step. - fn assemble_unboxed_candidates(&mut self, - obligation: &Obligation<'tcx>, - candidates: &mut CandidateSet<'tcx>) - -> Result<(),SelectionError<'tcx>> + fn assemble_unboxed_closure_candidates(&mut self, + obligation: &Obligation<'tcx>, + candidates: &mut CandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> { - let tcx = self.tcx(); - let kind = if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_trait() { - ty::FnUnboxedClosureKind - } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_mut_trait() { - ty::FnMutUnboxedClosureKind - } else if Some(obligation.trait_ref.def_id) == tcx.lang_items.fn_once_trait() { - ty::FnOnceUnboxedClosureKind - } else { - return Ok(()); // not a fn trait, ignore + let kind = match self.fn_family_trait_kind(obligation.trait_ref.def_id) { + Some(k) => k, + None => { return Ok(()); } }; let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); @@ -1015,6 +1018,42 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(()) } + /// Implement one of the `Fn()` family for a fn pointer. + fn assemble_fn_pointer_candidates(&mut self, + obligation: &Obligation<'tcx>, + candidates: &mut CandidateSet<'tcx>) + -> Result<(),SelectionError<'tcx>> + { + // We provide a `Fn` impl for fn pointers (but not e.g. `FnMut`). + if Some(obligation.trait_ref.def_id) != self.tcx().lang_items.fn_trait() { + return Ok(()); + } + + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + match self_ty.sty { + ty::ty_infer(..) => { + candidates.ambiguous = true; // could wind up being a fn() type + } + + // provide an impl, but only for suitable `fn` pointers + ty::ty_bare_fn(ty::BareFnTy { + fn_style: ast::NormalFn, + abi: abi::Rust, + sig: ty::FnSig { + inputs: _, + output: ty::FnConverging(_), + variadic: false + } + }) => { + candidates.vec.push(FnPointerCandidate); + } + + _ => { } + } + + Ok(()) + } + /// Search for impls that might apply to `obligation`. fn assemble_candidates_from_impls(&mut self, obligation: &Obligation<'tcx>, @@ -1551,6 +1590,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, &substs)); Ok(VtableUnboxedClosure(closure_def_id, substs)) } + + FnPointerCandidate => { + let fn_type = + try!(self.confirm_fn_pointer_candidate(obligation)); + Ok(VtableFnPointer(fn_type)) + } } } @@ -1646,6 +1691,51 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested: impl_obligations } } + fn confirm_fn_pointer_candidate(&mut self, + obligation: &Obligation<'tcx>) + -> Result,SelectionError<'tcx>> + { + debug!("confirm_fn_pointer_candidate({})", + obligation.repr(self.tcx())); + + let self_ty = self.infcx.shallow_resolve(obligation.self_ty()); + let sig = match self_ty.sty { + ty::ty_bare_fn(ty::BareFnTy { + fn_style: ast::NormalFn, + abi: abi::Rust, + ref sig + }) => { + (*sig).clone() + } + _ => { + self.tcx().sess.span_bug( + obligation.cause.span, + format!("Fn pointer candidate for inappropriate self type: {}", + self_ty.repr(self.tcx())).as_slice()); + } + }; + + let arguments_tuple = ty::mk_tup(self.tcx(), sig.inputs.to_vec()); + let output_type = sig.output.unwrap(); + let substs = + Substs::new_trait( + vec![arguments_tuple, output_type], + vec![], + vec![], + self_ty); + let trait_ref = Rc::new(ty::TraitRef { + def_id: obligation.trait_ref.def_id, + substs: substs, + }); + + let () = + try!(self.confirm(obligation.cause, + obligation.trait_ref.clone(), + trait_ref)); + + Ok(self_ty) + } + fn confirm_unboxed_closure_candidate(&mut self, obligation: &Obligation<'tcx>, closure_def_id: ast::DefId, @@ -1964,6 +2054,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { util::obligations_for_generics(self.tcx(), cause, recursion_depth, &bounds, &impl_substs.types) } + + fn fn_family_trait_kind(&self, + trait_def_id: ast::DefId) + -> Option + { + let tcx = self.tcx(); + if Some(trait_def_id) == tcx.lang_items.fn_trait() { + Some(ty::FnUnboxedClosureKind) + } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() { + Some(ty::FnMutUnboxedClosureKind) + } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() { + Some(ty::FnOnceUnboxedClosureKind) + } else { + None + } + } } impl<'tcx> Repr<'tcx> for Candidate<'tcx> { @@ -1972,7 +2078,10 @@ impl<'tcx> Repr<'tcx> for Candidate<'tcx> { ErrorCandidate => format!("ErrorCandidate"), BuiltinCandidate(b) => format!("BuiltinCandidate({})", b), UnboxedClosureCandidate(c, ref s) => { - format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx)) + format!("UnboxedClosureCandidate({},{})", c, s.repr(tcx)) + } + FnPointerCandidate => { + format!("FnPointerCandidate") } ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)), ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)), diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index e8b292aac6d..1084807ef4a 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -302,6 +302,10 @@ impl<'tcx, N:Repr<'tcx>> Repr<'tcx> for super::Vtable<'tcx, N> { d.repr(tcx), s.repr(tcx)), + super::VtableFnPointer(ref d) => + format!("VtableFnPointer({})", + d.repr(tcx)), + super::VtableParam(ref v) => format!("VtableParam({})", v.repr(tcx)), diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 08dcbffc928..de9eb426498 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -466,6 +466,9 @@ impl<'tcx, N: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Vtable<'tcx, N> traits::VtableUnboxedClosure(d, ref s) => { traits::VtableUnboxedClosure(d, s.fold_with(folder)) } + traits::VtableFnPointer(ref d) => { + traits::VtableFnPointer(d.fold_with(folder)) + } traits::VtableParam(ref p) => traits::VtableParam(p.fold_with(folder)), traits::VtableBuiltin(ref d) => traits::VtableBuiltin(d.fold_with(folder)), } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 23072dee3b6..84a6b59934f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -995,9 +995,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } if need_invoke(bcx) { - debug!("invoking {} at {}", llfn, bcx.llbb); + debug!("invoking {} at {}", bcx.val_to_string(llfn), bcx.llbb); for &llarg in llargs.iter() { - debug!("arg: {}", llarg); + debug!("arg: {}", bcx.val_to_string(llarg)); } let normal_bcx = bcx.fcx.new_temp_block("normal-return"); let landing_pad = bcx.fcx.get_landing_pad(); @@ -1015,9 +1015,9 @@ pub fn invoke<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(attributes)); return (llresult, normal_bcx); } else { - debug!("calling {} at {}", llfn, bcx.llbb); + debug!("calling {} at {}", bcx.val_to_string(llfn), bcx.llbb); for &llarg in llargs.iter() { - debug!("arg: {}", llarg); + debug!("arg: {}", bcx.val_to_string(llarg)); } match call_info { diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index 50d2f885afa..4bcb7b09495 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -242,6 +242,112 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } +/// Translates an adapter that implements the `Fn` trait for a fn +/// pointer. This is basically the equivalent of something like: +/// +/// ```rust +/// impl<'a> Fn(&'a int) -> &'a int for fn(&int) -> &int { +/// extern "rust-abi" fn call(&self, args: (&'a int,)) -> &'a int { +/// (*self)(args.0) +/// } +/// } +/// ``` +/// +/// but for the bare function type given. +pub fn trans_fn_pointer_shim<'a, 'tcx>( + ccx: &'a CrateContext<'a, 'tcx>, + bare_fn_ty: Ty<'tcx>) + -> ValueRef +{ + let _icx = push_ctxt("trans_fn_pointer_shim"); + let tcx = ccx.tcx(); + + debug!("trans_fn_pointer_shim(bare_fn_ty={})", + bare_fn_ty.repr(tcx)); + + // This is an impl of `Fn` trait, so receiver is `&self`. + let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, ty::ReStatic, bare_fn_ty); + + // 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 (input_tys, output_ty) = + match bare_fn_ty.sty { + ty::ty_bare_fn(ty::BareFnTy { fn_style: ast::NormalFn, + abi: synabi::Rust, + sig: ty::FnSig { inputs: ref input_tys, + output: output_ty, + variadic: false }}) => + { + (input_tys, output_ty) + } + + _ => { + tcx.sess.bug(format!("trans_fn_pointer_shim invoked on invalid type: {}", + bare_fn_ty.repr(tcx)).as_slice()); + } + }; + let tuple_input_ty = ty::mk_tup(tcx, input_tys.to_vec()); + let tuple_fn_ty = ty::mk_bare_fn(tcx, + ty::BareFnTy { fn_style: ast::NormalFn, + abi: synabi::RustCall, + sig: ty::FnSig { + inputs: vec![bare_fn_ty_ref, + tuple_input_ty], + output: output_ty, + variadic: false + }}); + debug!("tuple_fn_ty: {}", tuple_fn_ty.repr(tcx)); + + // + let function_name = + link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty, + "fn_pointer_shim"); + let llfn = + decl_internal_rust_fn(ccx, + tuple_fn_ty, + function_name.as_slice()); + + // + let block_arena = TypedArena::new(); + let empty_substs = Substs::trans_empty(); + let fcx = new_fn_ctxt(ccx, + llfn, + ast::DUMMY_NODE_ID, + false, + output_ty, + &empty_substs, + None, + &block_arena); + let mut bcx = init_function(&fcx, false, output_ty); + + // the first argument (`self`) will be ptr to the the fn pointer + let llfnpointer = + Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32)); + + // the remaining arguments will be the untupled values + let llargs: Vec<_> = + input_tys.iter() + .enumerate() + .map(|(i, _)| get_param(fcx.llfn, fcx.arg_pos(i+1) as u32)) + .collect(); + assert!(!fcx.needs_ret_allocas); + + let dest = fcx.llretslotptr.get().map(|_| + expr::SaveIn(fcx.get_ret_slot(bcx, output_ty, "ret_slot")) + ); + + bcx = trans_call_inner(bcx, + None, + bare_fn_ty, + |bcx, _| Callee { bcx: bcx, data: Fn(llfnpointer) }, + ArgVals(llargs.as_slice()), + dest).bcx; + + finish_fn(&fcx, bcx, output_ty); + + 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>, diff --git a/src/librustc_trans/trans/meth.rs b/src/librustc_trans/trans/meth.rs index a49b7b21627..ef431243b31 100644 --- a/src/librustc_trans/trans/meth.rs +++ b/src/librustc_trans/trans/meth.rs @@ -368,9 +368,15 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, data: Fn(llfn), } } - _ => { - bcx.tcx().sess.bug( - "vtable_param left in monomorphized function's vtable substs"); + traits::VtableFnPointer(fn_ty) => { + let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty); + Callee { bcx: bcx, data: Fn(llfn) } + } + traits::VtableBuiltin(..) | + traits::VtableParam(..) => { + bcx.sess().bug( + format!("resolved vtable bad vtable {} in trans", + vtable.repr(bcx.tcx())).as_slice()); } } } @@ -609,6 +615,10 @@ pub fn get_vtable<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, (vec!(llfn)).into_iter() } + traits::VtableFnPointer(bare_fn_ty) => { + let llfn = vec![trans_fn_pointer_shim(bcx.ccx(), bare_fn_ty)]; + llfn.into_iter() + } traits::VtableParam(..) => { bcx.sess().bug( format!("resolved vtable for {} to bad vtable {} in trans", diff --git a/src/test/compile-fail/issue-15965.rs b/src/test/compile-fail/issue-15965.rs index 856cd1b0f3f..935e6770658 100644 --- a/src/test/compile-fail/issue-15965.rs +++ b/src/test/compile-fail/issue-15965.rs @@ -11,8 +11,6 @@ fn main() { return { return () } //~ ERROR the type of this value must be known in this context - () //~^ ERROR the type of this value must be known in this context -//~^^ ERROR notation; the first type parameter for the function trait is neither a tuple nor unit -//~^^^ ERROR overloaded calls are experimental + () ; } diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs index 943d326182f..9cf922ae990 100644 --- a/src/test/compile-fail/issue-18532.rs +++ b/src/test/compile-fail/issue-18532.rs @@ -17,6 +17,4 @@ fn main() { (return)((),()); //~^ ERROR the type of this value must be known - //~^^ ERROR the type of this value must be known - //~^^^ ERROR cannot use call notation } diff --git a/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs new file mode 100644 index 00000000000..a82689b1649 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-unsafe-extern-fn.rs @@ -0,0 +1,28 @@ +// 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. + +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +#![feature(unboxed_closures)] + +use std::ops::{Fn,FnMut,FnOnce}; + +unsafe fn square(x: &int) -> int { (*x) * (*x) } + +fn call_itint>(_: &F, _: int) -> int { 0 } +fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } +fn call_it_onceint>(_: F, _: int) -> int { 0 } + +fn main() { + let x = call_it(&square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); //~ ERROR not implemented +} + diff --git a/src/test/compile-fail/unboxed-closures-wrong-abi.rs b/src/test/compile-fail/unboxed-closures-wrong-abi.rs new file mode 100644 index 00000000000..920e91958ee --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-wrong-abi.rs @@ -0,0 +1,28 @@ +// 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. + +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +#![feature(unboxed_closures)] + +use std::ops::{Fn,FnMut,FnOnce}; + +extern "C" fn square(x: &int) -> int { (*x) * (*x) } + +fn call_itint>(_: &F, _: int) -> int { 0 } +fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } +fn call_it_onceint>(_: F, _: int) -> int { 0 } + +fn main() { + let x = call_it(&square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); //~ ERROR not implemented +} + diff --git a/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs new file mode 100644 index 00000000000..a7a7b1c6762 --- /dev/null +++ b/src/test/compile-fail/unboxed-closures-wrong-arg-type-extern-fn.rs @@ -0,0 +1,29 @@ +// 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. + +// Tests that unsafe extern fn pointers do not implement any Fn traits. + +#![feature(unboxed_closures)] + +use std::ops::{Fn,FnMut,FnOnce}; + +unsafe fn square(x: int) -> int { x * x } +// note: argument type here is `int`, not `&int` + +fn call_itint>(_: &F, _: int) -> int { 0 } +fn call_it_mutint>(_: &mut F, _: int) -> int { 0 } +fn call_it_onceint>(_: F, _: int) -> int { 0 } + +fn main() { + let x = call_it(&square, 22); //~ ERROR not implemented + let y = call_it_mut(&mut square, 22); //~ ERROR not implemented + let z = call_it_once(square, 22); //~ ERROR not implemented +} + diff --git a/src/test/run-pass/unboxed-closures-extern-fn-hr.rs b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs new file mode 100644 index 00000000000..df753f0f33e --- /dev/null +++ b/src/test/run-pass/unboxed-closures-extern-fn-hr.rs @@ -0,0 +1,45 @@ +// 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. + +// Checks that higher-ranked extern fn pointers implement the full range of Fn traits. + +#![feature(unboxed_closures)] + +use std::ops::{Fn,FnMut,FnOnce}; + +fn square(x: &int) -> int { (*x) * (*x) } + +fn call_itint>(f: &F, x: int) -> int { + (*f)(&x) +} + +fn call_it_boxed(f: &Fn(&int) -> int, x: int) -> int { + f.call((&x,)) +} + +fn call_it_mutint>(f: &mut F, x: int) -> int { + (*f)(&x) +} + +fn call_it_onceint>(f: F, x: int) -> int { + f(&x) +} + +fn main() { + let x = call_it(&square, 22); + let x1 = call_it_boxed(&square, 22); + let y = call_it_mut(&mut square, 22); + let z = call_it_once(square, 22); + assert_eq!(x, square(&22)); + assert_eq!(x1, square(&22)); + assert_eq!(y, square(&22)); + assert_eq!(z, square(&22)); +} + diff --git a/src/test/run-pass/unboxed-closures-extern-fn.rs b/src/test/run-pass/unboxed-closures-extern-fn.rs index 2628bd90eef..58657c2b718 100644 --- a/src/test/run-pass/unboxed-closures-extern-fn.rs +++ b/src/test/run-pass/unboxed-closures-extern-fn.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Checks that extern fn points implement the full range of Fn traits. +// Checks that extern fn pointers implement the full range of Fn traits. #![feature(unboxed_closures)] #![feature(unboxed_closures)]