about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorMatthias Krüger <476013+matthiaskrgr@users.noreply.github.com>2025-03-07 19:15:33 +0100
committerGitHub <noreply@github.com>2025-03-07 19:15:33 +0100
commitf5a143f796d9227e45a8c0f4d101d2b644fa0cc8 (patch)
tree2931e05792fe3f648428e1d40c93b4621f6f3a1f /tests
parent03eb45452305f2d52348279d0caa5fc1f12c438d (diff)
parentd2bde63b7ade858b7fa819aa042f6b2e196863ff (diff)
Rollup merge of #134797 - spastorino:ergonomic-ref-counting-1, r=nikomatsakis
Ergonomic ref counting

This is an experimental first version of ergonomic ref counting.

This first version implements most of the RFC but doesn't implement any of the optimizations. This was left for following iterations.

RFC: https://github.com/rust-lang/rfcs/pull/3680
Tracking issue: https://github.com/rust-lang/rust/issues/132290
Project goal: https://github.com/rust-lang/rust-project-goals/issues/107

r? ```@nikomatsakis```
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.stderr8
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr16
-rw-r--r--tests/ui/ergonomic-clones/async/basic.rs17
-rw-r--r--tests/ui/ergonomic-clones/async/edition-2015.rs7
-rw-r--r--tests/ui/ergonomic-clones/async/edition-2015.stderr8
-rw-r--r--tests/ui/ergonomic-clones/async/local-type.rs10
-rw-r--r--tests/ui/ergonomic-clones/async/local-type.stderr15
-rw-r--r--tests/ui/ergonomic-clones/closure/basic.rs58
-rw-r--r--tests/ui/ergonomic-clones/closure/const-closure.rs11
-rw-r--r--tests/ui/ergonomic-clones/closure/expect-region.rs25
-rw-r--r--tests/ui/ergonomic-clones/closure/expect-region.stderr22
-rw-r--r--tests/ui/ergonomic-clones/closure/fn-once.rs14
-rw-r--r--tests/ui/ergonomic-clones/closure/fn-once.stderr16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs16
-rw-r--r--tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr14
-rw-r--r--tests/ui/ergonomic-clones/closure/local-type.rs9
-rw-r--r--tests/ui/ergonomic-clones/closure/local-type.stderr15
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation.rs12
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation2.rs11
-rw-r--r--tests/ui/ergonomic-clones/closure/mutation2.stderr17
-rw-r--r--tests/ui/ergonomic-clones/closure/nested.rs21
-rw-r--r--tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs19
-rw-r--r--tests/ui/ergonomic-clones/closure/parse.rs22
-rw-r--r--tests/ui/ergonomic-clones/closure/parse.stderr28
-rw-r--r--tests/ui/ergonomic-clones/closure/print-verbose.rs28
-rw-r--r--tests/ui/ergonomic-clones/closure/print-verbose.stderr20
-rw-r--r--tests/ui/ergonomic-clones/closure/print.rs26
-rw-r--r--tests/ui/ergonomic-clones/closure/print.stderr20
-rw-r--r--tests/ui/ergonomic-clones/closure/with-binders.rs10
-rw-r--r--tests/ui/ergonomic-clones/dotuse/basic.rs22
-rw-r--r--tests/ui/ergonomic-clones/dotuse/parse.rs39
-rw-r--r--tests/ui/ergonomic-clones/dotuse/parse.stderr53
-rw-r--r--tests/ui/feature-gates/feature-gate-ergonomic-clones.rs32
-rw-r--r--tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr63
-rw-r--r--tests/ui/parser/block-no-opening-brace.rs2
-rw-r--r--tests/ui/parser/block-no-opening-brace.stderr4
-rw-r--r--tests/ui/parser/misspelled-keywords/async-move.stderr4
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.rs2
-rw-r--r--tests/ui/parser/recover/recover-quantified-closure.stderr4
40 files changed, 736 insertions, 20 deletions
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 905e1249d97..152a6f3a41e 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -44,22 +44,22 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index af5cc515bb2..53f1b827f9c 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -44,34 +44,34 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
    |
 LL |     if local_passes_tt!(async) == 1 {}
-   |                              ^ expected one of `move`, `|`, or `||`
+   |                              ^ expected one of `move`, `use`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
diff --git a/tests/ui/ergonomic-clones/async/basic.rs b/tests/ui/ergonomic-clones/async/basic.rs
new file mode 100644
index 00000000000..ad2bfd97cd1
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/basic.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+//@ edition:2018
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+fn ergonomic_clone_async_closures() -> impl Future<Output = String> {
+    let s = String::from("hi");
+
+    async use {
+        s
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/async/edition-2015.rs b/tests/ui/ergonomic-clones/async/edition-2015.rs
new file mode 100644
index 00000000000..d3b2071b9f9
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/edition-2015.rs
@@ -0,0 +1,7 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    async use {};
+    //~^ ERROR `async use` blocks are only allowed in Rust 2018 or later
+}
diff --git a/tests/ui/ergonomic-clones/async/edition-2015.stderr b/tests/ui/ergonomic-clones/async/edition-2015.stderr
new file mode 100644
index 00000000000..b218e6b242e
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/edition-2015.stderr
@@ -0,0 +1,8 @@
+error: `async use` blocks are only allowed in Rust 2018 or later
+  --> $DIR/edition-2015.rs:5:5
+   |
+LL |     async use {};
+   |     ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/ergonomic-clones/async/local-type.rs b/tests/ui/ergonomic-clones/async/local-type.rs
new file mode 100644
index 00000000000..e891686b550
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/local-type.rs
@@ -0,0 +1,10 @@
+// Check that using the parameter name in its type does not ICE.
+//@ edition:2018
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _ = async use |x: x| x; //~ ERROR expected type
+    let _ = async use |x: bool| -> x { x }; //~ ERROR expected type
+}
diff --git a/tests/ui/ergonomic-clones/async/local-type.stderr b/tests/ui/ergonomic-clones/async/local-type.stderr
new file mode 100644
index 00000000000..fd832fbc8d2
--- /dev/null
+++ b/tests/ui/ergonomic-clones/async/local-type.stderr
@@ -0,0 +1,15 @@
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:8:27
+   |
+LL |     let _ = async use |x: x| x;
+   |                           ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:9:36
+   |
+LL |     let _ = async use |x: bool| -> x { x };
+   |                                    ^ not a type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/tests/ui/ergonomic-clones/closure/basic.rs b/tests/ui/ergonomic-clones/closure/basic.rs
new file mode 100644
index 00000000000..01d3b08ffa2
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/basic.rs
@@ -0,0 +1,58 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+use std::future::Future;
+
+fn ergonomic_clone_closure_no_captures() -> i32 {
+    let cl = use || {
+        1
+    };
+    cl()
+}
+
+fn ergonomic_clone_closure_move() -> String {
+    let s = String::from("hi");
+
+    let cl = use || {
+        s
+    };
+    cl()
+}
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn ergonomic_clone_closure_use_cloned() -> Foo {
+    let f = Foo;
+
+    let f1 = use || {
+        f
+    };
+
+    let f2 = use || {
+        f
+    };
+
+    f
+}
+
+fn ergonomic_clone_closure_copy() -> i32 {
+    let i = 1;
+
+    let i1 = use || {
+        i
+    };
+
+    let i2 = use || {
+        i
+    };
+
+    i
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/const-closure.rs b/tests/ui/ergonomic-clones/closure/const-closure.rs
new file mode 100644
index 00000000000..6b4de824df9
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/const-closure.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+
+#![feature(const_closures)]
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+const fn foo() {
+    let cl = const use || {};
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/expect-region.rs b/tests/ui/ergonomic-clones/closure/expect-region.rs
new file mode 100644
index 00000000000..cbb13e56a18
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/expect-region.rs
@@ -0,0 +1,25 @@
+#![feature(ergonomic_clones)]
+#![allow(warnings)]
+
+fn closure_expecting_bound<F>(_: F)
+where
+    F: FnOnce(&u32),
+{
+}
+
+fn expect_bound_supply_named<'x>() {
+    let mut f: Option<&u32> = None;
+
+    // Here we give a type annotation that `x` should be free. We get
+    // an error because of that.
+    closure_expecting_bound(use |x: &'x u32| {
+        //~^ ERROR lifetime may not live long enough
+        //~| ERROR lifetime may not live long enough
+
+        // Borrowck doesn't get a chance to run, but if it did it should error
+        // here.
+        f = Some(x);
+    });
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/expect-region.stderr b/tests/ui/ergonomic-clones/closure/expect-region.stderr
new file mode 100644
index 00000000000..4df1df1378b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/expect-region.stderr
@@ -0,0 +1,22 @@
+error: lifetime may not live long enough
+  --> $DIR/expect-region.rs:15:34
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(use |x: &'x u32| {
+   |                                  ^  - let's call the lifetime of this reference `'1`
+   |                                  |
+   |                                  requires that `'1` must outlive `'x`
+
+error: lifetime may not live long enough
+  --> $DIR/expect-region.rs:15:34
+   |
+LL | fn expect_bound_supply_named<'x>() {
+   |                              -- lifetime `'x` defined here
+...
+LL |     closure_expecting_bound(use |x: &'x u32| {
+   |                                  ^ requires that `'x` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/ergonomic-clones/closure/fn-once.rs b/tests/ui/ergonomic-clones/closure/fn-once.rs
new file mode 100644
index 00000000000..24060f3ed3b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/fn-once.rs
@@ -0,0 +1,14 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn get_closure() -> Box<dyn Fn() -> Vec<u8>> {
+    let vec = vec![1u8, 2u8];
+
+    let closure = use || { //~ ERROR expected a closure
+        vec
+    };
+
+    Box::new(closure)
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/fn-once.stderr b/tests/ui/ergonomic-clones/closure/fn-once.stderr
new file mode 100644
index 00000000000..40f1200695c
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/fn-once.stderr
@@ -0,0 +1,16 @@
+error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce`
+  --> $DIR/fn-once.rs:7:19
+   |
+LL |     let closure = use || {
+   |                   ^^^^^^ this closure implements `FnOnce`, not `Fn`
+LL |         vec
+   |         --- closure is `FnOnce` because it moves the variable `vec` out of its environment
+...
+LL |     Box::new(closure)
+   |     ----------------- the requirement to implement `Fn` derives from here
+   |
+   = note: required for the cast from `Box<{closure@$DIR/fn-once.rs:7:19: 7:25}>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0525`.
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed
new file mode 100644
index 00000000000..1e570632452
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.fixed
@@ -0,0 +1,16 @@
+//@ run-rustfix
+
+// Point at the captured immutable outer variable
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn foo(mut f: Box<dyn FnMut()>) {
+    f();
+}
+
+fn main() {
+    let mut y = true;
+    foo(Box::new(use || y = !y) as Box<_>);
+    //~^ ERROR cannot assign to `y`, as it is not declared as mutable
+}
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs
new file mode 100644
index 00000000000..59aa61f581d
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.rs
@@ -0,0 +1,16 @@
+//@ run-rustfix
+
+// Point at the captured immutable outer variable
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn foo(mut f: Box<dyn FnMut()>) {
+    f();
+}
+
+fn main() {
+    let y = true;
+    foo(Box::new(use || y = !y) as Box<_>);
+    //~^ ERROR cannot assign to `y`, as it is not declared as mutable
+}
diff --git a/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr
new file mode 100644
index 00000000000..f7c742d33fd
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/immutable-outer-variable.stderr
@@ -0,0 +1,14 @@
+error[E0594]: cannot assign to `y`, as it is not declared as mutable
+  --> $DIR/immutable-outer-variable.rs:14:25
+   |
+LL |     foo(Box::new(use || y = !y) as Box<_>);
+   |                         ^^^^^^ cannot assign
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut y = true;
+   |         +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0594`.
diff --git a/tests/ui/ergonomic-clones/closure/local-type.rs b/tests/ui/ergonomic-clones/closure/local-type.rs
new file mode 100644
index 00000000000..b2f99efa1e6
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/local-type.rs
@@ -0,0 +1,9 @@
+// Check that using the parameter name in its type does not ICE.
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let _ = use |x: x| x; //~ ERROR expected type
+    let _ = use |x: bool| -> x { x }; //~ ERROR expected type
+}
diff --git a/tests/ui/ergonomic-clones/closure/local-type.stderr b/tests/ui/ergonomic-clones/closure/local-type.stderr
new file mode 100644
index 00000000000..5a42ae63afa
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/local-type.stderr
@@ -0,0 +1,15 @@
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:7:21
+   |
+LL |     let _ = use |x: x| x;
+   |                     ^ not a type
+
+error[E0573]: expected type, found local variable `x`
+  --> $DIR/local-type.rs:8:30
+   |
+LL |     let _ = use |x: bool| -> x { x };
+   |                              ^ not a type
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0573`.
diff --git a/tests/ui/ergonomic-clones/closure/mutation.rs b/tests/ui/ergonomic-clones/closure/mutation.rs
new file mode 100644
index 00000000000..ef05fffd479
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation.rs
@@ -0,0 +1,12 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let mut my_var = false;
+    let mut callback = use || {
+        my_var = true;
+    };
+    callback();
+}
diff --git a/tests/ui/ergonomic-clones/closure/mutation2.rs b/tests/ui/ergonomic-clones/closure/mutation2.rs
new file mode 100644
index 00000000000..1cb5b8a7ec3
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation2.rs
@@ -0,0 +1,11 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    let mut my_var = false;
+    let callback = use || {
+        my_var = true;
+    };
+    callback();
+    //~^ ERROR cannot borrow `callback` as mutable, as it is not declared as mutable [E0596]
+}
diff --git a/tests/ui/ergonomic-clones/closure/mutation2.stderr b/tests/ui/ergonomic-clones/closure/mutation2.stderr
new file mode 100644
index 00000000000..3ff33cf7017
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/mutation2.stderr
@@ -0,0 +1,17 @@
+error[E0596]: cannot borrow `callback` as mutable, as it is not declared as mutable
+  --> $DIR/mutation2.rs:9:5
+   |
+LL |         my_var = true;
+   |         ------ calling `callback` requires mutable binding due to possible mutation of `my_var`
+LL |     };
+LL |     callback();
+   |     ^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut callback = use || {
+   |         +++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/ergonomic-clones/closure/nested.rs b/tests/ui/ergonomic-clones/closure/nested.rs
new file mode 100644
index 00000000000..fc364fb594b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/nested.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn work(_: Box<Foo>) {}
+fn foo<F:FnOnce()>(_: F) {}
+
+pub fn main() {
+  let a = Box::new(Foo);
+  foo(use || { foo(use || { work(a) }) });
+  let x = use || { use || { Foo } };
+  let _y = x();
+}
diff --git a/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs
new file mode 100644
index 00000000000..a8267ac5359
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/once-move-out-on-heap.rs
@@ -0,0 +1,19 @@
+//@ run-pass
+// Testing guarantees provided by once functions.
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::sync::Arc;
+
+fn foo<F: FnOnce()>(blk: F) {
+    blk();
+}
+
+pub fn main() {
+    let x = Arc::new(true);
+    foo(use || {
+        assert!(*x);
+        drop(x);
+    });
+}
diff --git a/tests/ui/ergonomic-clones/closure/parse.rs b/tests/ui/ergonomic-clones/closure/parse.rs
new file mode 100644
index 00000000000..0b3bfae0608
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/parse.rs
@@ -0,0 +1,22 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn parse1() {
+    || use {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found `{`
+    };
+}
+
+fn parse2() {
+    move use || {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `use`
+    };
+}
+
+fn parse3() {
+    use move || {
+        //~^ ERROR expected one of `async`, `|`, or `||`, found keyword `move`
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/closure/parse.stderr b/tests/ui/ergonomic-clones/closure/parse.stderr
new file mode 100644
index 00000000000..c37cb71394b
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/parse.stderr
@@ -0,0 +1,28 @@
+error: expected one of `async`, `|`, or `||`, found `{`
+  --> $DIR/parse.rs:5:12
+   |
+LL |     || use {
+   |     --     ^ expected one of `async`, `|`, or `||`
+   |     |
+   |     while parsing the body of this closure
+   |
+help: you might have meant to open the body of the closure, instead of enclosing the closure in a block
+   |
+LL ~ fn parse1() 
+LL ~     || { use {
+   |
+
+error: expected one of `async`, `|`, or `||`, found keyword `use`
+  --> $DIR/parse.rs:11:10
+   |
+LL |     move use || {
+   |          ^^^ expected one of `async`, `|`, or `||`
+
+error: expected one of `async`, `|`, or `||`, found keyword `move`
+  --> $DIR/parse.rs:17:9
+   |
+LL |     use move || {
+   |         ^^^^ expected one of `async`, `|`, or `||`
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.rs b/tests/ui/ergonomic-clones/closure/print-verbose.rs
new file mode 100644
index 00000000000..e80d0d4b649
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print-verbose.rs
@@ -0,0 +1,28 @@
+//@ compile-flags: -Zverbose-internals
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn to_fn_once<F: FnOnce()>(f: F) -> F {
+    f
+}
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U,
+    };
+
+    let foo = Foo { x: "x" };
+
+    let c = to_fn_once(use || {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+fn main() {
+    f("S");
+}
diff --git a/tests/ui/ergonomic-clones/closure/print-verbose.stderr b/tests/ui/ergonomic-clones/closure/print-verbose.stderr
new file mode 100644
index 00000000000..283405c79d6
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print-verbose.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/print-verbose.rs:22:5
+   |
+LL |     let c = to_fn_once(use || {
+   |         - move occurs because `c` has type `{f<T>::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'?9 str>, T)}`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/print-verbose.rs:21:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/ergonomic-clones/closure/print.rs b/tests/ui/ergonomic-clones/closure/print.rs
new file mode 100644
index 00000000000..c24a4cc5094
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print.rs
@@ -0,0 +1,26 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn to_fn_once<F: FnOnce()>(f: F) -> F {
+    f
+}
+
+fn f<T: std::fmt::Display>(y: T) {
+    struct Foo<U: std::fmt::Display> {
+        x: U,
+    };
+
+    let foo = Foo { x: "x" };
+
+    let c = to_fn_once(use || {
+        println!("{} {}", foo.x, y);
+    });
+
+    c();
+    c();
+    //~^ ERROR use of moved value
+}
+
+fn main() {
+    f("S");
+}
diff --git a/tests/ui/ergonomic-clones/closure/print.stderr b/tests/ui/ergonomic-clones/closure/print.stderr
new file mode 100644
index 00000000000..5f48059ebff
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/print.stderr
@@ -0,0 +1,20 @@
+error[E0382]: use of moved value: `c`
+  --> $DIR/print.rs:20:5
+   |
+LL |     let c = to_fn_once(use || {
+   |         - move occurs because `c` has type `{closure@$DIR/print.rs:15:24: 15:30}`, which does not implement the `Copy` trait
+...
+LL |     c();
+   |     --- `c` moved due to this call
+LL |     c();
+   |     ^ value used here after move
+   |
+note: this value implements `FnOnce`, which causes it to be moved when called
+  --> $DIR/print.rs:19:5
+   |
+LL |     c();
+   |     ^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/ergonomic-clones/closure/with-binders.rs b/tests/ui/ergonomic-clones/closure/with-binders.rs
new file mode 100644
index 00000000000..4260c252d9d
--- /dev/null
+++ b/tests/ui/ergonomic-clones/closure/with-binders.rs
@@ -0,0 +1,10 @@
+//@ edition:2021
+//@ check-pass
+
+#![feature(closure_lifetime_binder)]
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn main() {
+    for<'a> use || -> () {};
+}
diff --git a/tests/ui/ergonomic-clones/dotuse/basic.rs b/tests/ui/ergonomic-clones/dotuse/basic.rs
new file mode 100644
index 00000000000..8f962f079df
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/basic.rs
@@ -0,0 +1,22 @@
+//@ check-pass
+
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+use std::clone::UseCloned;
+
+fn basic_test(x: i32) -> i32 {
+    x.use.use.abs()
+}
+
+#[derive(Clone)]
+struct Foo;
+
+impl UseCloned for Foo {}
+
+fn do_not_move_test(x: Foo) -> Foo {
+    let s = x.use;
+    x
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/dotuse/parse.rs b/tests/ui/ergonomic-clones/dotuse/parse.rs
new file mode 100644
index 00000000000..37ef5c37029
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/parse.rs
@@ -0,0 +1,39 @@
+#![feature(ergonomic_clones)]
+#![allow(incomplete_features)]
+
+fn parse1() {
+    1.use!;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+    }
+
+fn parse2() {
+    1.use!(2);
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+    }
+
+fn parse3() {
+    1.use 2;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+    }
+
+fn parse4() {
+    1.use? 2;
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+    }
+
+fn parse5() {
+    1.use();
+    //~^ ERROR: incorrect use of `use`
+}
+
+fn parse6() {
+    1.use(2);
+    //~^ ERROR: expected function, found `{integer}` [E0618]
+}
+
+fn parse7() {
+    1.use { 2 };
+    //~^ ERROR: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
+}
+
+fn main() {}
diff --git a/tests/ui/ergonomic-clones/dotuse/parse.stderr b/tests/ui/ergonomic-clones/dotuse/parse.stderr
new file mode 100644
index 00000000000..4b7a92534ed
--- /dev/null
+++ b/tests/ui/ergonomic-clones/dotuse/parse.stderr
@@ -0,0 +1,53 @@
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+  --> $DIR/parse.rs:5:10
+   |
+LL |     1.use!;
+   |          ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `!`
+  --> $DIR/parse.rs:10:10
+   |
+LL |     1.use!(2);
+   |          ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+  --> $DIR/parse.rs:15:11
+   |
+LL |     1.use 2;
+   |           ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `2`
+  --> $DIR/parse.rs:20:12
+   |
+LL |     1.use? 2;
+   |            ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error: incorrect use of `use`
+  --> $DIR/parse.rs:25:10
+   |
+LL |     1.use();
+   |          ^^
+   |
+help: `use` is not a method call, try removing the parentheses
+   |
+LL -     1.use();
+LL +     1.use;
+   |
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `{`
+  --> $DIR/parse.rs:35:11
+   |
+LL |     1.use { 2 };
+   |           ^ expected one of `.`, `;`, `?`, `}`, or an operator
+
+error[E0618]: expected function, found `{integer}`
+  --> $DIR/parse.rs:30:5
+   |
+LL |     1.use(2);
+   |     ^^^^^---
+   |     |
+   |     call expression requires function
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0618`.
diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs
new file mode 100644
index 00000000000..c2e44064cfa
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.rs
@@ -0,0 +1,32 @@
+use std::clone::UseCloned;
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+fn ergonomic_clone(x: i32) -> i32 {
+    x.use
+    //~^ ERROR ergonomic clones are experimental [E0658]
+}
+
+#[derive(Clone)]
+struct Foo;
+
+fn foo<T: UseCloned>() {}
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+impl UseCloned for Foo {}
+//~^ ERROR use of unstable library feature `ergonomic_clones` [E0658]
+
+fn ergonomic_closure_clone() {
+    let f1 = Foo;
+
+    let f2 = use || {
+        //~^ ERROR ergonomic clones are experimental [E0658]
+        f1
+    };
+
+    let f3 = use || {
+        //~^ ERROR ergonomic clones are experimental [E0658]
+        f1
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr
new file mode 100644
index 00000000000..cf92f2f28df
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-ergonomic-clones.stderr
@@ -0,0 +1,63 @@
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:5:7
+   |
+LL |     x.use
+   |       ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:21:14
+   |
+LL |     let f2 = use || {
+   |              ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: ergonomic clones are experimental
+  --> $DIR/feature-gate-ergonomic-clones.rs:26:14
+   |
+LL |     let f3 = use || {
+   |              ^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:1:5
+   |
+LL | use std::clone::UseCloned;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:12:11
+   |
+LL | fn foo<T: UseCloned>() {}
+   |           ^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: use of unstable library feature `ergonomic_clones`
+  --> $DIR/feature-gate-ergonomic-clones.rs:15:6
+   |
+LL | impl UseCloned for Foo {}
+   |      ^^^^^^^^^
+   |
+   = note: see issue #132290 <https://github.com/rust-lang/rust/issues/132290> for more information
+   = help: add `#![feature(ergonomic_clones)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs
index 2fde37ce6ac..b08c830bfc7 100644
--- a/tests/ui/parser/block-no-opening-brace.rs
+++ b/tests/ui/parser/block-no-opening-brace.rs
@@ -30,7 +30,7 @@ fn in_try() {
 // FIXME(#80931)
 fn in_async() {
     async
-        let x = 0; //~ ERROR expected one of `move`, `|`, or `||`, found keyword `let`
+        let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let`
 }
 
 // FIXME(#78168)
diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr
index b65de4eac3f..f51ee92626f 100644
--- a/tests/ui/parser/block-no-opening-brace.stderr
+++ b/tests/ui/parser/block-no-opening-brace.stderr
@@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
 LL |     try
    |     ^^^ expected expression
 
-error: expected one of `move`, `|`, or `||`, found keyword `let`
+error: expected one of `move`, `use`, `|`, or `||`, found keyword `let`
   --> $DIR/block-no-opening-brace.rs:33:9
    |
 LL |     async
-   |          - expected one of `move`, `|`, or `||`
+   |          - expected one of `move`, `use`, `|`, or `||`
 LL |         let x = 0;
    |         ^^^ unexpected token
 
diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr
index a002d54dc91..2507326fb28 100644
--- a/tests/ui/parser/misspelled-keywords/async-move.stderr
+++ b/tests/ui/parser/misspelled-keywords/async-move.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `|`, or `||`, found `Move`
+error: expected one of `move`, `use`, `|`, or `||`, found `Move`
   --> $DIR/async-move.rs:4:11
    |
 LL |     async Move {}
-   |           ^^^^ expected one of `move`, `|`, or `||`
+   |           ^^^^ expected one of `move`, `use`, `|`, or `||`
    |
 help: write keyword `move` in lowercase
    |
diff --git a/tests/ui/parser/recover/recover-quantified-closure.rs b/tests/ui/parser/recover/recover-quantified-closure.rs
index 10af39b7007..1f5004ad099 100644
--- a/tests/ui/parser/recover/recover-quantified-closure.rs
+++ b/tests/ui/parser/recover/recover-quantified-closure.rs
@@ -7,6 +7,6 @@ fn main() {
 enum Foo { Bar }
 fn foo(x: impl Iterator<Item = Foo>) {
     for <Foo>::Bar in x {}
-    //~^ ERROR expected one of `move`, `static`, `|`
+    //~^ ERROR expected one of `move`, `static`, `use`, `|`
     //~^^ ERROR `for<...>` binders for closures are experimental
 }
diff --git a/tests/ui/parser/recover/recover-quantified-closure.stderr b/tests/ui/parser/recover/recover-quantified-closure.stderr
index 6e03bbb5869..48dea071ae6 100644
--- a/tests/ui/parser/recover/recover-quantified-closure.stderr
+++ b/tests/ui/parser/recover/recover-quantified-closure.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `static`, `|`, or `||`, found `::`
+error: expected one of `move`, `static`, `use`, `|`, or `||`, found `::`
   --> $DIR/recover-quantified-closure.rs:9:14
    |
 LL |     for <Foo>::Bar in x {}
-   |              ^^ expected one of `move`, `static`, `|`, or `||`
+   |              ^^ expected one of `move`, `static`, `use`, `|`, or `||`
 
 error[E0658]: `for<...>` binders for closures are experimental
   --> $DIR/recover-quantified-closure.rs:2:5