diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 0ebb6e94b9a0e..839243970ac67 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -769,3 +769,37 @@ pub trait FnOnce { fn call_once(self, args: Args) -> Result; } +macro_rules! def_fn_mut( + ($($args:ident)*) => ( + #[cfg(not(stage0))] + impl + FnMut<($($args,)*),Result> + for extern "Rust" fn($($args: $args,)*) -> Result { + #[rust_call_abi_hack] + #[allow(uppercase_variables)] + fn call_mut(&mut self, args: ($($args,)*)) -> Result { + let ($($args,)*) = args; + (*self)($($args,)*) + } + } + ) +) + +def_fn_mut!() +def_fn_mut!(A0) +def_fn_mut!(A0 A1) +def_fn_mut!(A0 A1 A2) +def_fn_mut!(A0 A1 A2 A3) +def_fn_mut!(A0 A1 A2 A3 A4) +def_fn_mut!(A0 A1 A2 A3 A4 A5) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14) +def_fn_mut!(A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15) + diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 557fd522fa918..39e79040e8367 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1541,6 +1541,13 @@ fn try_overloaded_call(fcx: &FnCtxt, callee_type: ty::t, args: &[Gc]) -> bool { + // Bail out if the callee is a bare function or a closure. We check those + // manually. + match *structure_of(fcx, callee.span, callee_type) { + ty::ty_bare_fn(_) | ty::ty_closure(_) => return false, + _ => {} + } + // Try `FnOnce`, then `FnMut`, then `Fn`. for &(maybe_function_trait, method_name) in [ (fcx.tcx().lang_items.fn_once_trait(), token::intern("call_once")), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 73de47e7b12e7..b9309f59557b4 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4042,7 +4042,8 @@ impl<'a> Parser<'a> { /// Parse a method in a trait impl, starting with `attrs` attributes. pub fn parse_method(&mut self, - already_parsed_attrs: Option>) -> Gc { + already_parsed_attrs: Option>) + -> Gc { let next_attrs = self.parse_outer_attributes(); let attrs = match already_parsed_attrs { Some(mut a) => { a.push_all_move(next_attrs); a } @@ -4080,6 +4081,11 @@ impl<'a> Parser<'a> { let visa = self.parse_visibility(); let abi = if self.eat_keyword(keywords::Extern) { self.parse_opt_abi().unwrap_or(abi::C) + } else if attr::contains_name(attrs.as_slice(), + "rust_call_abi_hack") { + // FIXME(stage0, pcwalton): Remove this awful hack after a + // snapshot, and change to `extern "rust-call" fn`. + abi::RustCall } else { abi::Rust }; diff --git a/src/test/run-pass/bare-fn-implements-fn-mut.rs b/src/test/run-pass/bare-fn-implements-fn-mut.rs new file mode 100644 index 0000000000000..37c551734defb --- /dev/null +++ b/src/test/run-pass/bare-fn-implements-fn-mut.rs @@ -0,0 +1,37 @@ +// 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(overloaded_calls)] + +use std::ops::FnMut; + +fn call_f>(mut f: F) { + f(); +} + +fn f() { + println!("hello"); +} + +fn call_g>(mut g: G, x: String, y: String) + -> String { + g(x, y) +} + +fn g(x: String, y: String) -> String { + x.append(y.as_slice()) +} + +fn main() { + call_f(f); + assert_eq!(call_g(g, "foo".to_string(), "bar".to_string()).as_slice(), + "foobar"); +} +