summaryrefslogtreecommitdiffstats
path: root/tests/ui/functions-closures
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:19:13 +0000
commit218caa410aa38c29984be31a5229b9fa717560ee (patch)
treec54bd55eeb6e4c508940a30e94c0032fbd45d677 /tests/ui/functions-closures
parentReleasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz
rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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.stderr20
-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, 687 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 000000000..ace9fbdfd
--- /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 000000000..8e1c68fd7
--- /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 000000000..bcde50463
--- /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 000000000..206b3d7b6
--- /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 000000000..1e725d805
--- /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 000000000..ccb2e201d
--- /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 000000000..0b749040a
--- /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 000000000..6d5a9876c
--- /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 000000000..e97785b5c
--- /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 000000000..e9964531c
--- /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 000000000..8665cfc21
--- /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 000000000..428fc6bde
--- /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 000000000..1877414f0
--- /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 000000000..4ce132e86
--- /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 000000000..0bb6159ff
--- /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 000000000..17db81687
--- /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 000000000..87ba488b5
--- /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 000000000..e7a938395
--- /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 000000000..72da02421
--- /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 000000000..ac3a4be33
--- /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 000000000..f5dab3c84
--- /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 000000000..922e016dd
--- /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 000000000..a6e6495a4
--- /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 000000000..2ba56eaae
--- /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 000000000..0d46fe220
--- /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 000000000..38bde7b9e
--- /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 000000000..e48ab4aa9
--- /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 000000000..9d4ea0115
--- /dev/null
+++ b/tests/ui/functions-closures/fn-help-with-err-generic-is-not-function.stderr
@@ -0,0 +1,20 @@
+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
+ |
+LL | impl<T> Struct<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 000000000..612fe1b84
--- /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 000000000..83a2b1f58
--- /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 000000000..4d50ea97b
--- /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 000000000..7a096764e
--- /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 000000000..bd9f1ed66
--- /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 000000000..01079eea4
--- /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 000000000..fe6567f22
--- /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 000000000..4ac07123d
--- /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 000000000..87dacfba2
--- /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 000000000..79759daba
--- /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 000000000..656a95f12
--- /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);
+}