}
}
-
-impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
- #[allow(non_snake_case)]
- extern "rust-call" fn call(&self, _args: ()) -> Result {
- (*self)()
+#[cfg(stage0)]
+mod fn_impls {
+ use super::Fn;
+
+ impl<Result> Fn<(),Result> for extern "Rust" fn() -> Result {
+ #[allow(non_snake_case)]
+ extern "rust-call" fn call(&self, _args: ()) -> Result {
+ (*self)()
+ }
}
-}
-impl<Result,A0> 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)
+ impl<Result,A0> 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<Result$(,$args)*>
- 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,)*)
+ macro_rules! def_fn(
+ ($($args:ident)*) => (
+ impl<Result$(,$args)*>
+ 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)
+ 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)
+}
/// 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<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>),
+
+ /// 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
pub fn iter_nested(&self) -> Items<N> {
match *self {
VtableImpl(ref i) => i.iter_nested(),
+ VtableFnPointer(..) => (&[]).iter(),
VtableUnboxedClosure(..) => (&[]).iter(),
VtableParam(_) => (&[]).iter(),
VtableBuiltin(ref i) => i.iter_nested(),
pub fn map_nested<M>(&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)),
pub fn map_move_nested<M>(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)),
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};
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;
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,
}
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));
}
}
/// 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());
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>,
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))
+ }
}
}
nested: impl_obligations }
}
+ fn confirm_fn_pointer_candidate(&mut self,
+ obligation: &Obligation<'tcx>)
+ -> Result<ty::Ty<'tcx>,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,
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<ty::UnboxedClosureKind>
+ {
+ 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> {
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)),
d.repr(tcx),
s.repr(tcx)),
+ super::VtableFnPointer(ref d) =>
+ format!("VtableFnPointer({})",
+ d.repr(tcx)),
+
super::VtableParam(ref v) =>
format!("VtableParam({})", v.repr(tcx)),
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)),
}
}
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();
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 {
}
}
+/// 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<Trait>` object into
/// `Trait` so that a by-value self method can be called.
pub fn trans_unboxing_shim<'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());
}
}
}
(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",
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
+ ()
;
}
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
}
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: 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
+}
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: 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
+}
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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_it<F:Fn(&int)->int>(_: &F, _: int) -> int { 0 }
+fn call_it_mut<F:FnMut(&int)->int>(_: &mut F, _: int) -> int { 0 }
+fn call_it_once<F:FnOnce(&int)->int>(_: 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
+}
+
--- /dev/null
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// 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_it<F:Fn(&int)->int>(f: &F, x: int) -> int {
+ (*f)(&x)
+}
+
+fn call_it_boxed(f: &Fn(&int) -> int, x: int) -> int {
+ f.call((&x,))
+}
+
+fn call_it_mut<F:FnMut(&int)->int>(f: &mut F, x: int) -> int {
+ (*f)(&x)
+}
+
+fn call_it_once<F:FnOnce(&int)->int>(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));
+}
+
// 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)]