about summary refs log tree commit diff
path: root/tests/ui/functions-closures
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/functions-closures')
-rw-r--r--tests/ui/functions-closures/auxiliary/fn-abi.rs2
-rw-r--r--tests/ui/functions-closures/call-closure-from-overloaded-op.rs9
-rw-r--r--tests/ui/functions-closures/capture-clauses-boxed-closures.rs14
-rw-r--r--tests/ui/functions-closures/capture-clauses-unboxed-closures.rs13
-rw-r--r--tests/ui/functions-closures/clone-closure.rs18
-rw-r--r--tests/ui/functions-closures/closure-bounds-can-capture-chan.rs16
-rw-r--r--tests/ui/functions-closures/closure-expected-type/README.md8
-rw-r--r--tests/ui/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs19
-rw-r--r--tests/ui/functions-closures/closure-expected-type/issue-38714.rs19
-rw-r--r--tests/ui/functions-closures/closure-expected-type/supply-just-return-type.rs26
-rw-r--r--tests/ui/functions-closures/closure-expected-type/supply-nothing.rs11
-rw-r--r--tests/ui/functions-closures/closure-immediate.rs13
-rw-r--r--tests/ui/functions-closures/closure-inference.rs11
-rw-r--r--tests/ui/functions-closures/closure-inference2.rs9
-rw-r--r--tests/ui/functions-closures/closure-reform.rs56
-rw-r--r--tests/ui/functions-closures/closure-returning-closure.rs5
-rw-r--r--tests/ui/functions-closures/closure-to-fn-coercion.rs35
-rw-r--r--tests/ui/functions-closures/closure_to_fn_coercion-expected-types.rs9
-rw-r--r--tests/ui/functions-closures/copy-closure.rs16
-rw-r--r--tests/ui/functions-closures/fn-abi.rs18
-rw-r--r--tests/ui/functions-closures/fn-bare-assign.rs17
-rw-r--r--tests/ui/functions-closures/fn-bare-coerce-to-block.rs10
-rw-r--r--tests/ui/functions-closures/fn-bare-item.rs8
-rw-r--r--tests/ui/functions-closures/fn-bare-size.rs8
-rw-r--r--tests/ui/functions-closures/fn-bare-spawn.rs15
-rw-r--r--tests/ui/functions-closures/fn-coerce-field.rs13
-rw-r--r--tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs14
-rw-r--r--tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr17
-rw-r--r--tests/ui/functions-closures/fn-help-with-err.rs24
-rw-r--r--tests/ui/functions-closures/fn-help-with-err.stderr27
-rw-r--r--tests/ui/functions-closures/fn-item-type-cast.rs22
-rw-r--r--tests/ui/functions-closures/fn-item-type-coerce.rs17
-rw-r--r--tests/ui/functions-closures/fn-item-type-zero-sized.rs13
-rw-r--r--tests/ui/functions-closures/fn-lval.rs11
-rw-r--r--tests/ui/functions-closures/fn-type-infer.rs11
-rw-r--r--tests/ui/functions-closures/implied-bounds-closure-arg-outlives.rs35
-rw-r--r--tests/ui/functions-closures/nullable-pointer-opt-closures.rs34
-rw-r--r--tests/ui/functions-closures/parallel-codegen-closures.rs28
-rw-r--r--tests/ui/functions-closures/return-from-closure.rs33
39 files changed, 684 insertions, 0 deletions
diff --git a/tests/ui/functions-closures/auxiliary/fn-abi.rs b/tests/ui/functions-closures/auxiliary/fn-abi.rs
new file mode 100644
index 00000000000..ace9fbdfd0c
--- /dev/null
+++ b/tests/ui/functions-closures/auxiliary/fn-abi.rs
@@ -0,0 +1,2 @@
+#[no_mangle]
+pub extern "C" fn foo() {}
diff --git a/tests/ui/functions-closures/call-closure-from-overloaded-op.rs b/tests/ui/functions-closures/call-closure-from-overloaded-op.rs
new file mode 100644
index 00000000000..8e1c68fd77d
--- /dev/null
+++ b/tests/ui/functions-closures/call-closure-from-overloaded-op.rs
@@ -0,0 +1,9 @@
+// run-pass
+
+fn foo() -> isize { 22 }
+
+pub fn main() {
+    let mut x: Vec<extern "Rust" fn() -> isize> = Vec::new();
+    x.push(foo);
+    assert_eq!((x[0])(), 22);
+}
diff --git a/tests/ui/functions-closures/capture-clauses-boxed-closures.rs b/tests/ui/functions-closures/capture-clauses-boxed-closures.rs
new file mode 100644
index 00000000000..bcde504635d
--- /dev/null
+++ b/tests/ui/functions-closures/capture-clauses-boxed-closures.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+fn each<T, F>(x: &[T], mut f: F) where F: FnMut(&T) {
+    for val in x {
+        f(val)
+    }
+}
+
+fn main() {
+    let mut sum = 0_usize;
+    let elems = [ 1_usize, 2, 3, 4, 5 ];
+    each(&elems, |val| sum += *val);
+    assert_eq!(sum, 15);
+}
diff --git a/tests/ui/functions-closures/capture-clauses-unboxed-closures.rs b/tests/ui/functions-closures/capture-clauses-unboxed-closures.rs
new file mode 100644
index 00000000000..206b3d7b613
--- /dev/null
+++ b/tests/ui/functions-closures/capture-clauses-unboxed-closures.rs
@@ -0,0 +1,13 @@
+// run-pass
+fn each<'a,T,F:FnMut(&'a T)>(x: &'a [T], mut f: F) {
+    for val in x {
+        f(val)
+    }
+}
+
+fn main() {
+    let mut sum = 0;
+    let elems = [ 1, 2, 3, 4, 5 ];
+    each(&elems, |val: &usize| sum += *val);
+    assert_eq!(sum, 15);
+}
diff --git a/tests/ui/functions-closures/clone-closure.rs b/tests/ui/functions-closures/clone-closure.rs
new file mode 100644
index 00000000000..1e725d8056d
--- /dev/null
+++ b/tests/ui/functions-closures/clone-closure.rs
@@ -0,0 +1,18 @@
+// run-pass
+// Check that closures implement `Clone`.
+
+#[derive(Clone)]
+struct S(i32);
+
+fn main() {
+    let mut a = S(5);
+    let mut hello = move || {
+        a.0 += 1;
+        println!("Hello {}", a.0);
+        a.0
+    };
+
+    let mut hello2 = hello.clone();
+    assert_eq!(6, hello2());
+    assert_eq!(6, hello());
+}
diff --git a/tests/ui/functions-closures/closure-bounds-can-capture-chan.rs b/tests/ui/functions-closures/closure-bounds-can-capture-chan.rs
new file mode 100644
index 00000000000..ccb2e201d7d
--- /dev/null
+++ b/tests/ui/functions-closures/closure-bounds-can-capture-chan.rs
@@ -0,0 +1,16 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+use std::sync::mpsc::channel;
+
+fn foo<F:FnOnce()+Send>(blk: F) {
+    blk();
+}
+
+pub fn main() {
+    let (tx, rx) = channel();
+    foo(move || {
+        tx.send(()).unwrap();
+    });
+    rx.recv().unwrap();
+}
diff --git a/tests/ui/functions-closures/closure-expected-type/README.md b/tests/ui/functions-closures/closure-expected-type/README.md
new file mode 100644
index 00000000000..0b749040a0e
--- /dev/null
+++ b/tests/ui/functions-closures/closure-expected-type/README.md
@@ -0,0 +1,8 @@
+Some tests targeted at how we deduce the types of closure arguments.
+This process is a result of some heuristics aimed at combining the
+*expected type* we have with the *actual types* that we get from
+inputs. This investigation was kicked off by #38714, which revealed
+some pretty deep flaws in the ad-hoc way that we were doing things
+before.
+
+See also `tests/ui/closure-expected-type`.
diff --git a/tests/ui/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs b/tests/ui/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs
new file mode 100644
index 00000000000..6d5a9876c37
--- /dev/null
+++ b/tests/ui/functions-closures/closure-expected-type/expect-infer-supply-two-infers.rs
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+fn with_closure<A, F>(_: F)
+    where F: FnOnce(Vec<A>, A)
+{
+}
+
+fn expect_free_supply_free<'x>(x: &'x u32) {
+    with_closure(|mut x: Vec<_>, y| {
+        // Shows that the call to `x.push()` is influencing type of `y`...
+        x.push(22_u32);
+
+        // ...since we now know the type of `y` and can resolve the method call.
+        let _ = y.wrapping_add(1);
+    });
+}
+
+fn main() { }
diff --git a/tests/ui/functions-closures/closure-expected-type/issue-38714.rs b/tests/ui/functions-closures/closure-expected-type/issue-38714.rs
new file mode 100644
index 00000000000..e97785b5cac
--- /dev/null
+++ b/tests/ui/functions-closures/closure-expected-type/issue-38714.rs
@@ -0,0 +1,19 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+struct UsizeRef<'a> {
+    a: &'a usize
+}
+
+type RefTo = Box<dyn for<'r> Fn(&'r Vec<usize>) -> UsizeRef<'r>>;
+
+fn ref_to<'a>(vec: &'a Vec<usize>) -> UsizeRef<'a> {
+    UsizeRef{ a: &vec[0]}
+}
+
+fn main() {
+    // Regression test: this was causing ICEs; it should compile.
+    let a: RefTo = Box::new(|vec: &Vec<usize>| {
+        UsizeRef{ a: &vec[0] }
+    });
+}
diff --git a/tests/ui/functions-closures/closure-expected-type/supply-just-return-type.rs b/tests/ui/functions-closures/closure-expected-type/supply-just-return-type.rs
new file mode 100644
index 00000000000..e9964531c3c
--- /dev/null
+++ b/tests/ui/functions-closures/closure-expected-type/supply-just-return-type.rs
@@ -0,0 +1,26 @@
+// run-pass
+fn with_closure<F, R>(f: F) -> Result<char, R>
+    where F: FnOnce(&char) -> Result<char, R>,
+{
+    f(&'a')
+}
+
+fn main() {
+    // Test that supplying the `-> Result<char, ()>` manually here
+    // (which is needed to constrain `R`) still allows us to figure
+    // out that the type of `x` is `&'a char` where `'a` is bound in
+    // the closure (if we didn't, we'd get a type-error because
+    // `with_closure` requires a bound region).
+    //
+    // This pattern was found in the wild.
+    let z = with_closure(|x| -> Result<char, ()> { Ok(*x) });
+    assert_eq!(z.unwrap(), 'a');
+
+    // It also works with `_`:
+    let z = with_closure(|x: _| -> Result<char, ()> { Ok(*x) });
+    assert_eq!(z.unwrap(), 'a');
+
+    // It also works with `&_`:
+    let z = with_closure(|x: &_| -> Result<char, ()> { Ok(*x) });
+    assert_eq!(z.unwrap(), 'a');
+}
diff --git a/tests/ui/functions-closures/closure-expected-type/supply-nothing.rs b/tests/ui/functions-closures/closure-expected-type/supply-nothing.rs
new file mode 100644
index 00000000000..8665cfc21a7
--- /dev/null
+++ b/tests/ui/functions-closures/closure-expected-type/supply-nothing.rs
@@ -0,0 +1,11 @@
+// run-pass
+fn with_closure<F>(f: F) -> u32
+    where F: FnOnce(&u32, &u32) -> u32
+{
+    f(&22, &44)
+}
+
+fn main() {
+    let z = with_closure(|x, y| x + y).wrapping_add(1);
+    assert_eq!(z, 22 + 44 + 1);
+}
diff --git a/tests/ui/functions-closures/closure-immediate.rs b/tests/ui/functions-closures/closure-immediate.rs
new file mode 100644
index 00000000000..428fc6bdef3
--- /dev/null
+++ b/tests/ui/functions-closures/closure-immediate.rs
@@ -0,0 +1,13 @@
+// run-pass
+
+// After the work to reoptimize structs, it became possible for immediate logic to fail.
+// This test verifies that it actually works.
+
+fn main() {
+    let c = |a: u8, b: u16, c: u8| {
+        assert_eq!(a, 1);
+        assert_eq!(b, 2);
+        assert_eq!(c, 3);
+    };
+    c(1, 2, 3);
+}
diff --git a/tests/ui/functions-closures/closure-inference.rs b/tests/ui/functions-closures/closure-inference.rs
new file mode 100644
index 00000000000..1877414f099
--- /dev/null
+++ b/tests/ui/functions-closures/closure-inference.rs
@@ -0,0 +1,11 @@
+// run-pass
+#![allow(unused_braces)]
+
+fn foo(i: isize) -> isize { i + 1 }
+
+fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
+
+pub fn main() {
+    let f = {|i| foo(i)};
+    assert_eq!(apply(f, 2), 3);
+}
diff --git a/tests/ui/functions-closures/closure-inference2.rs b/tests/ui/functions-closures/closure-inference2.rs
new file mode 100644
index 00000000000..4ce132e86ca
--- /dev/null
+++ b/tests/ui/functions-closures/closure-inference2.rs
@@ -0,0 +1,9 @@
+// run-pass
+// Test a rather underspecified example:
+#![allow(unused_braces)]
+
+pub fn main() {
+    let f = {|i| i};
+    assert_eq!(f(2), 2);
+    assert_eq!(f(5), 5);
+}
diff --git a/tests/ui/functions-closures/closure-reform.rs b/tests/ui/functions-closures/closure-reform.rs
new file mode 100644
index 00000000000..0bb6159ff4a
--- /dev/null
+++ b/tests/ui/functions-closures/closure-reform.rs
@@ -0,0 +1,56 @@
+// run-pass
+#![allow(unused_variables)]
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+fn call_it<F>(f: F)
+    where F : FnOnce(String) -> String
+{
+    println!("{}", f("Fred".to_string()))
+}
+
+fn call_a_thunk<F>(f: F) where F: FnOnce() {
+    f();
+}
+
+fn call_this<F>(f: F) where F: FnOnce(&str) + Send {
+    f("Hello!");
+}
+
+fn call_bare(f: fn(&str)) {
+    f("Hello world!")
+}
+
+fn call_bare_again(f: extern "Rust" fn(&str)) {
+    f("Goodbye world!")
+}
+
+pub fn main() {
+    // Procs
+
+    let greeting = "Hello ".to_string();
+    call_it(|s| {
+        format!("{}{}", greeting, s)
+    });
+
+    let greeting = "Goodbye ".to_string();
+    call_it(|s| format!("{}{}", greeting, s));
+
+    let greeting = "How's life, ".to_string();
+    call_it(|s: String| -> String {
+        format!("{}{}", greeting, s)
+    });
+
+    // Closures
+
+    call_a_thunk(|| println!("Hello world!"));
+
+    call_this(|s| println!("{}", s));
+
+    // External functions
+
+    fn foo(s: &str) {}
+    call_bare(foo);
+
+    call_bare_again(foo);
+}
diff --git a/tests/ui/functions-closures/closure-returning-closure.rs b/tests/ui/functions-closures/closure-returning-closure.rs
new file mode 100644
index 00000000000..17db81687ab
--- /dev/null
+++ b/tests/ui/functions-closures/closure-returning-closure.rs
@@ -0,0 +1,5 @@
+// run-pass
+fn main() {
+    let f = |_||x, y| x+y;
+    assert_eq!(f(())(1, 2), 3);
+}
diff --git a/tests/ui/functions-closures/closure-to-fn-coercion.rs b/tests/ui/functions-closures/closure-to-fn-coercion.rs
new file mode 100644
index 00000000000..87ba488b5ae
--- /dev/null
+++ b/tests/ui/functions-closures/closure-to-fn-coercion.rs
@@ -0,0 +1,35 @@
+// run-pass
+use std::mem;
+
+const FOO: fn(u8) -> u8 = |v: u8| { v };
+
+const BAR: [fn(&mut u32); 5] = [
+    |_: &mut u32| {},
+    |v: &mut u32| *v += 1,
+    |v: &mut u32| *v += 2,
+    |v: &mut u32| *v += 3,
+    |v: &mut u32| *v += 4,
+];
+fn func_specific() -> fn() -> u32 {
+    || return 42
+}
+
+fn generic<T>(_: T) -> fn() -> usize {
+    || mem::size_of::<T>()
+}
+
+fn main() {
+    // Items
+    assert_eq!(func_specific()(), 42);
+    let foo: fn(u8) -> u8 = |v: u8| { v };
+    assert_eq!(foo(31), 31);
+    // Constants
+    assert_eq!(FOO(31), 31);
+    let mut a: u32 = 0;
+    assert_eq!({ BAR[0](&mut a); a }, 0);
+    assert_eq!({ BAR[1](&mut a); a }, 1);
+    assert_eq!({ BAR[2](&mut a); a }, 3);
+    assert_eq!({ BAR[3](&mut a); a }, 6);
+    assert_eq!({ BAR[4](&mut a); a }, 10);
+    assert_eq!(generic(0i8)(), 1);
+}
diff --git a/tests/ui/functions-closures/closure_to_fn_coercion-expected-types.rs b/tests/ui/functions-closures/closure_to_fn_coercion-expected-types.rs
new file mode 100644
index 00000000000..e7a9383950f
--- /dev/null
+++ b/tests/ui/functions-closures/closure_to_fn_coercion-expected-types.rs
@@ -0,0 +1,9 @@
+// run-pass
+#![allow(unused_variables)]
+// Ensure that we deduce expected argument types when a `fn()` type is expected (#41755)
+
+fn foo(f: fn(Vec<u32>) -> usize) { }
+
+fn main() {
+    foo(|x| x.len())
+}
diff --git a/tests/ui/functions-closures/copy-closure.rs b/tests/ui/functions-closures/copy-closure.rs
new file mode 100644
index 00000000000..72da02421b7
--- /dev/null
+++ b/tests/ui/functions-closures/copy-closure.rs
@@ -0,0 +1,16 @@
+// run-pass
+// Check that closures implement `Copy`.
+
+fn call<T, F: FnOnce() -> T>(f: F) -> T { f() }
+
+fn main() {
+    let a = 5;
+    let hello = || {
+        println!("Hello {}", a);
+        a
+    };
+
+    assert_eq!(5, call(hello.clone()));
+    assert_eq!(5, call(hello));
+    assert_eq!(5, call(hello));
+}
diff --git a/tests/ui/functions-closures/fn-abi.rs b/tests/ui/functions-closures/fn-abi.rs
new file mode 100644
index 00000000000..ac3a4be3346
--- /dev/null
+++ b/tests/ui/functions-closures/fn-abi.rs
@@ -0,0 +1,18 @@
+// run-pass
+// Ensure that declarations and types which use `extern fn` both have the same
+// ABI (#9309).
+
+// pretty-expanded FIXME #23616
+// aux-build:fn-abi.rs
+
+extern crate fn_abi;
+
+extern "C" {
+    fn foo();
+}
+
+pub fn main() {
+    // Will only type check if the type of _p and the decl of foo use the
+    // same ABI
+    let _p: unsafe extern "C" fn() = foo;
+}
diff --git a/tests/ui/functions-closures/fn-bare-assign.rs b/tests/ui/functions-closures/fn-bare-assign.rs
new file mode 100644
index 00000000000..f5dab3c8402
--- /dev/null
+++ b/tests/ui/functions-closures/fn-bare-assign.rs
@@ -0,0 +1,17 @@
+// run-pass
+
+fn f(i: isize, called: &mut bool) {
+    assert_eq!(i, 10);
+    *called = true;
+}
+
+fn g(f: fn(isize, v: &mut bool), called: &mut bool) {
+    f(10, called);
+}
+
+pub fn main() {
+    let mut called = false;
+    let h = f;
+    g(h, &mut called);
+    assert_eq!(called, true);
+}
diff --git a/tests/ui/functions-closures/fn-bare-coerce-to-block.rs b/tests/ui/functions-closures/fn-bare-coerce-to-block.rs
new file mode 100644
index 00000000000..922e016ddc8
--- /dev/null
+++ b/tests/ui/functions-closures/fn-bare-coerce-to-block.rs
@@ -0,0 +1,10 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+fn bare() {}
+
+fn likes_block<F>(f: F) where F: FnOnce() { f() }
+
+pub fn main() {
+    likes_block(bare);
+}
diff --git a/tests/ui/functions-closures/fn-bare-item.rs b/tests/ui/functions-closures/fn-bare-item.rs
new file mode 100644
index 00000000000..a6e6495a40a
--- /dev/null
+++ b/tests/ui/functions-closures/fn-bare-item.rs
@@ -0,0 +1,8 @@
+// run-pass
+fn f() {
+    println!("This is a bare function");
+}
+
+pub fn main() {
+    f();
+}
diff --git a/tests/ui/functions-closures/fn-bare-size.rs b/tests/ui/functions-closures/fn-bare-size.rs
new file mode 100644
index 00000000000..2ba56eaaed4
--- /dev/null
+++ b/tests/ui/functions-closures/fn-bare-size.rs
@@ -0,0 +1,8 @@
+// run-pass
+
+use std::mem;
+
+pub fn main() {
+    // Bare functions should just be a pointer
+    assert_eq!(mem::size_of::<extern "Rust" fn()>(), mem::size_of::<isize>());
+}
diff --git a/tests/ui/functions-closures/fn-bare-spawn.rs b/tests/ui/functions-closures/fn-bare-spawn.rs
new file mode 100644
index 00000000000..0d46fe22087
--- /dev/null
+++ b/tests/ui/functions-closures/fn-bare-spawn.rs
@@ -0,0 +1,15 @@
+// run-pass
+// This is what the signature to spawn should look like with bare functions
+
+
+fn spawn<T:Send>(val: T, f: fn(T)) {
+    f(val);
+}
+
+fn f(i: isize) {
+    assert_eq!(i, 100);
+}
+
+pub fn main() {
+    spawn(100, f);
+}
diff --git a/tests/ui/functions-closures/fn-coerce-field.rs b/tests/ui/functions-closures/fn-coerce-field.rs
new file mode 100644
index 00000000000..38bde7b9e8f
--- /dev/null
+++ b/tests/ui/functions-closures/fn-coerce-field.rs
@@ -0,0 +1,13 @@
+// run-pass
+#![allow(dead_code)]
+// pretty-expanded FIXME #23616
+#![allow(non_camel_case_types)]
+
+struct r<F> where F: FnOnce() {
+    field: F,
+}
+
+pub fn main() {
+    fn f() {}
+    let _i: r<fn()> = r {field: f as fn()};
+}
diff --git a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs
new file mode 100644
index 00000000000..e48ab4aa96f
--- /dev/null
+++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.rs
@@ -0,0 +1,14 @@
+struct Struct<T>(T);
+impl Struct<T>
+//~^ ERROR cannot find type `T` in this scope
+//~| NOTE not found in this scope
+//~| HELP you might be missing a type parameter
+where
+    T: Copy,
+    //~^ ERROR cannot find type `T` in this scope
+    //~| NOTE not found in this scope
+{
+    fn method(v: Vec<u8>) { v.len(); }
+}
+
+fn main() {}
diff --git a/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
new file mode 100644
index 00000000000..26bdf460f5e
--- /dev/null
+++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
@@ -0,0 +1,17 @@
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:2:13
+   |
+LL | impl Struct<T>
+   |     -       ^ not found in this scope
+   |     |
+   |     help: you might be missing a type parameter: `<T>`
+
+error[E0412]: cannot find type `T` in this scope
+  --> $DIR/fn-help-with-err-generic-is-not-function.rs:7:5
+   |
+LL |     T: Copy,
+   |     ^ not found in this scope
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/functions-closures/fn-help-with-err.rs b/tests/ui/functions-closures/fn-help-with-err.rs
new file mode 100644
index 00000000000..612fe1b8419
--- /dev/null
+++ b/tests/ui/functions-closures/fn-help-with-err.rs
@@ -0,0 +1,24 @@
+// This test case checks the behavior of typeck::check::method::suggest::is_fn on Ty::Error.
+
+struct Foo;
+
+trait Bar {
+    //~^ NOTE `Bar` defines an item `bar`, perhaps you need to implement it
+    fn bar(&self) {}
+}
+
+impl Bar for Foo {}
+
+fn main() {
+    let arc = std::sync::Arc::new(oops);
+    //~^ ERROR cannot find value `oops` in this scope
+    //~| NOTE not found
+    arc.bar();
+
+    let arc2 = std::sync::Arc::new(|| Foo);
+    arc2.bar();
+    //~^ ERROR no method named `bar`
+    //~| NOTE method not found
+    //~| HELP items from traits can only be used if the trait is implemented and in scope
+    //~| HELP use parentheses to call this closure
+}
diff --git a/tests/ui/functions-closures/fn-help-with-err.stderr b/tests/ui/functions-closures/fn-help-with-err.stderr
new file mode 100644
index 00000000000..83a2b1f58f9
--- /dev/null
+++ b/tests/ui/functions-closures/fn-help-with-err.stderr
@@ -0,0 +1,27 @@
+error[E0425]: cannot find value `oops` in this scope
+  --> $DIR/fn-help-with-err.rs:13:35
+   |
+LL |     let arc = std::sync::Arc::new(oops);
+   |                                   ^^^^ not found in this scope
+
+error[E0599]: no method named `bar` found for struct `Arc<[closure@fn-help-with-err.rs:18:36]>` in the current scope
+  --> $DIR/fn-help-with-err.rs:19:10
+   |
+LL |     arc2.bar();
+   |          ^^^ method not found in `Arc<[closure@fn-help-with-err.rs:18:36]>`
+   |
+   = help: items from traits can only be used if the trait is implemented and in scope
+note: `Bar` defines an item `bar`, perhaps you need to implement it
+  --> $DIR/fn-help-with-err.rs:5:1
+   |
+LL | trait Bar {
+   | ^^^^^^^^^
+help: use parentheses to call this closure
+   |
+LL |     arc2().bar();
+   |         ++
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0425, E0599.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/functions-closures/fn-item-type-cast.rs b/tests/ui/functions-closures/fn-item-type-cast.rs
new file mode 100644
index 00000000000..4d50ea97b8b
--- /dev/null
+++ b/tests/ui/functions-closures/fn-item-type-cast.rs
@@ -0,0 +1,22 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+// Test explicit coercions from a fn item type to a fn pointer type.
+
+
+fn foo(x: isize) -> isize { x * 2 }
+fn bar(x: isize) -> isize { x * 4 }
+type IntMap = fn(isize) -> isize;
+
+fn eq<T>(x: T, y: T) { }
+
+static TEST: Option<IntMap> = Some(foo as IntMap);
+
+fn main() {
+    let f = foo as IntMap;
+
+    let f = if true { foo as IntMap } else { bar as IntMap };
+    assert_eq!(f(4), 8);
+
+    eq(foo as IntMap, bar as IntMap);
+}
diff --git a/tests/ui/functions-closures/fn-item-type-coerce.rs b/tests/ui/functions-closures/fn-item-type-coerce.rs
new file mode 100644
index 00000000000..7a096764e45
--- /dev/null
+++ b/tests/ui/functions-closures/fn-item-type-coerce.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![allow(unused_variables)]
+// Test implicit coercions from a fn item type to a fn pointer type.
+
+// pretty-expanded FIXME #23616
+
+fn foo(x: isize) -> isize { x * 2 }
+fn bar(x: isize) -> isize { x * 4 }
+type IntMap = fn(isize) -> isize;
+
+fn eq<T>(x: T, y: T) { }
+
+fn main() {
+    let f: IntMap = foo;
+
+    eq::<IntMap>(foo, bar);
+}
diff --git a/tests/ui/functions-closures/fn-item-type-zero-sized.rs b/tests/ui/functions-closures/fn-item-type-zero-sized.rs
new file mode 100644
index 00000000000..bd9f1ed663d
--- /dev/null
+++ b/tests/ui/functions-closures/fn-item-type-zero-sized.rs
@@ -0,0 +1,13 @@
+// run-pass
+// Test that fn item types are zero-sized.
+
+use std::mem::{size_of, size_of_val};
+
+fn main() {
+    assert_eq!(size_of_val(&main), 0);
+
+    let (a, b) = (size_of::<u8>, size_of::<u16>);
+    assert_eq!(size_of_val(&a), 0);
+    assert_eq!(size_of_val(&b), 0);
+    assert_eq!((a(), b()), (1, 2));
+}
diff --git a/tests/ui/functions-closures/fn-lval.rs b/tests/ui/functions-closures/fn-lval.rs
new file mode 100644
index 00000000000..01079eea457
--- /dev/null
+++ b/tests/ui/functions-closures/fn-lval.rs
@@ -0,0 +1,11 @@
+// run-pass
+
+
+
+// pretty-expanded FIXME #23616
+
+fn foo(_f: fn(isize) -> isize) { }
+
+fn id(x: isize) -> isize { return x; }
+
+pub fn main() { foo(id); }
diff --git a/tests/ui/functions-closures/fn-type-infer.rs b/tests/ui/functions-closures/fn-type-infer.rs
new file mode 100644
index 00000000000..fe6567f22b5
--- /dev/null
+++ b/tests/ui/functions-closures/fn-type-infer.rs
@@ -0,0 +1,11 @@
+// run-pass
+// pretty-expanded FIXME #23616
+
+#![allow(unused_variables)]
+
+pub fn main() {
+    // We should be able to type infer inside of ||s.
+    let _f = || {
+        let i = 10;
+    };
+}
diff --git a/tests/ui/functions-closures/implied-bounds-closure-arg-outlives.rs b/tests/ui/functions-closures/implied-bounds-closure-arg-outlives.rs
new file mode 100644
index 00000000000..4ac07123d9d
--- /dev/null
+++ b/tests/ui/functions-closures/implied-bounds-closure-arg-outlives.rs
@@ -0,0 +1,35 @@
+// run-pass
+// Test that we are able to handle the relationships between free
+// regions bound in a closure callback.
+
+#[derive(Copy, Clone)]
+struct MyCx<'short, 'long: 'short> {
+    short: &'short u32,
+    long: &'long u32,
+}
+
+impl<'short, 'long> MyCx<'short, 'long> {
+    fn short(self) -> &'short u32 { self.short }
+    fn long(self) -> &'long u32 { self.long }
+    fn set_short(&mut self, v: &'short u32) { self.short = v; }
+}
+
+fn with<F, R>(op: F) -> R
+where
+    F: for<'short, 'long> FnOnce(MyCx<'short, 'long>) -> R,
+{
+    op(MyCx {
+        short: &22,
+        long: &22,
+    })
+}
+
+fn main() {
+    with(|mut cx| {
+        // For this to type-check, we need to be able to deduce that
+        // the lifetime of `l` can be `'short`, even though it has
+        // input from `'long`.
+        let l = if true { cx.long() } else { cx.short() };
+        cx.set_short(l);
+    });
+}
diff --git a/tests/ui/functions-closures/nullable-pointer-opt-closures.rs b/tests/ui/functions-closures/nullable-pointer-opt-closures.rs
new file mode 100644
index 00000000000..87dacfba25b
--- /dev/null
+++ b/tests/ui/functions-closures/nullable-pointer-opt-closures.rs
@@ -0,0 +1,34 @@
+// run-pass
+
+use std::mem;
+
+pub fn main() {
+    // By Ref Capture
+    let a = 10i32;
+    let b = Some(|| println!("{}", a));
+    // When we capture by reference we can use any of the
+    // captures as the discriminant since they're all
+    // behind a pointer.
+    assert_eq!(mem::size_of_val(&b), mem::size_of::<usize>());
+
+    // By Value Capture
+    let a = Box::new(12i32);
+    let b = Some(move || println!("{}", a));
+    // We captured `a` by value and since it's a `Box` we can use it
+    // as the discriminant.
+    assert_eq!(mem::size_of_val(&b), mem::size_of::<Box<i32>>());
+
+    // By Value Capture - Transitive case
+    let a = "Hello".to_string(); // String -> Vec -> Unique -> NonZero
+    let b = Some(move || println!("{}", a));
+    // We captured `a` by value and since down the chain it contains
+    // a `NonZero` field, we can use it as the discriminant.
+    assert_eq!(mem::size_of_val(&b), mem::size_of::<String>());
+
+    // By Value - No Optimization
+    let a = 14i32;
+    let b = Some(move || println!("{}", a));
+    // We captured `a` by value but we can't use it as the discriminant
+    // thus we end up with an extra field for the discriminant
+    assert_eq!(mem::size_of_val(&b), mem::size_of::<(i32, i32)>());
+}
diff --git a/tests/ui/functions-closures/parallel-codegen-closures.rs b/tests/ui/functions-closures/parallel-codegen-closures.rs
new file mode 100644
index 00000000000..79759daba50
--- /dev/null
+++ b/tests/ui/functions-closures/parallel-codegen-closures.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(stable_features)]
+
+// Tests parallel codegen - this can fail if the symbol for the anonymous
+// closure in `sum` pollutes the second codegen unit from the first.
+
+// compile-flags: -C codegen_units=2
+
+#![feature(iter_arith)]
+
+mod a {
+    fn foo() {
+        let x = ["a", "bob", "c"];
+        let len: usize = x.iter().map(|s| s.len()).sum();
+    }
+}
+
+mod b {
+    fn bar() {
+        let x = ["a", "bob", "c"];
+        let len: usize = x.iter().map(|s| s.len()).sum();
+    }
+}
+
+fn main() {
+}
diff --git a/tests/ui/functions-closures/return-from-closure.rs b/tests/ui/functions-closures/return-from-closure.rs
new file mode 100644
index 00000000000..656a95f120a
--- /dev/null
+++ b/tests/ui/functions-closures/return-from-closure.rs
@@ -0,0 +1,33 @@
+// run-pass
+#![allow(non_upper_case_globals)]
+// just to make sure that `return` is only returning from the closure,
+// not the surrounding function.
+
+static mut calls: usize = 0;
+
+fn surrounding() {
+    let return_works = |n: isize| {
+        unsafe { calls += 1 }
+
+        if n >= 0 { return; }
+        panic!()
+    };
+
+    return_works(10);
+    return_works(20);
+
+    let return_works_proc = |n: isize| {
+        unsafe { calls += 1 }
+
+        if n >= 0 { return; }
+        panic!()
+    };
+
+    return_works_proc(10);
+}
+
+pub fn main() {
+    surrounding();
+
+    assert_eq!(unsafe {calls}, 3);
+}